17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5a35baf17Shyw * Common Development and Distribution License (the "License"). 6a35baf17Shyw * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*ae115bc7Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * The main CPU-control loops, used to control masters and slaves. 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <kmdb/kaif.h> 357c478bd9Sstevel@tonic-gate #include <kmdb/kaif_start.h> 367c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_asmutil.h> 377c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h> 387c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #define KAIF_SLAVE_CMD_SPIN 0 417c478bd9Sstevel@tonic-gate #define KAIF_SLAVE_CMD_SWITCH 1 427c478bd9Sstevel@tonic-gate #define KAIF_SLAVE_CMD_RESUME 2 437c478bd9Sstevel@tonic-gate #define KAIF_SLAVE_CMD_FLUSH 3 447c478bd9Sstevel@tonic-gate #define KAIF_SLAVE_CMD_REBOOT 4 45a35baf17Shyw #if defined(__sparc) 46a35baf17Shyw #define KAIF_SLAVE_CMD_ACK 5 47a35baf17Shyw #endif 48a35baf17Shyw 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /* 517c478bd9Sstevel@tonic-gate * Used to synchronize attempts to set kaif_master_cpuid. kaif_master_cpuid may 527c478bd9Sstevel@tonic-gate * be read without kaif_master_lock, and may be written by the current master 537c478bd9Sstevel@tonic-gate * CPU. 547c478bd9Sstevel@tonic-gate */ 557c478bd9Sstevel@tonic-gate int kaif_master_cpuid = KAIF_MASTER_CPUID_UNSET; 567c478bd9Sstevel@tonic-gate static uintptr_t kaif_master_lock = 0; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * Used to ensure that all CPUs leave the debugger together. kaif_loop_lock must 607c478bd9Sstevel@tonic-gate * be held to write kaif_looping, but need not be held to read it. 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate static volatile uint_t kaif_looping; 637c478bd9Sstevel@tonic-gate static uintptr_t kaif_loop_lock; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate static volatile int kaif_slave_cmd; 667c478bd9Sstevel@tonic-gate static volatile int kaif_slave_tgt; /* target cpuid for CMD_SWITCH */ 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate static void 697c478bd9Sstevel@tonic-gate kaif_lock_enter(uintptr_t *lock) 707c478bd9Sstevel@tonic-gate { 717c478bd9Sstevel@tonic-gate while (cas(lock, 0, 1) != 0) 727c478bd9Sstevel@tonic-gate continue; 737c478bd9Sstevel@tonic-gate membar_producer(); 747c478bd9Sstevel@tonic-gate } 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static void 777c478bd9Sstevel@tonic-gate kaif_lock_exit(uintptr_t *lock) 787c478bd9Sstevel@tonic-gate { 797c478bd9Sstevel@tonic-gate *lock = 0; 807c478bd9Sstevel@tonic-gate membar_producer(); 817c478bd9Sstevel@tonic-gate } 827c478bd9Sstevel@tonic-gate 83*ae115bc7Smrj static void 84*ae115bc7Smrj kaif_start_slaves(int cmd) 85*ae115bc7Smrj { 86*ae115bc7Smrj kaif_slave_cmd = cmd; 87*ae115bc7Smrj kmdb_kdi_start_slaves(); 88*ae115bc7Smrj } 89*ae115bc7Smrj 907c478bd9Sstevel@tonic-gate static int 917c478bd9Sstevel@tonic-gate kaif_master_loop(kaif_cpusave_t *cpusave) 927c478bd9Sstevel@tonic-gate { 937c478bd9Sstevel@tonic-gate int notflushed, i; 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate #if defined(__sparc) 967c478bd9Sstevel@tonic-gate kaif_prom_rearm(); 977c478bd9Sstevel@tonic-gate #endif 987c478bd9Sstevel@tonic-gate kaif_trap_set_debugger(); 997c478bd9Sstevel@tonic-gate 100*ae115bc7Smrj /* 101*ae115bc7Smrj * If we re-entered due to a ::switch, we need to tell the slave CPUs 102*ae115bc7Smrj * to sleep again. 103*ae115bc7Smrj */ 104*ae115bc7Smrj kmdb_kdi_stop_slaves(cpusave->krs_cpu_id, 0); 105*ae115bc7Smrj 1067c478bd9Sstevel@tonic-gate master_loop: 1077c478bd9Sstevel@tonic-gate switch (kmdb_dpi_reenter()) { 1087c478bd9Sstevel@tonic-gate case KMDB_DPI_CMD_SWITCH_CPU: 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * We assume that the target CPU is a valid slave. There's no 1117c478bd9Sstevel@tonic-gate * easy way to complain here, so we'll assume that the caller 1127c478bd9Sstevel@tonic-gate * has done the proper checking. 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate if (kmdb_dpi_switch_target == cpusave->krs_cpu_id) 1157c478bd9Sstevel@tonic-gate break; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate kaif_slave_tgt = kaif_master_cpuid = kmdb_dpi_switch_target; 1187c478bd9Sstevel@tonic-gate cpusave->krs_cpu_state = KAIF_CPU_STATE_SLAVE; 1197c478bd9Sstevel@tonic-gate membar_producer(); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate /* 1227c478bd9Sstevel@tonic-gate * Switch back to the saved trap table before we switch CPUs -- 1237c478bd9Sstevel@tonic-gate * we need to make sure that only one CPU is on the debugger's 1247c478bd9Sstevel@tonic-gate * table at a time. 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate kaif_trap_set_saved(cpusave); 1277c478bd9Sstevel@tonic-gate 128*ae115bc7Smrj kaif_start_slaves(KAIF_SLAVE_CMD_SWITCH); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* The new master is now awake */ 1317c478bd9Sstevel@tonic-gate return (KAIF_CPU_CMD_SWITCH); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate case KMDB_DPI_CMD_RESUME_ALL: 1347c478bd9Sstevel@tonic-gate case KMDB_DPI_CMD_RESUME_UNLOAD: 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * Resume everyone, clean up for next entry. 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate kaif_master_cpuid = KAIF_MASTER_CPUID_UNSET; 1397c478bd9Sstevel@tonic-gate membar_producer(); 140*ae115bc7Smrj kaif_start_slaves(KAIF_SLAVE_CMD_RESUME); 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (kmdb_dpi_work_required()) 1437c478bd9Sstevel@tonic-gate kmdb_dpi_wrintr_fire(); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate kaif_trap_set_saved(cpusave); 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate return (KAIF_CPU_CMD_RESUME); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate case KMDB_DPI_CMD_RESUME_MASTER: 1507c478bd9Sstevel@tonic-gate /* 1517c478bd9Sstevel@tonic-gate * Single-CPU resume, which is performed on the debugger's 1527c478bd9Sstevel@tonic-gate * trap table (so no need to switch back). 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate return (KAIF_CPU_CMD_RESUME_MASTER); 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate case KMDB_DPI_CMD_FLUSH_CACHES: 157*ae115bc7Smrj kaif_start_slaves(KAIF_SLAVE_CMD_FLUSH); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * Wait for the other cpus to finish flushing their caches. 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate do { 1637c478bd9Sstevel@tonic-gate notflushed = 0; 1647c478bd9Sstevel@tonic-gate for (i = 0; i < kaif_ncpusave; i++) { 1657c478bd9Sstevel@tonic-gate kaif_cpusave_t *save = &kaif_cpusave[i]; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate if (save->krs_cpu_state == 1687c478bd9Sstevel@tonic-gate KAIF_CPU_STATE_SLAVE && 1697c478bd9Sstevel@tonic-gate !save->krs_cpu_flushed) { 1707c478bd9Sstevel@tonic-gate notflushed++; 1717c478bd9Sstevel@tonic-gate break; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate } while (notflushed > 0); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate kaif_slave_cmd = KAIF_SLAVE_CMD_SPIN; 1777c478bd9Sstevel@tonic-gate break; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 1807c478bd9Sstevel@tonic-gate case KMDB_DPI_CMD_REBOOT: 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * Reboot must be initiated by CPU 0. I could ask why, but I'm 1837c478bd9Sstevel@tonic-gate * afraid that I don't want to know the answer. 1847c478bd9Sstevel@tonic-gate */ 1857c478bd9Sstevel@tonic-gate if (cpusave->krs_cpu_id == 0) 186*ae115bc7Smrj kmdb_kdi_reboot(); 1877c478bd9Sstevel@tonic-gate 188*ae115bc7Smrj kaif_start_slaves(KAIF_SLAVE_CMD_REBOOT); 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate /* 1917c478bd9Sstevel@tonic-gate * Spin forever, waiting for CPU 0 (apparently a slave) to 1927c478bd9Sstevel@tonic-gate * reboot the system. 1937c478bd9Sstevel@tonic-gate */ 1947c478bd9Sstevel@tonic-gate for (;;) 1957c478bd9Sstevel@tonic-gate continue; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1987c478bd9Sstevel@tonic-gate break; 1997c478bd9Sstevel@tonic-gate #endif 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate goto master_loop; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate static int 2067c478bd9Sstevel@tonic-gate kaif_slave_loop(kaif_cpusave_t *cpusave) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate int slavecmd, rv; 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate #if defined(__sparc) 2117c478bd9Sstevel@tonic-gate /* 2127c478bd9Sstevel@tonic-gate * If the user elects to drop to OBP from the debugger, some OBP 2137c478bd9Sstevel@tonic-gate * implementations will cross-call the slaves. We have to turn 2147c478bd9Sstevel@tonic-gate * IE back on so we can receive the cross-calls. If we don't, 2157c478bd9Sstevel@tonic-gate * some OBP implementations will wait forever. 2167c478bd9Sstevel@tonic-gate */ 2177c478bd9Sstevel@tonic-gate interrupts_on(); 2187c478bd9Sstevel@tonic-gate #endif 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* Wait for duty to call */ 2217c478bd9Sstevel@tonic-gate for (;;) { 2227c478bd9Sstevel@tonic-gate slavecmd = kaif_slave_cmd; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if (slavecmd == KAIF_SLAVE_CMD_SWITCH && 2257c478bd9Sstevel@tonic-gate kaif_slave_tgt == cpusave->krs_cpu_id) { 2267c478bd9Sstevel@tonic-gate kaif_slave_cmd = KAIF_SLAVE_CMD_SPIN; 2277c478bd9Sstevel@tonic-gate cpusave->krs_cpu_state = KAIF_CPU_STATE_MASTER; 2287c478bd9Sstevel@tonic-gate rv = KAIF_CPU_CMD_SWITCH; 2297c478bd9Sstevel@tonic-gate break; 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate } else if (slavecmd == KAIF_SLAVE_CMD_FLUSH) { 2327c478bd9Sstevel@tonic-gate kmdb_kdi_flush_caches(); 2337c478bd9Sstevel@tonic-gate cpusave->krs_cpu_flushed = 1; 2347c478bd9Sstevel@tonic-gate continue; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 2377c478bd9Sstevel@tonic-gate } else if (slavecmd == KAIF_SLAVE_CMD_REBOOT && 2387c478bd9Sstevel@tonic-gate cpusave->krs_cpu_id == 0) { 239*ae115bc7Smrj rv = 0; 240*ae115bc7Smrj kmdb_kdi_reboot(); 2417c478bd9Sstevel@tonic-gate break; 2427c478bd9Sstevel@tonic-gate #endif 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate } else if (slavecmd == KAIF_SLAVE_CMD_RESUME) { 2457c478bd9Sstevel@tonic-gate rv = KAIF_CPU_CMD_RESUME; 2467c478bd9Sstevel@tonic-gate break; 247a35baf17Shyw #if defined(__sparc) 248a35baf17Shyw } else if (slavecmd == KAIF_SLAVE_CMD_ACK) { 249a35baf17Shyw cpusave->krs_cpu_acked = 1; 250a35baf17Shyw } else if (cpusave->krs_cpu_acked && 251a35baf17Shyw slavecmd == KAIF_SLAVE_CMD_SPIN) { 252a35baf17Shyw cpusave->krs_cpu_acked = 0; 253a35baf17Shyw #endif 2547c478bd9Sstevel@tonic-gate } 255*ae115bc7Smrj 256*ae115bc7Smrj kmdb_kdi_slave_wait(); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate #if defined(__sparc) 2607c478bd9Sstevel@tonic-gate interrupts_off(); 2617c478bd9Sstevel@tonic-gate #endif 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate return (rv); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate static void 2677c478bd9Sstevel@tonic-gate kaif_select_master(kaif_cpusave_t *cpusave) 2687c478bd9Sstevel@tonic-gate { 2697c478bd9Sstevel@tonic-gate kaif_lock_enter(&kaif_master_lock); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate if (kaif_master_cpuid == KAIF_MASTER_CPUID_UNSET) { 2727c478bd9Sstevel@tonic-gate /* This is the master. */ 2737c478bd9Sstevel@tonic-gate kaif_master_cpuid = cpusave->krs_cpu_id; 2747c478bd9Sstevel@tonic-gate cpusave->krs_cpu_state = KAIF_CPU_STATE_MASTER; 2757c478bd9Sstevel@tonic-gate kaif_slave_cmd = KAIF_SLAVE_CMD_SPIN; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate membar_producer(); 2787c478bd9Sstevel@tonic-gate 279*ae115bc7Smrj kmdb_kdi_stop_slaves(cpusave->krs_cpu_id, 1); 2807c478bd9Sstevel@tonic-gate } else { 2817c478bd9Sstevel@tonic-gate /* The master was already chosen - go be a slave */ 2827c478bd9Sstevel@tonic-gate cpusave->krs_cpu_state = KAIF_CPU_STATE_SLAVE; 2837c478bd9Sstevel@tonic-gate membar_producer(); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate kaif_lock_exit(&kaif_master_lock); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate int 2907c478bd9Sstevel@tonic-gate kaif_main_loop(kaif_cpusave_t *cpusave) 2917c478bd9Sstevel@tonic-gate { 2927c478bd9Sstevel@tonic-gate int cmd; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate if (kaif_master_cpuid == KAIF_MASTER_CPUID_UNSET) { 2957c478bd9Sstevel@tonic-gate if (!kmdb_dpi_resume_requested && 2967c478bd9Sstevel@tonic-gate kmdb_kdi_get_unload_request()) { 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * Special case: Unload requested before first debugger 2997c478bd9Sstevel@tonic-gate * entry. Don't stop the world, as there's nothing to 3007c478bd9Sstevel@tonic-gate * clean up that can't be handled by the running kernel. 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate cpusave->krs_cpu_state = KAIF_CPU_STATE_NONE; 3037c478bd9Sstevel@tonic-gate return (KAIF_CPU_CMD_RESUME); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate kaif_select_master(cpusave); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate #ifdef __sparc 3097c478bd9Sstevel@tonic-gate if (kaif_master_cpuid == cpusave->krs_cpu_id) { 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * Everyone has arrived, so we can disarm the post-PROM 3127c478bd9Sstevel@tonic-gate * entry point. 3137c478bd9Sstevel@tonic-gate */ 3147c478bd9Sstevel@tonic-gate *kaif_promexitarmp = 0; 3157c478bd9Sstevel@tonic-gate membar_producer(); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate #endif 3187c478bd9Sstevel@tonic-gate } else if (kaif_master_cpuid == cpusave->krs_cpu_id) { 3197c478bd9Sstevel@tonic-gate cpusave->krs_cpu_state = KAIF_CPU_STATE_MASTER; 3207c478bd9Sstevel@tonic-gate } else { 3217c478bd9Sstevel@tonic-gate cpusave->krs_cpu_state = KAIF_CPU_STATE_SLAVE; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate cpusave->krs_cpu_flushed = 0; 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate kaif_lock_enter(&kaif_loop_lock); 3277c478bd9Sstevel@tonic-gate kaif_looping++; 3287c478bd9Sstevel@tonic-gate kaif_lock_exit(&kaif_loop_lock); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * We know who the master and slaves are, so now they can go off 3327c478bd9Sstevel@tonic-gate * to their respective loops. 3337c478bd9Sstevel@tonic-gate */ 3347c478bd9Sstevel@tonic-gate do { 3357c478bd9Sstevel@tonic-gate if (kaif_master_cpuid == cpusave->krs_cpu_id) 3367c478bd9Sstevel@tonic-gate cmd = kaif_master_loop(cpusave); 3377c478bd9Sstevel@tonic-gate else 3387c478bd9Sstevel@tonic-gate cmd = kaif_slave_loop(cpusave); 3397c478bd9Sstevel@tonic-gate } while (cmd == KAIF_CPU_CMD_SWITCH); 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate kaif_lock_enter(&kaif_loop_lock); 3427c478bd9Sstevel@tonic-gate kaif_looping--; 3437c478bd9Sstevel@tonic-gate kaif_lock_exit(&kaif_loop_lock); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate cpusave->krs_cpu_state = KAIF_CPU_STATE_NONE; 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate if (cmd == KAIF_CPU_CMD_RESUME) { 3487c478bd9Sstevel@tonic-gate /* 3497c478bd9Sstevel@tonic-gate * By this point, the master has directed the slaves to resume, 3507c478bd9Sstevel@tonic-gate * and everyone is making their way to this point. We're going 3517c478bd9Sstevel@tonic-gate * to block here until all CPUs leave the master and slave 3527c478bd9Sstevel@tonic-gate * loops. When all have arrived, we'll turn them all loose. 3537c478bd9Sstevel@tonic-gate * This barrier is required for two reasons: 3547c478bd9Sstevel@tonic-gate * 3557c478bd9Sstevel@tonic-gate * 1. There exists a race condition whereby a CPU could reenter 3567c478bd9Sstevel@tonic-gate * the debugger while another CPU is still in the slave loop 3577c478bd9Sstevel@tonic-gate * from this debugger entry. This usually happens when the 3587c478bd9Sstevel@tonic-gate * current master releases the slaves, and makes it back to 3597c478bd9Sstevel@tonic-gate * the world before the slaves notice the release. The 3607c478bd9Sstevel@tonic-gate * former master then triggers a debugger entry, and attempts 3617c478bd9Sstevel@tonic-gate * to stop the slaves for this entry before they've even 3627c478bd9Sstevel@tonic-gate * resumed from the last one. When the slaves arrive here, 3637c478bd9Sstevel@tonic-gate * they'll have re-disabled interrupts, and will thus ignore 3647c478bd9Sstevel@tonic-gate * cross-calls until they finish resuming. 3657c478bd9Sstevel@tonic-gate * 3667c478bd9Sstevel@tonic-gate * 2. At the time of this writing, there exists a SPARC bug that 3677c478bd9Sstevel@tonic-gate * causes an apparently unsolicited interrupt vector trap 3687c478bd9Sstevel@tonic-gate * from OBP to one of the slaves. This wouldn't normally be 3697c478bd9Sstevel@tonic-gate * a problem but for the fact that the cross-called CPU 3707c478bd9Sstevel@tonic-gate * encounters some sort of failure while in OBP. OBP 3717c478bd9Sstevel@tonic-gate * recovers by executing the debugger-hook word, which sends 3727c478bd9Sstevel@tonic-gate * the slave back into the debugger, triggering a debugger 3737c478bd9Sstevel@tonic-gate * fault. This problem seems to only happen during resume, 3747c478bd9Sstevel@tonic-gate * the result being that all CPUs save for the cross-called 3757c478bd9Sstevel@tonic-gate * one make it back into the world, while the cross-called 3767c478bd9Sstevel@tonic-gate * one is stuck at the debugger fault prompt. Leave the 3777c478bd9Sstevel@tonic-gate * world in that state too long, and you'll get a mondo 3787c478bd9Sstevel@tonic-gate * timeout panic. If we hold everyone here, we can give the 3797c478bd9Sstevel@tonic-gate * the user a chance to trigger a panic for further analysis. 3807c478bd9Sstevel@tonic-gate * To trigger the bug, "pool_unlock:b :c" and "while : ; do 3817c478bd9Sstevel@tonic-gate * psrset -p ; done". 3827c478bd9Sstevel@tonic-gate * 3837c478bd9Sstevel@tonic-gate * When the second item is fixed, the barrier can move into 3847c478bd9Sstevel@tonic-gate * kaif_select_master(), immediately prior to the setting of 3857c478bd9Sstevel@tonic-gate * kaif_master_cpuid. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate while (kaif_looping != 0) 3887c478bd9Sstevel@tonic-gate continue; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate return (cmd); 3927c478bd9Sstevel@tonic-gate } 393a35baf17Shyw 394a35baf17Shyw 395a35baf17Shyw #if defined(__sparc) 396a35baf17Shyw 397a35baf17Shyw static int slave_loop_barrier_failures = 0; /* for debug */ 398a35baf17Shyw 399a35baf17Shyw /* 400a35baf17Shyw * There exist a race condition observed by some 401a35baf17Shyw * platforms where the kmdb master cpu exits to OBP via 402a35baf17Shyw * prom_enter_mon (e.g. "$q" command) and then later re-enter 403a35baf17Shyw * kmdb (typing "go") while the slaves are still proceeding 404a35baf17Shyw * from the OBP idle-loop back to the kmdb slave loop. The 405a35baf17Shyw * problem arises when the master cpu now back in kmdb proceed 406a35baf17Shyw * to re-enter OBP (e.g. doing a prom_read() from the kmdb main 407a35baf17Shyw * loop) while the slaves are still trying to get out of (the 408a35baf17Shyw * previous trip in) OBP into the safety of the kmdb slave loop. 409a35baf17Shyw * This routine forces the slaves to explicitly acknowledge 410a35baf17Shyw * that they are back in the slave loop. The master cpu can 411a35baf17Shyw * call this routine to ensure that all slave cpus are back 412a35baf17Shyw * in the slave loop before proceeding. 413a35baf17Shyw */ 414a35baf17Shyw void 415a35baf17Shyw kaif_slave_loop_barrier(void) 416a35baf17Shyw { 417a35baf17Shyw extern void kdi_usecwait(clock_t); 418a35baf17Shyw int i; 419a35baf17Shyw int not_acked; 420a35baf17Shyw int timeout_count = 0; 421a35baf17Shyw 422*ae115bc7Smrj kaif_start_slaves(KAIF_SLAVE_CMD_ACK); 423a35baf17Shyw 424a35baf17Shyw /* 425a35baf17Shyw * Wait for slave cpus to explicitly acknowledge 426a35baf17Shyw * that they are spinning in the slave loop. 427a35baf17Shyw */ 428a35baf17Shyw do { 429a35baf17Shyw not_acked = 0; 430a35baf17Shyw for (i = 0; i < kaif_ncpusave; i++) { 431a35baf17Shyw kaif_cpusave_t *save = &kaif_cpusave[i]; 432a35baf17Shyw 433a35baf17Shyw if (save->krs_cpu_state == 434a35baf17Shyw KAIF_CPU_STATE_SLAVE && 435a35baf17Shyw !save->krs_cpu_acked) { 436a35baf17Shyw not_acked++; 437a35baf17Shyw break; 438a35baf17Shyw } 439a35baf17Shyw } 440a35baf17Shyw 441a35baf17Shyw if (not_acked == 0) 442a35baf17Shyw break; 443a35baf17Shyw 444a35baf17Shyw /* 445a35baf17Shyw * Play it safe and do a timeout delay. 446a35baf17Shyw * We will do at most kaif_ncpusave delays before 447a35baf17Shyw * bailing out of this barrier. 448a35baf17Shyw */ 449a35baf17Shyw kdi_usecwait(200); 450a35baf17Shyw 451a35baf17Shyw } while (++timeout_count < kaif_ncpusave); 452a35baf17Shyw 453a35baf17Shyw if (not_acked > 0) 454a35baf17Shyw /* 455a35baf17Shyw * we cannot establish a barrier with all 456a35baf17Shyw * the slave cpus coming back from OBP 457a35baf17Shyw * Record this fact for future debugging 458a35baf17Shyw */ 459a35baf17Shyw slave_loop_barrier_failures++; 460a35baf17Shyw 461a35baf17Shyw kaif_slave_cmd = KAIF_SLAVE_CMD_SPIN; 462a35baf17Shyw } 463a35baf17Shyw #endif 464