1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Floating interrupt tests. 4 * 5 * Copyright 2021 Red Hat Inc 6 * 7 * Authors: 8 * David Hildenbrand <david@redhat.com> 9 */ 10 #include <libcflat.h> 11 #include <asm/asm-offsets.h> 12 #include <asm/interrupt.h> 13 #include <asm/page.h> 14 #include <asm-generic/barrier.h> 15 16 #include <sclp.h> 17 #include <smp.h> 18 #include <alloc_page.h> 19 20 static void wait_for_sclp_int(void) 21 { 22 /* Enable SCLP interrupts on this CPU only. */ 23 ctl_set_bit(0, CTL0_SERVICE_SIGNAL); 24 25 /* Enable external interrupts and go to the wait state. */ 26 wait_for_interrupt(PSW_MASK_EXT); 27 } 28 29 /* 30 * Some KVM versions might mix CPUs when looking for a floating IRQ target, 31 * accidentially detecting a stopped CPU as waiting and resulting in the actually 32 * waiting CPU not getting woken up for the interrupt. 33 */ 34 static void test_wait_state_delivery(void) 35 { 36 SCCBHeader *h; 37 int ret; 38 39 report_prefix_push("wait state delivery"); 40 41 if (smp_query_num_cpus() < 3) { 42 report_skip("need at least 3 CPUs for this test"); 43 goto out; 44 } 45 46 /* Stop CPU #2. It must succeed because we have at least 3 CPUs */ 47 ret = smp_cpu_stop(2); 48 assert(!ret); 49 50 /* 51 * We're going to perform an SCLP service call but expect the 52 * interrupt on CPU #1 while it is in the wait state. 53 */ 54 sclp_mark_busy(); 55 56 /* Start CPU #1 and let it wait for the interrupt. */ 57 ret = smp_cpu_setup(1, PSW_WITH_CUR_MASK(wait_for_sclp_int)); 58 /* This must not fail because we have at least 3 CPUs */ 59 assert(!ret); 60 61 /* 62 * We'd have to jump trough some hoops to sense e.g., via SIGP 63 * CONDITIONAL EMERGENCY SIGNAL if CPU #1 is already in the 64 * wait state. 65 * 66 * Although not completely reliable, use SIGP SENSE RUNNING STATUS 67 * until not reported as running -- after all, our SCLP processing 68 * will take some time as well and smp_cpu_setup() returns when we're 69 * either already in wait_for_sclp_int() or just about to execute it. 70 */ 71 while(smp_sense_running_status(1)); 72 73 h = alloc_pages_flags(0, AREA_DMA31); 74 h->length = 4096; 75 ret = servc(SCLP_CMDW_READ_CPU_INFO, __pa(h)); 76 if (ret) { 77 sclp_clear_busy(); 78 report_fail("SCLP_CMDW_READ_CPU_INFO failed"); 79 goto out_destroy; 80 } 81 82 /* 83 * Wait until the interrupt gets delivered on CPU #1, marking the 84 * SCLP requests as done. 85 */ 86 sclp_wait_busy(); 87 88 report(true, "sclp interrupt delivered"); 89 90 out_destroy: 91 free_page(h); 92 smp_cpu_destroy(1); 93 out: 94 report_prefix_pop(); 95 } 96 97 int main(void) 98 { 99 report_prefix_push("firq"); 100 101 test_wait_state_delivery(); 102 103 report_prefix_pop(); 104 return report_summary(); 105 } 106