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 /*
22ae115bc7Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*66a2141cSJohn Levon  * Copyright 2018 Joyent, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * The main CPU-control loops, used to control masters and slaves.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <kmdb/kaif.h>
347c478bd9Sstevel@tonic-gate #include <kmdb/kaif_start.h>
357c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_asmutil.h>
367c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h>
377c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #define	KAIF_SLAVE_CMD_SPIN	0
407c478bd9Sstevel@tonic-gate #define	KAIF_SLAVE_CMD_SWITCH	1
417c478bd9Sstevel@tonic-gate #define	KAIF_SLAVE_CMD_RESUME	2
427c478bd9Sstevel@tonic-gate #define	KAIF_SLAVE_CMD_FLUSH	3
437c478bd9Sstevel@tonic-gate #define	KAIF_SLAVE_CMD_REBOOT	4
44a35baf17Shyw #if defined(__sparc)
45a35baf17Shyw #define	KAIF_SLAVE_CMD_ACK	5
46a35baf17Shyw #endif
47a35baf17Shyw 
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * Used to synchronize attempts to set kaif_master_cpuid.  kaif_master_cpuid may
517c478bd9Sstevel@tonic-gate  * be read without kaif_master_lock, and may be written by the current master
527c478bd9Sstevel@tonic-gate  * CPU.
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate int kaif_master_cpuid = KAIF_MASTER_CPUID_UNSET;
557c478bd9Sstevel@tonic-gate static uintptr_t kaif_master_lock = 0;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * Used to ensure that all CPUs leave the debugger together. kaif_loop_lock must
597c478bd9Sstevel@tonic-gate  * be held to write kaif_looping, but need not be held to read it.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate static volatile uint_t kaif_looping;
627c478bd9Sstevel@tonic-gate static uintptr_t kaif_loop_lock;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static volatile int kaif_slave_cmd;
657c478bd9Sstevel@tonic-gate static volatile int kaif_slave_tgt;	/* target cpuid for CMD_SWITCH */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate static void
kaif_lock_enter(uintptr_t * lock)687c478bd9Sstevel@tonic-gate kaif_lock_enter(uintptr_t *lock)
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate 	while (cas(lock, 0, 1) != 0)
717c478bd9Sstevel@tonic-gate 		continue;
727c478bd9Sstevel@tonic-gate 	membar_producer();
737c478bd9Sstevel@tonic-gate }
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static void
kaif_lock_exit(uintptr_t * lock)767c478bd9Sstevel@tonic-gate kaif_lock_exit(uintptr_t *lock)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	*lock = 0;
797c478bd9Sstevel@tonic-gate 	membar_producer();
807c478bd9Sstevel@tonic-gate }
817c478bd9Sstevel@tonic-gate 
82ae115bc7Smrj static void
kaif_start_slaves(int cmd)83ae115bc7Smrj kaif_start_slaves(int cmd)
84ae115bc7Smrj {
85ae115bc7Smrj 	kaif_slave_cmd = cmd;
86ae115bc7Smrj 	kmdb_kdi_start_slaves();
87ae115bc7Smrj }
88ae115bc7Smrj 
897c478bd9Sstevel@tonic-gate static int
kaif_master_loop(kaif_cpusave_t * cpusave)907c478bd9Sstevel@tonic-gate kaif_master_loop(kaif_cpusave_t *cpusave)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	int notflushed, i;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #if defined(__sparc)
957c478bd9Sstevel@tonic-gate 	kaif_prom_rearm();
967c478bd9Sstevel@tonic-gate #endif
977c478bd9Sstevel@tonic-gate 	kaif_trap_set_debugger();
987c478bd9Sstevel@tonic-gate 
99ae115bc7Smrj 	/*
100ae115bc7Smrj 	 * If we re-entered due to a ::switch, we need to tell the slave CPUs
101ae115bc7Smrj 	 * to sleep again.
102ae115bc7Smrj 	 */
103ae115bc7Smrj 	kmdb_kdi_stop_slaves(cpusave->krs_cpu_id, 0);
104ae115bc7Smrj 
1057c478bd9Sstevel@tonic-gate master_loop:
1067c478bd9Sstevel@tonic-gate 	switch (kmdb_dpi_reenter()) {
1077c478bd9Sstevel@tonic-gate 	case KMDB_DPI_CMD_SWITCH_CPU:
1087c478bd9Sstevel@tonic-gate 		/*
1097c478bd9Sstevel@tonic-gate 		 * We assume that the target CPU is a valid slave.  There's no
1107c478bd9Sstevel@tonic-gate 		 * easy way to complain here, so we'll assume that the caller
1117c478bd9Sstevel@tonic-gate 		 * has done the proper checking.
1127c478bd9Sstevel@tonic-gate 		 */
1137c478bd9Sstevel@tonic-gate 		if (kmdb_dpi_switch_target == cpusave->krs_cpu_id)
1147c478bd9Sstevel@tonic-gate 			break;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 		kaif_slave_tgt = kaif_master_cpuid = kmdb_dpi_switch_target;
1177c478bd9Sstevel@tonic-gate 		cpusave->krs_cpu_state = KAIF_CPU_STATE_SLAVE;
1187c478bd9Sstevel@tonic-gate 		membar_producer();
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 		/*
1217c478bd9Sstevel@tonic-gate 		 * Switch back to the saved trap table before we switch CPUs --
1227c478bd9Sstevel@tonic-gate 		 * we need to make sure that only one CPU is on the debugger's
1237c478bd9Sstevel@tonic-gate 		 * table at a time.
1247c478bd9Sstevel@tonic-gate 		 */
1257c478bd9Sstevel@tonic-gate 		kaif_trap_set_saved(cpusave);
1267c478bd9Sstevel@tonic-gate 
127ae115bc7Smrj 		kaif_start_slaves(KAIF_SLAVE_CMD_SWITCH);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 		/* The new master is now awake */
1307c478bd9Sstevel@tonic-gate 		return (KAIF_CPU_CMD_SWITCH);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	case KMDB_DPI_CMD_RESUME_ALL:
1337c478bd9Sstevel@tonic-gate 	case KMDB_DPI_CMD_RESUME_UNLOAD:
1347c478bd9Sstevel@tonic-gate 		/*
1357c478bd9Sstevel@tonic-gate 		 * Resume everyone, clean up for next entry.
1367c478bd9Sstevel@tonic-gate 		 */
1377c478bd9Sstevel@tonic-gate 		kaif_master_cpuid = KAIF_MASTER_CPUID_UNSET;
1387c478bd9Sstevel@tonic-gate 		membar_producer();
139ae115bc7Smrj 		kaif_start_slaves(KAIF_SLAVE_CMD_RESUME);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 		if (kmdb_dpi_work_required())
1427c478bd9Sstevel@tonic-gate 			kmdb_dpi_wrintr_fire();
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 		kaif_trap_set_saved(cpusave);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 		return (KAIF_CPU_CMD_RESUME);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	case KMDB_DPI_CMD_RESUME_MASTER:
1497c478bd9Sstevel@tonic-gate 		/*
1507c478bd9Sstevel@tonic-gate 		 * Single-CPU resume, which is performed on the debugger's
1517c478bd9Sstevel@tonic-gate 		 * trap table (so no need to switch back).
1527c478bd9Sstevel@tonic-gate 		 */
1537c478bd9Sstevel@tonic-gate 		return (KAIF_CPU_CMD_RESUME_MASTER);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	case KMDB_DPI_CMD_FLUSH_CACHES:
156ae115bc7Smrj 		kaif_start_slaves(KAIF_SLAVE_CMD_FLUSH);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 		/*
1597c478bd9Sstevel@tonic-gate 		 * Wait for the other cpus to finish flushing their caches.
1607c478bd9Sstevel@tonic-gate 		 */
1617c478bd9Sstevel@tonic-gate 		do {
1627c478bd9Sstevel@tonic-gate 			notflushed = 0;
1637c478bd9Sstevel@tonic-gate 			for (i = 0; i < kaif_ncpusave; i++) {
1647c478bd9Sstevel@tonic-gate 				kaif_cpusave_t *save = &kaif_cpusave[i];
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 				if (save->krs_cpu_state ==
1677c478bd9Sstevel@tonic-gate 				    KAIF_CPU_STATE_SLAVE &&
1687c478bd9Sstevel@tonic-gate 				    !save->krs_cpu_flushed) {
1697c478bd9Sstevel@tonic-gate 					notflushed++;
1707c478bd9Sstevel@tonic-gate 					break;
1717c478bd9Sstevel@tonic-gate 				}
1727c478bd9Sstevel@tonic-gate 			}
1737c478bd9Sstevel@tonic-gate 		} while (notflushed > 0);
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 		kaif_slave_cmd = KAIF_SLAVE_CMD_SPIN;
1767c478bd9Sstevel@tonic-gate 		break;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
1797c478bd9Sstevel@tonic-gate 	case KMDB_DPI_CMD_REBOOT:
1807c478bd9Sstevel@tonic-gate 		/*
1817c478bd9Sstevel@tonic-gate 		 * Reboot must be initiated by CPU 0.  I could ask why, but I'm
1827c478bd9Sstevel@tonic-gate 		 * afraid that I don't want to know the answer.
1837c478bd9Sstevel@tonic-gate 		 */
1847c478bd9Sstevel@tonic-gate 		if (cpusave->krs_cpu_id == 0)
185ae115bc7Smrj 			kmdb_kdi_reboot();
1867c478bd9Sstevel@tonic-gate 
187ae115bc7Smrj 		kaif_start_slaves(KAIF_SLAVE_CMD_REBOOT);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 		/*
1907c478bd9Sstevel@tonic-gate 		 * Spin forever, waiting for CPU 0 (apparently a slave) to
1917c478bd9Sstevel@tonic-gate 		 * reboot the system.
1927c478bd9Sstevel@tonic-gate 		 */
1937c478bd9Sstevel@tonic-gate 		for (;;)
1947c478bd9Sstevel@tonic-gate 			continue;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1977c478bd9Sstevel@tonic-gate 		break;
1987c478bd9Sstevel@tonic-gate #endif
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	goto master_loop;
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate static int
kaif_slave_loop(kaif_cpusave_t * cpusave)2057c478bd9Sstevel@tonic-gate kaif_slave_loop(kaif_cpusave_t *cpusave)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	int slavecmd, rv;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate #if defined(__sparc)
2107c478bd9Sstevel@tonic-gate 	/*
2117c478bd9Sstevel@tonic-gate 	 * If the user elects to drop to OBP from the debugger, some OBP
2127c478bd9Sstevel@tonic-gate 	 * implementations will cross-call the slaves.  We have to turn
2137c478bd9Sstevel@tonic-gate 	 * IE back on so we can receive the cross-calls.  If we don't,
2147c478bd9Sstevel@tonic-gate 	 * some OBP implementations will wait forever.
2157c478bd9Sstevel@tonic-gate 	 */
2167c478bd9Sstevel@tonic-gate 	interrupts_on();
2177c478bd9Sstevel@tonic-gate #endif
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/* Wait for duty to call */
2207c478bd9Sstevel@tonic-gate 	for (;;) {
2217c478bd9Sstevel@tonic-gate 		slavecmd = kaif_slave_cmd;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 		if (slavecmd == KAIF_SLAVE_CMD_SWITCH &&
2247c478bd9Sstevel@tonic-gate 		    kaif_slave_tgt == cpusave->krs_cpu_id) {
2257c478bd9Sstevel@tonic-gate 			kaif_slave_cmd = KAIF_SLAVE_CMD_SPIN;
2267c478bd9Sstevel@tonic-gate 			cpusave->krs_cpu_state = KAIF_CPU_STATE_MASTER;
2277c478bd9Sstevel@tonic-gate 			rv = KAIF_CPU_CMD_SWITCH;
2287c478bd9Sstevel@tonic-gate 			break;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 		} else if (slavecmd == KAIF_SLAVE_CMD_FLUSH) {
2317c478bd9Sstevel@tonic-gate 			kmdb_kdi_flush_caches();
2327c478bd9Sstevel@tonic-gate 			cpusave->krs_cpu_flushed = 1;
2337c478bd9Sstevel@tonic-gate 			continue;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
2367c478bd9Sstevel@tonic-gate 		} else if (slavecmd == KAIF_SLAVE_CMD_REBOOT &&
2377c478bd9Sstevel@tonic-gate 		    cpusave->krs_cpu_id == 0) {
238ae115bc7Smrj 			rv = 0;
239ae115bc7Smrj 			kmdb_kdi_reboot();
2407c478bd9Sstevel@tonic-gate 			break;
2417c478bd9Sstevel@tonic-gate #endif
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 		} else if (slavecmd == KAIF_SLAVE_CMD_RESUME) {
2447c478bd9Sstevel@tonic-gate 			rv = KAIF_CPU_CMD_RESUME;
2457c478bd9Sstevel@tonic-gate 			break;
246a35baf17Shyw #if defined(__sparc)
247a35baf17Shyw 		} else if (slavecmd == KAIF_SLAVE_CMD_ACK) {
248a35baf17Shyw 			cpusave->krs_cpu_acked = 1;
249a35baf17Shyw 		} else if (cpusave->krs_cpu_acked &&
250*66a2141cSJohn Levon 		    slavecmd == KAIF_SLAVE_CMD_SPIN) {
251a35baf17Shyw 			cpusave->krs_cpu_acked = 0;
252a35baf17Shyw #endif
2537c478bd9Sstevel@tonic-gate 		}
254ae115bc7Smrj 
255ae115bc7Smrj 		kmdb_kdi_slave_wait();
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate #if defined(__sparc)
2597c478bd9Sstevel@tonic-gate 	interrupts_off();
2607c478bd9Sstevel@tonic-gate #endif
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	return (rv);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate static void
kaif_select_master(kaif_cpusave_t * cpusave)2667c478bd9Sstevel@tonic-gate kaif_select_master(kaif_cpusave_t *cpusave)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	kaif_lock_enter(&kaif_master_lock);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	if (kaif_master_cpuid == KAIF_MASTER_CPUID_UNSET) {
2717c478bd9Sstevel@tonic-gate 		/* This is the master. */
2727c478bd9Sstevel@tonic-gate 		kaif_master_cpuid = cpusave->krs_cpu_id;
2737c478bd9Sstevel@tonic-gate 		cpusave->krs_cpu_state = KAIF_CPU_STATE_MASTER;
2747c478bd9Sstevel@tonic-gate 		kaif_slave_cmd = KAIF_SLAVE_CMD_SPIN;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		membar_producer();
2777c478bd9Sstevel@tonic-gate 
278ae115bc7Smrj 		kmdb_kdi_stop_slaves(cpusave->krs_cpu_id, 1);
2797c478bd9Sstevel@tonic-gate 	} else {
2807c478bd9Sstevel@tonic-gate 		/* The master was already chosen - go be a slave */
2817c478bd9Sstevel@tonic-gate 		cpusave->krs_cpu_state = KAIF_CPU_STATE_SLAVE;
2827c478bd9Sstevel@tonic-gate 		membar_producer();
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	kaif_lock_exit(&kaif_master_lock);
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate int
kaif_main_loop(kaif_cpusave_t * cpusave)2897c478bd9Sstevel@tonic-gate kaif_main_loop(kaif_cpusave_t *cpusave)
2907c478bd9Sstevel@tonic-gate {
2917c478bd9Sstevel@tonic-gate 	int cmd;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	if (kaif_master_cpuid == KAIF_MASTER_CPUID_UNSET) {
294*66a2141cSJohn Levon 
295*66a2141cSJohn Levon 		/*
296*66a2141cSJohn Levon 		 * Special case: Unload requested before first debugger entry.
297*66a2141cSJohn Levon 		 * Don't stop the world, as there's nothing to clean up that
298*66a2141cSJohn Levon 		 * can't be handled by the running kernel.
299*66a2141cSJohn Levon 		 */
3007c478bd9Sstevel@tonic-gate 		if (!kmdb_dpi_resume_requested &&
3017c478bd9Sstevel@tonic-gate 		    kmdb_kdi_get_unload_request()) {
302*66a2141cSJohn Levon 			cpusave->krs_cpu_state = KAIF_CPU_STATE_NONE;
303*66a2141cSJohn Levon 			return (KAIF_CPU_CMD_RESUME);
304*66a2141cSJohn Levon 		}
305*66a2141cSJohn Levon 
306*66a2141cSJohn Levon 		/*
307*66a2141cSJohn Levon 		 * We're a slave with no master, so just resume.  This can
308*66a2141cSJohn Levon 		 * happen if, prior to this, two CPUs both raced through
309*66a2141cSJohn Levon 		 * kdi_cmnint() - for example, a breakpoint on a frequently
310*66a2141cSJohn Levon 		 * called function.  The loser will be redirected to the slave
311*66a2141cSJohn Levon 		 * loop; note that the event itself is lost at this point.
312*66a2141cSJohn Levon 		 *
313*66a2141cSJohn Levon 		 * The winner will then cross-call that slave, but it won't
314*66a2141cSJohn Levon 		 * actually be received until the slave returns to the kernel
315*66a2141cSJohn Levon 		 * and enables interrupts.  We'll then come back in via
316*66a2141cSJohn Levon 		 * kdi_slave_entry() and hit this path.
317*66a2141cSJohn Levon 		 */
318*66a2141cSJohn Levon 		if (cpusave->krs_cpu_state == KAIF_CPU_STATE_SLAVE) {
3197c478bd9Sstevel@tonic-gate 			cpusave->krs_cpu_state = KAIF_CPU_STATE_NONE;
3207c478bd9Sstevel@tonic-gate 			return (KAIF_CPU_CMD_RESUME);
3217c478bd9Sstevel@tonic-gate 		}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 		kaif_select_master(cpusave);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate #ifdef __sparc
3267c478bd9Sstevel@tonic-gate 		if (kaif_master_cpuid == cpusave->krs_cpu_id) {
3277c478bd9Sstevel@tonic-gate 			/*
3287c478bd9Sstevel@tonic-gate 			 * Everyone has arrived, so we can disarm the post-PROM
3297c478bd9Sstevel@tonic-gate 			 * entry point.
3307c478bd9Sstevel@tonic-gate 			 */
3317c478bd9Sstevel@tonic-gate 			*kaif_promexitarmp = 0;
3327c478bd9Sstevel@tonic-gate 			membar_producer();
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate #endif
3357c478bd9Sstevel@tonic-gate 	} else if (kaif_master_cpuid == cpusave->krs_cpu_id) {
3367c478bd9Sstevel@tonic-gate 		cpusave->krs_cpu_state = KAIF_CPU_STATE_MASTER;
3377c478bd9Sstevel@tonic-gate 	} else {
3387c478bd9Sstevel@tonic-gate 		cpusave->krs_cpu_state = KAIF_CPU_STATE_SLAVE;
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	cpusave->krs_cpu_flushed = 0;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	kaif_lock_enter(&kaif_loop_lock);
3447c478bd9Sstevel@tonic-gate 	kaif_looping++;
3457c478bd9Sstevel@tonic-gate 	kaif_lock_exit(&kaif_loop_lock);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/*
3487c478bd9Sstevel@tonic-gate 	 * We know who the master and slaves are, so now they can go off
3497c478bd9Sstevel@tonic-gate 	 * to their respective loops.
3507c478bd9Sstevel@tonic-gate 	 */
3517c478bd9Sstevel@tonic-gate 	do {
3527c478bd9Sstevel@tonic-gate 		if (kaif_master_cpuid == cpusave->krs_cpu_id)
3537c478bd9Sstevel@tonic-gate 			cmd = kaif_master_loop(cpusave);
3547c478bd9Sstevel@tonic-gate 		else
3557c478bd9Sstevel@tonic-gate 			cmd = kaif_slave_loop(cpusave);
3567c478bd9Sstevel@tonic-gate 	} while (cmd == KAIF_CPU_CMD_SWITCH);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	kaif_lock_enter(&kaif_loop_lock);
3597c478bd9Sstevel@tonic-gate 	kaif_looping--;
3607c478bd9Sstevel@tonic-gate 	kaif_lock_exit(&kaif_loop_lock);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	cpusave->krs_cpu_state = KAIF_CPU_STATE_NONE;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	if (cmd == KAIF_CPU_CMD_RESUME) {
3657c478bd9Sstevel@tonic-gate 		/*
3667c478bd9Sstevel@tonic-gate 		 * By this point, the master has directed the slaves to resume,
3677c478bd9Sstevel@tonic-gate 		 * and everyone is making their way to this point.  We're going
3687c478bd9Sstevel@tonic-gate 		 * to block here until all CPUs leave the master and slave
3697c478bd9Sstevel@tonic-gate 		 * loops.  When all have arrived, we'll turn them all loose.
3707c478bd9Sstevel@tonic-gate 		 * This barrier is required for two reasons:
3717c478bd9Sstevel@tonic-gate 		 *
3727c478bd9Sstevel@tonic-gate 		 * 1. There exists a race condition whereby a CPU could reenter
3737c478bd9Sstevel@tonic-gate 		 *    the debugger while another CPU is still in the slave loop
3747c478bd9Sstevel@tonic-gate 		 *    from this debugger entry.  This usually happens when the
3757c478bd9Sstevel@tonic-gate 		 *    current master releases the slaves, and makes it back to
3767c478bd9Sstevel@tonic-gate 		 *    the world before the slaves notice the release.  The
3777c478bd9Sstevel@tonic-gate 		 *    former master then triggers a debugger entry, and attempts
3787c478bd9Sstevel@tonic-gate 		 *    to stop the slaves for this entry before they've even
3797c478bd9Sstevel@tonic-gate 		 *    resumed from the last one.  When the slaves arrive here,
3807c478bd9Sstevel@tonic-gate 		 *    they'll have re-disabled interrupts, and will thus ignore
3817c478bd9Sstevel@tonic-gate 		 *    cross-calls until they finish resuming.
3827c478bd9Sstevel@tonic-gate 		 *
3837c478bd9Sstevel@tonic-gate 		 * 2. At the time of this writing, there exists a SPARC bug that
3847c478bd9Sstevel@tonic-gate 		 *    causes an apparently unsolicited interrupt vector trap
3857c478bd9Sstevel@tonic-gate 		 *    from OBP to one of the slaves.  This wouldn't normally be
3867c478bd9Sstevel@tonic-gate 		 *    a problem but for the fact that the cross-called CPU
3877c478bd9Sstevel@tonic-gate 		 *    encounters some sort of failure while in OBP.  OBP
3887c478bd9Sstevel@tonic-gate 		 *    recovers by executing the debugger-hook word, which sends
3897c478bd9Sstevel@tonic-gate 		 *    the slave back into the debugger, triggering a debugger
3907c478bd9Sstevel@tonic-gate 		 *    fault.  This problem seems to only happen during resume,
3917c478bd9Sstevel@tonic-gate 		 *    the result being that all CPUs save for the cross-called
3927c478bd9Sstevel@tonic-gate 		 *    one make it back into the world, while the cross-called
3937c478bd9Sstevel@tonic-gate 		 *    one is stuck at the debugger fault prompt.  Leave the
3947c478bd9Sstevel@tonic-gate 		 *    world in that state too long, and you'll get a mondo
3957c478bd9Sstevel@tonic-gate 		 *    timeout panic.  If we hold everyone here, we can give the
3967c478bd9Sstevel@tonic-gate 		 *    the user a chance to trigger a panic for further analysis.
3977c478bd9Sstevel@tonic-gate 		 *    To trigger the bug, "pool_unlock:b :c" and "while : ; do
3987c478bd9Sstevel@tonic-gate 		 *    psrset -p ; done".
3997c478bd9Sstevel@tonic-gate 		 *
4007c478bd9Sstevel@tonic-gate 		 * When the second item is fixed, the barrier can move into
4017c478bd9Sstevel@tonic-gate 		 * kaif_select_master(), immediately prior to the setting of
4027c478bd9Sstevel@tonic-gate 		 * kaif_master_cpuid.
4037c478bd9Sstevel@tonic-gate 		 */
4047c478bd9Sstevel@tonic-gate 		while (kaif_looping != 0)
4057c478bd9Sstevel@tonic-gate 			continue;
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	return (cmd);
4097c478bd9Sstevel@tonic-gate }
410a35baf17Shyw 
411a35baf17Shyw 
412a35baf17Shyw #if defined(__sparc)
413a35baf17Shyw 
414a35baf17Shyw static int slave_loop_barrier_failures = 0;	/* for debug */
415a35baf17Shyw 
416a35baf17Shyw /*
417a35baf17Shyw  * There exist a race condition observed by some
418a35baf17Shyw  * platforms where the kmdb master cpu exits to OBP via
419a35baf17Shyw  * prom_enter_mon (e.g. "$q" command) and then later re-enter
420a35baf17Shyw  * kmdb (typing "go") while the slaves are still proceeding
421a35baf17Shyw  * from the OBP idle-loop back to the kmdb slave loop. The
422a35baf17Shyw  * problem arises when the master cpu now back in kmdb proceed
423a35baf17Shyw  * to re-enter OBP (e.g. doing a prom_read() from the kmdb main
424a35baf17Shyw  * loop) while the slaves are still trying to get out of (the
425a35baf17Shyw  * previous trip in) OBP into the safety of the kmdb slave loop.
426a35baf17Shyw  * This routine forces the slaves to explicitly acknowledge
427a35baf17Shyw  * that they are back in the slave loop. The master cpu can
428a35baf17Shyw  * call this routine to ensure that all slave cpus are back
429a35baf17Shyw  * in the slave loop before proceeding.
430a35baf17Shyw  */
431a35baf17Shyw void
kaif_slave_loop_barrier(void)432a35baf17Shyw kaif_slave_loop_barrier(void)
433a35baf17Shyw {
434a35baf17Shyw 	extern void kdi_usecwait(clock_t);
435a35baf17Shyw 	int i;
436a35baf17Shyw 	int not_acked;
437a35baf17Shyw 	int timeout_count = 0;
438a35baf17Shyw 
439ae115bc7Smrj 	kaif_start_slaves(KAIF_SLAVE_CMD_ACK);
440a35baf17Shyw 
441a35baf17Shyw 	/*
442a35baf17Shyw 	 * Wait for slave cpus to explicitly acknowledge
443a35baf17Shyw 	 * that they are spinning in the slave loop.
444a35baf17Shyw 	 */
445a35baf17Shyw 	do {
446a35baf17Shyw 		not_acked = 0;
447a35baf17Shyw 		for (i = 0; i < kaif_ncpusave; i++) {
448a35baf17Shyw 			kaif_cpusave_t *save = &kaif_cpusave[i];
449a35baf17Shyw 
450a35baf17Shyw 			if (save->krs_cpu_state ==
451a35baf17Shyw 			    KAIF_CPU_STATE_SLAVE &&
452a35baf17Shyw 			    !save->krs_cpu_acked) {
453a35baf17Shyw 				not_acked++;
454a35baf17Shyw 				break;
455a35baf17Shyw 			}
456a35baf17Shyw 		}
457a35baf17Shyw 
458a35baf17Shyw 		if (not_acked == 0)
459a35baf17Shyw 			break;
460a35baf17Shyw 
461a35baf17Shyw 		/*
462a35baf17Shyw 		 * Play it safe and do a timeout delay.
463a35baf17Shyw 		 * We will do at most kaif_ncpusave delays before
464a35baf17Shyw 		 * bailing out of this barrier.
465a35baf17Shyw 		 */
466a35baf17Shyw 		kdi_usecwait(200);
467a35baf17Shyw 
468a35baf17Shyw 	} while (++timeout_count < kaif_ncpusave);
469a35baf17Shyw 
470a35baf17Shyw 	if (not_acked > 0)
471a35baf17Shyw 		/*
472a35baf17Shyw 		 * we cannot establish a barrier with all
473a35baf17Shyw 		 * the slave cpus coming back from OBP
474a35baf17Shyw 		 * Record this fact for future debugging
475a35baf17Shyw 		 */
476a35baf17Shyw 		slave_loop_barrier_failures++;
477a35baf17Shyw 
478a35baf17Shyw 	kaif_slave_cmd = KAIF_SLAVE_CMD_SPIN;
479a35baf17Shyw }
480a35baf17Shyw #endif
481