/* SPDX-License-Identifier: GPL-2.0-only */ /* * Floating interrupt tests. * * Copyright 2021 Red Hat Inc * * Authors: * David Hildenbrand */ #include #include #include #include #include #include #include #include static void wait_for_sclp_int(void) { /* Enable SCLP interrupts on this CPU only. */ ctl_set_bit(0, CTL0_SERVICE_SIGNAL); /* Enable external interrupts and go to the wait state. */ wait_for_interrupt(PSW_MASK_EXT); } /* * Some KVM versions might mix CPUs when looking for a floating IRQ target, * accidentially detecting a stopped CPU as waiting and resulting in the actually * waiting CPU not getting woken up for the interrupt. */ static void test_wait_state_delivery(void) { SCCBHeader *h; int ret; report_prefix_push("wait state delivery"); if (smp_query_num_cpus() < 3) { report_skip("need at least 3 CPUs for this test"); goto out; } /* Stop CPU #2. It must succeed because we have at least 3 CPUs */ ret = smp_cpu_stop(2); assert(!ret); /* * We're going to perform an SCLP service call but expect the * interrupt on CPU #1 while it is in the wait state. */ sclp_mark_busy(); /* Start CPU #1 and let it wait for the interrupt. */ ret = smp_cpu_setup(1, PSW_WITH_CUR_MASK(wait_for_sclp_int)); /* This must not fail because we have at least 3 CPUs */ assert(!ret); /* * We'd have to jump trough some hoops to sense e.g., via SIGP * CONDITIONAL EMERGENCY SIGNAL if CPU #1 is already in the * wait state. * * Although not completely reliable, use SIGP SENSE RUNNING STATUS * until not reported as running -- after all, our SCLP processing * will take some time as well and smp_cpu_setup() returns when we're * either already in wait_for_sclp_int() or just about to execute it. */ while(smp_sense_running_status(1)); h = alloc_pages_flags(0, AREA_DMA31); h->length = 4096; ret = servc(SCLP_CMDW_READ_CPU_INFO, __pa(h)); if (ret) { sclp_clear_busy(); report_fail("SCLP_CMDW_READ_CPU_INFO failed"); goto out_destroy; } /* * Wait until the interrupt gets delivered on CPU #1, marking the * SCLP requests as done. */ sclp_wait_busy(); report(true, "sclp interrupt delivered"); out_destroy: free_page(h); smp_cpu_destroy(1); out: report_prefix_pop(); } int main(void) { report_prefix_push("firq"); test_wait_state_delivery(); report_prefix_pop(); return report_summary(); }