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
kaif_lock_enter(uintptr_t * lock)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
kaif_lock_exit(uintptr_t * lock)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
kaif_start_slaves(int cmd)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
kaif_master_loop(kaif_cpusave_t * cpusave)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
kaif_slave_loop(kaif_cpusave_t * cpusave)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
kaif_select_master(kaif_cpusave_t * cpusave)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
kaif_main_loop(kaif_cpusave_t * cpusave)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
kaif_slave_loop_barrier(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