18b98745dSDavid Hildenbrand /* SPDX-License-Identifier: GPL-2.0-only */ 28b98745dSDavid Hildenbrand /* 38b98745dSDavid Hildenbrand * Floating interrupt tests. 48b98745dSDavid Hildenbrand * 58b98745dSDavid Hildenbrand * Copyright 2021 Red Hat Inc 68b98745dSDavid Hildenbrand * 78b98745dSDavid Hildenbrand * Authors: 88b98745dSDavid Hildenbrand * David Hildenbrand <david@redhat.com> 98b98745dSDavid Hildenbrand */ 108b98745dSDavid Hildenbrand #include <libcflat.h> 118b98745dSDavid Hildenbrand #include <asm/asm-offsets.h> 128b98745dSDavid Hildenbrand #include <asm/interrupt.h> 138b98745dSDavid Hildenbrand #include <asm/page.h> 148b98745dSDavid Hildenbrand #include <asm-generic/barrier.h> 158b98745dSDavid Hildenbrand 168b98745dSDavid Hildenbrand #include <sclp.h> 178b98745dSDavid Hildenbrand #include <smp.h> 188b98745dSDavid Hildenbrand #include <alloc_page.h> 198b98745dSDavid Hildenbrand 208b98745dSDavid Hildenbrand static void wait_for_sclp_int(void) 218b98745dSDavid Hildenbrand { 228b98745dSDavid Hildenbrand /* Enable SCLP interrupts on this CPU only. */ 238b98745dSDavid Hildenbrand ctl_set_bit(0, CTL0_SERVICE_SIGNAL); 248b98745dSDavid Hildenbrand 258b98745dSDavid Hildenbrand /* Enable external interrupts and go to the wait state. */ 268b98745dSDavid Hildenbrand wait_for_interrupt(PSW_MASK_EXT); 278b98745dSDavid Hildenbrand } 288b98745dSDavid Hildenbrand 298b98745dSDavid Hildenbrand /* 308b98745dSDavid Hildenbrand * Some KVM versions might mix CPUs when looking for a floating IRQ target, 318b98745dSDavid Hildenbrand * accidentially detecting a stopped CPU as waiting and resulting in the actually 328b98745dSDavid Hildenbrand * waiting CPU not getting woken up for the interrupt. 338b98745dSDavid Hildenbrand */ 348b98745dSDavid Hildenbrand static void test_wait_state_delivery(void) 358b98745dSDavid Hildenbrand { 368b98745dSDavid Hildenbrand struct psw psw; 378b98745dSDavid Hildenbrand SCCBHeader *h; 388b98745dSDavid Hildenbrand int ret; 398b98745dSDavid Hildenbrand 408b98745dSDavid Hildenbrand report_prefix_push("wait state delivery"); 418b98745dSDavid Hildenbrand 428b98745dSDavid Hildenbrand if (smp_query_num_cpus() < 3) { 438b98745dSDavid Hildenbrand report_skip("need at least 3 CPUs for this test"); 448b98745dSDavid Hildenbrand goto out; 458b98745dSDavid Hildenbrand } 468b98745dSDavid Hildenbrand 478b98745dSDavid Hildenbrand if (stap()) { 488b98745dSDavid Hildenbrand report_skip("need to start on CPU #0"); 498b98745dSDavid Hildenbrand goto out; 508b98745dSDavid Hildenbrand } 518b98745dSDavid Hildenbrand 528b98745dSDavid Hildenbrand /* 538b98745dSDavid Hildenbrand * We want CPU #2 to be stopped. This should be the case at this 548b98745dSDavid Hildenbrand * point, however, we want to sense if it even exists as well. 558b98745dSDavid Hildenbrand */ 568b98745dSDavid Hildenbrand ret = smp_cpu_stop(2); 578b98745dSDavid Hildenbrand if (ret) { 588b98745dSDavid Hildenbrand report_skip("CPU #2 not found"); 598b98745dSDavid Hildenbrand goto out; 608b98745dSDavid Hildenbrand } 618b98745dSDavid Hildenbrand 628b98745dSDavid Hildenbrand /* 638b98745dSDavid Hildenbrand * We're going to perform an SCLP service call but expect 648b98745dSDavid Hildenbrand * the interrupt on CPU #1 while it is in the wait state. 658b98745dSDavid Hildenbrand */ 668b98745dSDavid Hildenbrand sclp_mark_busy(); 678b98745dSDavid Hildenbrand 688b98745dSDavid Hildenbrand /* Start CPU #1 and let it wait for the interrupt. */ 698b98745dSDavid Hildenbrand psw.mask = extract_psw_mask(); 708b98745dSDavid Hildenbrand psw.addr = (unsigned long)wait_for_sclp_int; 718b98745dSDavid Hildenbrand ret = smp_cpu_setup(1, psw); 728b98745dSDavid Hildenbrand if (ret) { 738b98745dSDavid Hildenbrand sclp_clear_busy(); 748b98745dSDavid Hildenbrand report_skip("cpu #1 not found"); 758b98745dSDavid Hildenbrand goto out; 768b98745dSDavid Hildenbrand } 778b98745dSDavid Hildenbrand 788b98745dSDavid Hildenbrand /* 798b98745dSDavid Hildenbrand * We'd have to jump trough some hoops to sense e.g., via SIGP 808b98745dSDavid Hildenbrand * CONDITIONAL EMERGENCY SIGNAL if CPU #1 is already in the 818b98745dSDavid Hildenbrand * wait state. 828b98745dSDavid Hildenbrand * 838b98745dSDavid Hildenbrand * Although not completely reliable, use SIGP SENSE RUNNING STATUS 848b98745dSDavid Hildenbrand * until not reported as running -- after all, our SCLP processing 858b98745dSDavid Hildenbrand * will take some time as well and smp_cpu_setup() returns when we're 868b98745dSDavid Hildenbrand * either already in wait_for_sclp_int() or just about to execute it. 878b98745dSDavid Hildenbrand */ 888b98745dSDavid Hildenbrand while(smp_sense_running_status(1)); 898b98745dSDavid Hildenbrand 90*0f26dca4SJanosch Frank h = alloc_pages_flags(0, AREA_DMA31); 918b98745dSDavid Hildenbrand h->length = 4096; 928b98745dSDavid Hildenbrand ret = servc(SCLP_CMDW_READ_CPU_INFO, __pa(h)); 938b98745dSDavid Hildenbrand if (ret) { 948b98745dSDavid Hildenbrand sclp_clear_busy(); 958b98745dSDavid Hildenbrand report_fail("SCLP_CMDW_READ_CPU_INFO failed"); 968b98745dSDavid Hildenbrand goto out_destroy; 978b98745dSDavid Hildenbrand } 988b98745dSDavid Hildenbrand 998b98745dSDavid Hildenbrand /* 1008b98745dSDavid Hildenbrand * Wait until the interrupt gets delivered on CPU #1, marking the 1018b98745dSDavid Hildenbrand * SCLP requests as done. 1028b98745dSDavid Hildenbrand */ 1038b98745dSDavid Hildenbrand sclp_wait_busy(); 1048b98745dSDavid Hildenbrand 1058b98745dSDavid Hildenbrand report(true, "sclp interrupt delivered"); 1068b98745dSDavid Hildenbrand 1078b98745dSDavid Hildenbrand out_destroy: 1088b98745dSDavid Hildenbrand free_page(h); 1098b98745dSDavid Hildenbrand smp_cpu_destroy(1); 1108b98745dSDavid Hildenbrand out: 1118b98745dSDavid Hildenbrand report_prefix_pop(); 1128b98745dSDavid Hildenbrand } 1138b98745dSDavid Hildenbrand 1148b98745dSDavid Hildenbrand int main(void) 1158b98745dSDavid Hildenbrand { 1168b98745dSDavid Hildenbrand report_prefix_push("firq"); 1178b98745dSDavid Hildenbrand 1188b98745dSDavid Hildenbrand test_wait_state_delivery(); 1198b98745dSDavid Hildenbrand 1208b98745dSDavid Hildenbrand report_prefix_pop(); 1218b98745dSDavid Hildenbrand return report_summary(); 1228b98745dSDavid Hildenbrand } 123