xref: /titanic_44/usr/src/uts/sun4u/serengeti/io/sbdp_cpu.c (revision dfc7be02c381b7c61998fdb9ecbf069933d62381)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * CPU management for serengeti DR
29  *
30  * There are three states a CPU can be in:
31  *
32  *	disconnected:		In reset
33  *	connect,unconfigured:	Idling in OBP's idle loop
34  *	configured:		Running Solaris
35  *
36  * State transitions:
37  *
38  *                connect              configure
39  *              ------------>         ------------>
40  * disconnected              connected             configured
41  *                          unconfigured
42  *              <-----------         <-------------
43  *                disconnect           unconfigure
44  *
45  * Firmware involvements
46  *
47  *              start_cpu(SC)
48  *      prom_serengeti_wakeupcpu(OBP)
49  *              ------------>         ------------------------->
50  * disconnected              connected                         configured
51  *                          unconfigured
52  *              <-----------          <-------------------------
53  *      prom_serengeti_cpu_off(OBP)  prom_serengeti_cpu_off(OBP)
54  *               stop_cpu(SC)        prom_serengeti_wakeupcpu(OBP)
55  *
56  * SIR (Software Initiated Reset) is used to unconfigure a CPU.
57  * After the CPU has completed flushing the caches, it issues an
58  * sir instruction to put itself through POST.  POST detects that
59  * it is an SIR, and re-enters OBP as a slave.  When the operation
60  * completes successfully, the CPU will be idling in OBP.
61  */
62 
63 #include <sys/obpdefs.h>
64 #include <sys/types.h>
65 #include <sys/cmn_err.h>
66 #include <sys/cpuvar.h>
67 #include <sys/membar.h>
68 #include <sys/x_call.h>
69 #include <sys/machsystm.h>
70 #include <sys/cpu_sgnblk_defs.h>
71 #include <sys/pte.h>
72 #include <vm/hat_sfmmu.h>
73 #include <sys/promif.h>
74 #include <sys/note.h>
75 #include <sys/vmsystm.h>
76 #include <vm/seg_kmem.h>
77 
78 #include <sys/sbd_ioctl.h>
79 #include <sys/sbd.h>
80 #include <sys/sbdp_priv.h>
81 #include <sys/sbdp_mem.h>
82 #include <sys/sbdp_error.h>
83 #include <sys/sgsbbc_iosram.h>
84 #include <sys/prom_plat.h>
85 #include <sys/cheetahregs.h>
86 
87 uint64_t	*sbdp_valp;
88 extern uint64_t	va_to_pa(void *);
89 static int	sbdp_cpu_ntries = 50000;
90 static int	sbdp_cpu_delay = 100;
91 void		sbdp_get_cpu_sram_addr(uint64_t, uint64_t);
92 static int	cpusram_map(caddr_t *, pgcnt_t *);
93 static void	cpusram_unmap(caddr_t *, pgcnt_t);
94 extern int	prom_serengeti_wakeupcpu(pnode_t);
95 extern int	prom_serengeti_cpu_off(pnode_t);
96 extern sbdp_wnode_t *sbdp_get_wnodep(int);
97 extern caddr_t	sbdp_shutdown_va;
98 static int	sbdp_prom_get_cpu(void *arg, int changed);
99 
100 
101 int
102 sbdp_disconnect_cpu(sbdp_handle_t *hp, dev_info_t *dip, processorid_t cpuid)
103 {
104 	pnode_t		nodeid;
105 	int		bd, wnode;
106 	sbdp_wnode_t	*wnodep;
107 	sbdp_bd_t	*bdp = NULL;
108 	int		rv = 0;
109 	processorid_t	cpu = cpuid;
110 	processorid_t	portid;
111 	static fn_t	f = "sbdp_disconnect_cpu";
112 
113 	SBDP_DBG_FUNC("%s\n", f);
114 
115 	nodeid = ddi_get_nodeid(dip);
116 
117 	/*
118 	 * Get board number and node number
119 	 * The check for determining if nodeid is valid is done inside
120 	 * sbdp_get_bd_and_wnode_num.
121 	 */
122 	if (SBDP_INJECT_ERROR(f, 0) ||
123 	    sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) != 0) {
124 
125 		rv = -1;
126 		goto out;
127 	}
128 
129 	/*
130 	 * Grab the lock to prevent status threads from accessing
131 	 * registers on the CPU when it is being put into reset.
132 	 */
133 	wnodep = sbdp_get_wnodep(wnode);
134 	bdp = &wnodep->bds[bd];
135 	ASSERT(bdp);
136 	mutex_enter(&bdp->bd_mutex);
137 
138 	/*
139 	 * Mark the CPU in reset.  This should be done before calling
140 	 * the SC because we won't know at which stage it failed if
141 	 * the SC call returns failure.
142 	 */
143 	sbdp_cpu_in_reset(wnode, bd, SG_CPUID_TO_CPU_UNIT(cpuid), 1);
144 
145 	/*
146 	 * Ask OBP to mark the CPU as in POST
147 	 */
148 	if (SBDP_INJECT_ERROR(f, 1) || prom_serengeti_cpu_off(nodeid) != 0) {
149 
150 		rv = -1;
151 		goto out;
152 	}
153 
154 	/*
155 	 * Ask the SC to put the CPU into reset. If the first
156 	 * core is not present, the stop CPU interface needs
157 	 * to be called with the portid rather than the cpuid.
158 	 */
159 	portid = SG_CPUID_TO_PORTID(cpuid);
160 	if (!SBDP_IS_CPU_PRESENT(bdp, SG_CPUID_TO_CPU_UNIT(portid))) {
161 		cpu = portid;
162 	}
163 
164 	if (SBDP_INJECT_ERROR(f, 2) || sbdp_stop_cpu(cpu) != 0) {
165 
166 		rv = -1;
167 		goto out;
168 	}
169 
170 out:
171 	if (bdp != NULL) {
172 		mutex_exit(&bdp->bd_mutex);
173 	}
174 
175 	if (rv != 0) {
176 		sbdp_set_err(hp->h_err, ESGT_STOPCPU, NULL);
177 	}
178 
179 	return (rv);
180 }
181 
182 int
183 sbdp_connect_cpu(sbdp_handle_t *hp, dev_info_t *dip, processorid_t cpuid)
184 {
185 	pnode_t		nodeid;
186 	sbd_error_t	*sep;
187 	int		i;
188 	int		bd, wnode;
189 	int		rv = 0;
190 	static fn_t	f = "sbdp_connect_cpu";
191 
192 	SBDP_DBG_FUNC("%s\n", f);
193 
194 	sep = hp->h_err;
195 
196 	nodeid = ddi_get_nodeid(dip);
197 
198 	/*
199 	 * The check for determining if nodeid is valid is done inside
200 	 * sbdp_get_bd_and_wnode_num.
201 	 */
202 	if (SBDP_INJECT_ERROR(f, 0) ||
203 	    sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) != 0) {
204 
205 		rv = -1;
206 		goto out;
207 	}
208 
209 	/*
210 	 * Ask the SC to bring the CPU out of reset.
211 	 * At this point, the sb_dev_present bit is not set for the CPU.
212 	 * From sbd point of view the CPU is not present yet.  No
213 	 * status threads will try to read registers off the CPU.
214 	 * Since we are already holding sb_mutex, it is not necessary
215 	 * to grab the board mutex when checking and setting the
216 	 * cpus_in_reset bit.
217 	 */
218 	if (sbdp_is_cpu_in_reset(wnode, bd, SG_CPUID_TO_CPU_UNIT(cpuid))) {
219 
220 		sbdp_wnode_t	*wnodep;
221 		sbdp_bd_t	*bdp = NULL;
222 		processorid_t	cpu = cpuid;
223 		processorid_t	portid;
224 
225 		wnodep = sbdp_get_wnodep(wnode);
226 		bdp = &wnodep->bds[bd];
227 		ASSERT(bdp);
228 
229 		/*
230 		 * If the first core is not present, the start CPU
231 		 * interface needs to be called with the portid rather
232 		 * than the cpuid.
233 		 */
234 		portid = SG_CPUID_TO_PORTID(cpuid);
235 		if (!SBDP_IS_CPU_PRESENT(bdp, SG_CPUID_TO_CPU_UNIT(portid))) {
236 			cpu = portid;
237 		}
238 
239 		if (SBDP_INJECT_ERROR(f, 1) || sbdp_start_cpu(cpu) != 0) {
240 
241 			rv = -1;
242 			goto out;
243 		}
244 
245 		if (SBDP_INJECT_ERROR(f, 2) ||
246 		    prom_serengeti_wakeupcpu(nodeid) != 0) {
247 
248 			rv = -1;
249 			goto out;
250 		}
251 	}
252 
253 	/*
254 	 * Mark the CPU out of reset.
255 	 */
256 	sbdp_cpu_in_reset(wnode, bd, SG_CPUID_TO_CPU_UNIT(cpuid), 0);
257 
258 	/*
259 	 * Refresh the bd info
260 	 * we need to wait until all cpus are out of reset
261 	 */
262 	for (i = 0; i < SG_MAX_CPUS_PER_BD; i++)
263 		if (sbdp_is_cpu_present(wnode, bd, i) &&
264 		    sbdp_is_cpu_in_reset(wnode, bd, i) == 1) {
265 			break;
266 		}
267 
268 	if (i == SG_MAX_CPUS_PER_BD) {
269 		/*
270 		 * All cpus are out of reset so it is safe to
271 		 * update the bd info
272 		 */
273 		sbdp_add_new_bd_info(wnode, bd);
274 	}
275 
276 out:
277 	if (rv != 0)
278 		sbdp_set_err(sep, ESGT_WAKEUPCPU, NULL);
279 
280 	return (rv);
281 }
282 
283 int
284 sbdp_cpu_poweron(struct cpu *cp)
285 {
286 	int		cpuid;
287 	int		ntries;
288 	pnode_t		nodeid;
289 	extern void	restart_other_cpu(int);
290 	static fn_t	f = "sbdp_cpu_poweron";
291 
292 	SBDP_DBG_FUNC("%s\n", f);
293 
294 	ASSERT(MUTEX_HELD(&cpu_lock));
295 
296 	ntries = sbdp_cpu_ntries;
297 	cpuid = cp->cpu_id;
298 
299 	nodeid = cpunodes[cpuid].nodeid;
300 	ASSERT(nodeid != (pnode_t)0);
301 
302 	/*
303 	 * This is a safe guard in case the CPU has taken a trap
304 	 * and idling in POST.
305 	 */
306 	if (SBDP_INJECT_ERROR(f, 0) ||
307 	    prom_serengeti_wakeupcpu(nodeid) != 0) {
308 
309 		return (EBUSY);
310 	}
311 
312 	cp->cpu_flags &= ~CPU_POWEROFF;
313 
314 	/*
315 	 * NOTE: restart_other_cpu pauses cpus during the
316 	 *	slave cpu start.  This helps to quiesce the
317 	 *	bus traffic a bit which makes the tick sync
318 	 *	routine in the prom more robust.
319 	 */
320 	SBDP_DBG_CPU("%s: COLD START for cpu (%d)\n", f, cpuid);
321 
322 	restart_other_cpu(cpuid);
323 
324 	SBDP_DBG_CPU("after restarting other cpus\n");
325 
326 	/*
327 	 * Wait for the cpu to reach its idle thread before
328 	 * we zap him with a request to blow away the mappings
329 	 * he (might) have for the sbdp_shutdown_asm code
330 	 * he may have executed on unconfigure.
331 	 */
332 	while ((cp->cpu_thread != cp->cpu_idle_thread) && (ntries > 0)) {
333 		DELAY(sbdp_cpu_delay);
334 		ntries--;
335 	}
336 
337 	SBDP_DBG_CPU("%s: waited %d out of %d loops for cpu %d\n",
338 	    f, sbdp_cpu_ntries - ntries, sbdp_cpu_ntries, cpuid);
339 
340 	return (0);
341 }
342 
343 
344 #define	SBDP_CPU_SRAM_ADDR	0x7fff0900000ull
345 #define	SBDP_CPU_SRAM_SIZE	0x20000ull
346 
347 static const char cpyren_key[] = "COPYREN";
348 
349 static uint64_t bbsram_pa;
350 static uint_t bbsram_size;
351 
352 typedef struct {
353 	caddr_t		vaddr;
354 	pgcnt_t		npages;
355 	uint64_t	*pa;
356 	uint_t		*size;
357 } sbdp_cpu_sram_map_t;
358 
359 int
360 sbdp_cpu_poweroff(struct cpu *cp)
361 {
362 	processorid_t	cpuid;
363 	static void	sbdp_cpu_shutdown_self(void);
364 	pnode_t		nodeid;
365 	sbdp_cpu_sram_map_t	map;
366 	static fn_t	f = "sbdp_cpu_poweroff";
367 
368 	SBDP_DBG_FUNC("%s\n", f);
369 
370 	ASSERT(MUTEX_HELD(&cpu_lock));
371 
372 	/*
373 	 * Capture all CPUs (except for detaching proc) to prevent
374 	 * crosscalls to the detaching proc until it has cleared its
375 	 * bit in cpu_ready_set.
376 	 */
377 	cpuid = cp->cpu_id;
378 
379 	nodeid = cpunodes[cpuid].nodeid;
380 	ASSERT(nodeid != (pnode_t)0);
381 
382 	*sbdp_valp = 0ull;
383 	/*
384 	 * Do the cpu sram mapping now.  This avoids problems with
385 	 * mutexes and high PILS
386 	 */
387 	if (SBDP_INJECT_ERROR(f, 0) ||
388 	    cpusram_map(&map.vaddr, &map.npages) != DDI_SUCCESS) {
389 		return (EBUSY);
390 	}
391 
392 	map.pa = &bbsram_pa;
393 	map.size = &bbsram_size;
394 
395 	/*
396 	 * Do a cross call to the cpu so it obtains the base address
397 	 */
398 	xc_one(cpuid, sbdp_get_cpu_sram_addr, (uint64_t)&map,
399 	    (uint64_t)NULL);
400 
401 	cpusram_unmap(&map.vaddr, map.npages);
402 
403 	if (SBDP_INJECT_ERROR(f, 1) || bbsram_size == 0) {
404 		cmn_err(CE_WARN, "cpu%d: Key \"%s\" missing from CPU SRAM TOC",
405 		    cpuid, cpyren_key);
406 		return (EBUSY);
407 	}
408 
409 	if ((bbsram_pa & MMU_PAGEOFFSET) != 0) {
410 		cmn_err(CE_WARN, "cpu%d: CPU SRAM key \"%s\" not page aligned, "
411 		    "offset = 0x%lx", cpuid, cpyren_key,
412 		    (bbsram_pa - (uint64_t)SBDP_CPU_SRAM_ADDR));
413 		return (EBUSY);
414 	}
415 
416 	if (bbsram_size < MMU_PAGESIZE) {
417 		cmn_err(CE_WARN, "cpu%d: CPU SRAM key \"%s\" too small, "
418 		    "size = 0x%x", cpuid, cpyren_key, bbsram_size);
419 		return (EBUSY);
420 	}
421 
422 	/*
423 	 * Capture all CPUs (except for detaching proc) to prevent
424 	 * crosscalls to the detaching proc until it has cleared its
425 	 * bit in cpu_ready_set.
426 	 *
427 	 * The CPU's remain paused and the prom_mutex is known to be free.
428 	 * This prevents the x-trap victim from blocking when doing prom
429 	 * IEEE-1275 calls at a high PIL level.
430 	 */
431 
432 	promsafe_pause_cpus();
433 
434 	/*
435 	 * Quiesce interrupts on the target CPU. We do this by setting
436 	 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
437 	 * prevent it from receiving cross calls and cross traps.
438 	 * This prevents the processor from receiving any new soft interrupts.
439 	 */
440 
441 	mp_cpu_quiesce(cp);
442 
443 	/* tell the prom the cpu is going away */
444 	if (SBDP_INJECT_ERROR(f, 2) || prom_serengeti_cpu_off(nodeid) != 0)
445 		return (EBUSY);
446 
447 	/*
448 	 * An sir instruction is issued at the end of the shutdown
449 	 * routine to make the CPU go through POST and re-enter OBP.
450 	 */
451 	xt_one_unchecked(cp->cpu_id, (xcfunc_t *)idle_stop_xcall,
452 	    (uint64_t)sbdp_cpu_shutdown_self, 0);
453 
454 	*sbdp_valp = 3ull;
455 
456 	start_cpus();
457 
458 	/*
459 	 * Wait until we reach the OBP idle loop or time out.
460 	 * prom_serengeti_wakeupcpu waits for up to 60 seconds for the
461 	 * CPU to reach OBP idle loop.
462 	 */
463 	if (SBDP_INJECT_ERROR(f, 3) ||
464 	    prom_serengeti_wakeupcpu(nodeid) != 0) {
465 
466 		/*
467 		 * If it fails here, we still consider the unconfigure
468 		 * operation as successful.
469 		 */
470 		cmn_err(CE_WARN, "cpu%d: CPU failed to enter OBP idle loop.\n",
471 		    cpuid);
472 	}
473 
474 	ASSERT(!(CPU_IN_SET(cpu_ready_set, cpuid)));
475 
476 	bbsram_pa = 0;
477 	bbsram_size = 0;
478 
479 	return (0);
480 }
481 
482 processorid_t
483 sbdp_get_cpuid(sbdp_handle_t *hp, dev_info_t *dip)
484 {
485 	int		cpuid;
486 	char		type[OBP_MAXPROPNAME];
487 	pnode_t		nodeid;
488 	sbd_error_t	*sep;
489 	static fn_t	f = "sbdp_get_cpuid";
490 
491 	SBDP_DBG_FUNC("%s\n", f);
492 
493 	nodeid = ddi_get_nodeid(dip);
494 	if (sbdp_is_node_bad(nodeid))
495 		return (-1);
496 
497 	sep = hp->h_err;
498 
499 	if (prom_getproplen(nodeid, "device_type") < OBP_MAXPROPNAME)
500 		(void) prom_getprop(nodeid, "device_type", (caddr_t)type);
501 	else {
502 		sbdp_set_err(sep, ESGT_NO_DEV_TYPE, NULL);
503 		return (-1);
504 	}
505 
506 	if (strcmp(type, "cpu") != 0) {
507 		sbdp_set_err(sep, ESGT_NOT_CPUTYPE, NULL);
508 		return (-1);
509 	}
510 
511 	/*
512 	 * Check to see if property "cpuid" exists first.
513 	 * If not, check for "portid".
514 	 */
515 	if (prom_getprop(nodeid, "cpuid", (caddr_t)&cpuid) == -1)
516 		if (prom_getprop(nodeid, "portid", (caddr_t)&cpuid) == -1) {
517 
518 			return (-1);
519 	}
520 
521 	return ((processorid_t)cpuid & SG_CPU_ID_MASK);
522 }
523 
524 int
525 sbdp_cpu_get_impl(sbdp_handle_t *hp, dev_info_t *dip)
526 {
527 	int		impl;
528 	char		type[OBP_MAXPROPNAME];
529 	pnode_t		nodeid;
530 	sbd_error_t	*sep;
531 	static fn_t	f = "sbdp_cpu_get_impl";
532 
533 	SBDP_DBG_FUNC("%s\n", f);
534 
535 	nodeid = ddi_get_nodeid(dip);
536 	if (sbdp_is_node_bad(nodeid))
537 		return (-1);
538 
539 	sep = hp->h_err;
540 
541 	if (prom_getproplen(nodeid, "device_type") < OBP_MAXPROPNAME)
542 		(void) prom_getprop(nodeid, "device_type", (caddr_t)type);
543 	else {
544 		sbdp_set_err(sep, ESGT_NO_DEV_TYPE, NULL);
545 		return (-1);
546 	}
547 
548 	if (strcmp(type, "cpu") != 0) {
549 		sbdp_set_err(sep, ESGT_NOT_CPUTYPE, NULL);
550 		return (-1);
551 	}
552 
553 	/*
554 	 * Get the implementation# property.
555 	 */
556 	if (prom_getprop(nodeid, "implementation#", (caddr_t)&impl) == -1)
557 		return (-1);
558 
559 	return (impl);
560 }
561 
562 struct sbdp_prom_get_node_args {
563 	pnode_t node;		/* current node */
564 	processorid_t portid;	/* portid we are looking for */
565 	pnode_t result_node;	/* node found with the above portid */
566 };
567 
568 pnode_t
569 sbdp_find_nearby_cpu_by_portid(pnode_t nodeid, processorid_t portid)
570 {
571 	struct sbdp_prom_get_node_args arg;
572 	static fn_t	f = "sbdp_find_nearby_cpu_by_portid";
573 
574 	SBDP_DBG_FUNC("%s\n", f);
575 
576 	arg.node = nodeid;
577 	arg.portid = portid;
578 	(void) prom_tree_access(sbdp_prom_get_cpu, &arg, NULL);
579 
580 	return (arg.result_node);
581 }
582 
583 /*ARGSUSED*/
584 static int
585 sbdp_prom_get_cpu(void *arg, int changed)
586 {
587 	int	portid;
588 	pnode_t	parent, cur_node;
589 	struct sbdp_prom_get_node_args *argp = arg;
590 	static fn_t	f = "sbdp_prom_get_cpu";
591 
592 	SBDP_DBG_FUNC("%s\n", f);
593 
594 	parent = prom_parentnode(argp->node);
595 
596 	for (cur_node = prom_childnode(parent); cur_node != OBP_NONODE;
597 	    cur_node = prom_nextnode(cur_node)) {
598 
599 		if (prom_getprop(cur_node, OBP_PORTID, (caddr_t)&portid) < 0)
600 			continue;
601 
602 		if ((portid == argp->portid) && (cur_node != argp->node))
603 			break;
604 	}
605 
606 	argp->result_node = cur_node;
607 
608 	return (0);
609 }
610 
611 
612 /*
613  * A detaching CPU is xcalled with an xtrap to sbdp_cpu_stop_self() after
614  * it has been offlined. The function of this routine is to get the cpu
615  * spinning in a safe place. The requirement is that the system will not
616  * reference anything on the detaching board (memory and i/o is detached
617  * elsewhere) and that the CPU not reference anything on any other board
618  * in the system.  This isolation is required during and after the writes
619  * to the domain masks to remove the board from the domain.
620  *
621  * To accomplish this isolation the following is done:
622  *	0) Map the CPUSRAM to obtain the correct address in SRAM
623  *      1) Create a locked mapping to a location in CPU SRAM where
624  *      the cpu will execute.
625  *      2) Copy the target function (sbdp_shutdown_asm) in which
626  *      the cpu will execute into CPU SRAM.
627  *      3) Jump into function with CPU SRAM.
628  *      Function will:
629  *      3.1) Flush its Ecache (displacement).
630  *      3.2) Flush its Dcache with HW mechanism.
631  *      3.3) Flush its Icache with HW mechanism.
632  *      3.4) Flush all valid and _unlocked_ D-TLB entries.
633  *      3.5) Flush all valid and _unlocked_ I-TLB entries.
634  *      4) Jump into a tight loop.
635  */
636 
637 static void
638 sbdp_cpu_stop_self(uint64_t pa)
639 {
640 	cpu_t		*cp = CPU;
641 	int		cpuid = cp->cpu_id;
642 	tte_t		tte;
643 	volatile uint_t	*src, *dst;
644 	uint_t		funclen;
645 	sbdp_shutdown_t	sht;
646 	uint_t		bbsram_pfn;
647 	uint64_t	bbsram_addr;
648 	void		(*bbsram_func)(sbdp_shutdown_t *);
649 	extern void	sbdp_shutdown_asm(sbdp_shutdown_t *);
650 	extern void	sbdp_shutdown_asm_end(void);
651 
652 	funclen = (uint_t)sbdp_shutdown_asm_end - (uint_t)sbdp_shutdown_asm;
653 	ASSERT(funclen <= MMU_PAGESIZE);
654 	ASSERT(bbsram_pa != 0);
655 	ASSERT((bbsram_pa & MMU_PAGEOFFSET) == 0);
656 	ASSERT(bbsram_size >= MMU_PAGESIZE);
657 
658 	stdphys(pa, 3);
659 	bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT);
660 
661 	bbsram_addr = (uint64_t)sbdp_shutdown_va;
662 	sht.estack = bbsram_addr + MMU_PAGESIZE;
663 	sht.flushaddr = ecache_flushaddr;
664 
665 	tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) |
666 	    TTE_PFN_INTHI(bbsram_pfn);
667 	tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) |
668 	    TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT;
669 	sfmmu_dtlb_ld_kva(sbdp_shutdown_va, &tte); /* load dtlb */
670 	sfmmu_itlb_ld_kva(sbdp_shutdown_va, &tte); /* load itlb */
671 
672 	for (src = (uint_t *)sbdp_shutdown_asm, dst = (uint_t *)bbsram_addr;
673 	    src < (uint_t *)sbdp_shutdown_asm_end; src++, dst++)
674 	*dst = *src;
675 
676 	bbsram_func = (void (*)())bbsram_addr;
677 	sht.size = (uint32_t)cpunodes[cpuid].ecache_size << 1;
678 	sht.linesize = (uint32_t)cpunodes[cpuid].ecache_linesize;
679 	sht.physaddr = pa;
680 
681 	/*
682 	 * Signal to sbdp_cpu_poweroff() that we're just
683 	 * about done.
684 	 */
685 	cp->cpu_m.in_prom = 1;
686 
687 	stdphys(pa, 4);
688 	(*bbsram_func)(&sht);
689 }
690 
691 /* ARGSUSED */
692 void
693 sbdp_get_cpu_sram_addr(uint64_t arg1, uint64_t arg2)
694 {
695 	uint64_t	*pap;
696 	uint_t		*sizep;
697 	struct iosram_toc *tocp;
698 	uint_t		offset;
699 	uint_t		size;
700 	sbdp_cpu_sram_map_t *map;
701 	int		i;
702 	fn_t		f = "sbdp_get_cpu_sram_addr";
703 
704 	SBDP_DBG_FUNC("%s\n", f);
705 
706 	map = (sbdp_cpu_sram_map_t *)arg1;
707 	tocp = (struct iosram_toc *)map->vaddr;
708 	pap = map->pa;
709 	sizep = map->size;
710 
711 	for (i = 0; i < tocp->iosram_tagno; i++) {
712 		if (strcmp(tocp->iosram_keys[i].key, cpyren_key) == 0)
713 			break;
714 	}
715 	if (i == tocp->iosram_tagno) {
716 		*pap = 0;
717 		*sizep = 0;
718 		return;
719 	}
720 	offset = tocp->iosram_keys[i].offset;
721 	size = tocp->iosram_keys[i].size;
722 
723 	/*
724 	 * The address we want is the begining of cpusram + offset
725 	 */
726 	*pap = SBDP_CPU_SRAM_ADDR + offset;
727 
728 	*sizep = size;
729 }
730 
731 static int
732 cpusram_map(caddr_t *vaddrp, pgcnt_t *npp)
733 {
734 	uint_t		pgoffset;
735 	pgcnt_t		npages;
736 	pfn_t		pfn;
737 	uint64_t	base;
738 	caddr_t		kaddr;
739 	uint_t		mapping_attr;
740 
741 	base = (uint64_t)SBDP_CPU_SRAM_ADDR & (~MMU_PAGEOFFSET);
742 	pfn = mmu_btop(base);
743 
744 	/*
745 	 * Do a quick sanity check to make sure we are in I/O space.
746 	 */
747 	if (pf_is_memory(pfn))
748 		return (DDI_FAILURE);
749 
750 	pgoffset = (ulong_t)SBDP_CPU_SRAM_ADDR & MMU_PAGEOFFSET;
751 	npages = mmu_btopr(SBDP_CPU_SRAM_SIZE + pgoffset);
752 
753 	kaddr = vmem_alloc(heap_arena, ptob(npages), VM_NOSLEEP);
754 	if (kaddr == NULL)
755 		return (DDI_ME_NORESOURCES);
756 
757 	mapping_attr = PROT_READ;
758 	/*
759 	 * Now map in the pages we've allocated...
760 	 */
761 	hat_devload(kas.a_hat, kaddr, ptob(npages), pfn, mapping_attr,
762 	    HAT_LOAD_LOCK);
763 
764 	*vaddrp = kaddr + pgoffset;
765 	*npp = npages;
766 
767 	return (DDI_SUCCESS);
768 }
769 
770 static void
771 cpusram_unmap(caddr_t *vaddrp, pgcnt_t npages)
772 {
773 	uint_t  pgoffset;
774 	caddr_t base;
775 	caddr_t addr = *vaddrp;
776 
777 
778 	pgoffset = (ulong_t)SBDP_CPU_SRAM_ADDR & MMU_PAGEOFFSET;
779 	base = addr - pgoffset;
780 	hat_unload(kas.a_hat, base, ptob(npages), HAT_UNLOAD_UNLOCK);
781 	vmem_free(heap_arena, base, ptob(npages));
782 
783 	*vaddrp = 0;
784 }
785 
786 
787 static void
788 sbdp_cpu_shutdown_self(void)
789 {
790 	cpu_t		*cp = CPU;
791 	int		cpuid = cp->cpu_id;
792 	extern void	flush_windows(void);
793 	uint64_t	pa = va_to_pa((void *)sbdp_valp);
794 
795 	stdphys(pa, 8);
796 	flush_windows();
797 
798 	(void) spl8();
799 
800 	stdphys(pa, 6);
801 
802 	ASSERT(cp->cpu_intr_actv == 0);
803 	ASSERT(cp->cpu_thread == cp->cpu_idle_thread ||
804 	    cp->cpu_thread == cp->cpu_startup_thread);
805 
806 	cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
807 
808 	CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid);
809 
810 	stdphys(pa, 7);
811 	sbdp_cpu_stop_self(pa);
812 
813 	cmn_err(CE_PANIC, "sbdp_cpu_shutdown_self: CPU %d FAILED TO SHUTDOWN",
814 	    cpuid);
815 }
816 
817 typedef struct {
818 	int	node;
819 	int	board;
820 	int 	non_panther_cpus;
821 } sbdp_node_walk_t;
822 
823 static int
824 sbdp_find_non_panther_cpus(dev_info_t *dip, void *node_args)
825 {
826 	int	impl, cpuid, portid;
827 	int	buflen;
828 	char	buf[OBP_MAXPROPNAME];
829 	sbdp_node_walk_t *args = (sbdp_node_walk_t *)node_args;
830 
831 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
832 	    DDI_PROP_DONTPASS, OBP_DEVICETYPE, (caddr_t)buf,
833 	    &buflen) != DDI_PROP_SUCCESS) {
834 		return (DDI_WALK_CONTINUE);
835 	}
836 
837 	if (strcmp(buf, "cpu") != 0) {
838 		return (DDI_WALK_CONTINUE);
839 	}
840 
841 	if ((impl = ddi_getprop(DDI_DEV_T_ANY, dip,
842 	    DDI_PROP_DONTPASS, "implementation#", -1)) == -1) {
843 		return (DDI_WALK_CONTINUE);
844 	}
845 
846 	if ((cpuid = ddi_getprop(DDI_DEV_T_ANY, dip,
847 	    DDI_PROP_DONTPASS, "cpuid", -1)) == -1) {
848 		return (DDI_WALK_CONTINUE);
849 	}
850 
851 	portid = SG_CPUID_TO_PORTID(cpuid);
852 
853 	/* filter out nodes not on this board */
854 	if (SG_PORTID_TO_BOARD_NUM(portid) != args->board ||
855 	    SG_PORTID_TO_NODEID(portid) != args->node) {
856 		return (DDI_WALK_PRUNECHILD);
857 	}
858 
859 	switch (impl) {
860 	case CHEETAH_IMPL:
861 	case CHEETAH_PLUS_IMPL:
862 	case JAGUAR_IMPL:
863 		args->non_panther_cpus++;
864 		break;
865 	case PANTHER_IMPL:
866 		break;
867 	default:
868 		ASSERT(0);
869 		args->non_panther_cpus++;
870 		break;
871 	}
872 
873 	SBDP_DBG_CPU("cpuid=0x%x, portid=0x%x, impl=0x%x, device_type=%s",
874 	    cpuid, portid, impl, buf);
875 
876 	return (DDI_WALK_CONTINUE);
877 }
878 
879 int
880 sbdp_board_non_panther_cpus(int node, int board)
881 {
882 	sbdp_node_walk_t arg = {0};
883 
884 	arg.node = node;
885 	arg.board = board;
886 
887 	/*
888 	 * Root node doesn't have to be held.
889 	 */
890 	ddi_walk_devs(ddi_root_node(), sbdp_find_non_panther_cpus,
891 	    (void *)&arg);
892 
893 	return (arg.non_panther_cpus);
894 }
895