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 struct psw psw; 37 SCCBHeader *h; 38 int ret; 39 40 report_prefix_push("wait state delivery"); 41 42 if (smp_query_num_cpus() < 3) { 43 report_skip("need at least 3 CPUs for this test"); 44 goto out; 45 } 46 47 if (stap()) { 48 report_skip("need to start on CPU #0"); 49 goto out; 50 } 51 52 /* 53 * We want CPU #2 to be stopped. This should be the case at this 54 * point, however, we want to sense if it even exists as well. 55 */ 56 ret = smp_cpu_stop(2); 57 if (ret) { 58 report_skip("CPU #2 not found"); 59 goto out; 60 } 61 62 /* 63 * We're going to perform an SCLP service call but expect 64 * the interrupt on CPU #1 while it is in the wait state. 65 */ 66 sclp_mark_busy(); 67 68 /* Start CPU #1 and let it wait for the interrupt. */ 69 psw.mask = extract_psw_mask(); 70 psw.addr = (unsigned long)wait_for_sclp_int; 71 ret = smp_cpu_setup(1, psw); 72 if (ret) { 73 sclp_clear_busy(); 74 report_skip("cpu #1 not found"); 75 goto out; 76 } 77 78 /* 79 * We'd have to jump trough some hoops to sense e.g., via SIGP 80 * CONDITIONAL EMERGENCY SIGNAL if CPU #1 is already in the 81 * wait state. 82 * 83 * Although not completely reliable, use SIGP SENSE RUNNING STATUS 84 * until not reported as running -- after all, our SCLP processing 85 * will take some time as well and smp_cpu_setup() returns when we're 86 * either already in wait_for_sclp_int() or just about to execute it. 87 */ 88 while(smp_sense_running_status(1)); 89 90 h = alloc_pages_flags(0, AREA_DMA31); 91 h->length = 4096; 92 ret = servc(SCLP_CMDW_READ_CPU_INFO, __pa(h)); 93 if (ret) { 94 sclp_clear_busy(); 95 report_fail("SCLP_CMDW_READ_CPU_INFO failed"); 96 goto out_destroy; 97 } 98 99 /* 100 * Wait until the interrupt gets delivered on CPU #1, marking the 101 * SCLP requests as done. 102 */ 103 sclp_wait_busy(); 104 105 report(true, "sclp interrupt delivered"); 106 107 out_destroy: 108 free_page(h); 109 smp_cpu_destroy(1); 110 out: 111 report_prefix_pop(); 112 } 113 114 int main(void) 115 { 116 report_prefix_push("firq"); 117 118 test_wait_state_delivery(); 119 120 report_prefix_pop(); 121 return report_summary(); 122 } 123