xref: /titanic_51/usr/src/uts/sun4u/serengeti/io/sbdp_cpu.c (revision 45e662eb8429b38c18931ebeed30f2e5287ae51b)
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 static void	sbdp_cpu_shutdown_self(void);
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 	pnode_t		nodeid;
364 	sbdp_cpu_sram_map_t	map;
365 	static fn_t	f = "sbdp_cpu_poweroff";
366 
367 	SBDP_DBG_FUNC("%s\n", f);
368 
369 	ASSERT(MUTEX_HELD(&cpu_lock));
370 
371 	/*
372 	 * Capture all CPUs (except for detaching proc) to prevent
373 	 * crosscalls to the detaching proc until it has cleared its
374 	 * bit in cpu_ready_set.
375 	 */
376 	cpuid = cp->cpu_id;
377 
378 	nodeid = cpunodes[cpuid].nodeid;
379 	ASSERT(nodeid != (pnode_t)0);
380 
381 	*sbdp_valp = 0ull;
382 	/*
383 	 * Do the cpu sram mapping now.  This avoids problems with
384 	 * mutexes and high PILS
385 	 */
386 	if (SBDP_INJECT_ERROR(f, 0) ||
387 	    cpusram_map(&map.vaddr, &map.npages) != DDI_SUCCESS) {
388 		return (EBUSY);
389 	}
390 
391 	map.pa = &bbsram_pa;
392 	map.size = &bbsram_size;
393 
394 	/*
395 	 * Do a cross call to the cpu so it obtains the base address
396 	 */
397 	xc_one(cpuid, sbdp_get_cpu_sram_addr, (uint64_t)&map,
398 	    (uint64_t)NULL);
399 
400 	cpusram_unmap(&map.vaddr, map.npages);
401 
402 	if (SBDP_INJECT_ERROR(f, 1) || bbsram_size == 0) {
403 		cmn_err(CE_WARN, "cpu%d: Key \"%s\" missing from CPU SRAM TOC",
404 		    cpuid, cpyren_key);
405 		return (EBUSY);
406 	}
407 
408 	if ((bbsram_pa & MMU_PAGEOFFSET) != 0) {
409 		cmn_err(CE_WARN, "cpu%d: CPU SRAM key \"%s\" not page aligned, "
410 		    "offset = 0x%lx", cpuid, cpyren_key,
411 		    (bbsram_pa - (uint64_t)SBDP_CPU_SRAM_ADDR));
412 		return (EBUSY);
413 	}
414 
415 	if (bbsram_size < MMU_PAGESIZE) {
416 		cmn_err(CE_WARN, "cpu%d: CPU SRAM key \"%s\" too small, "
417 		    "size = 0x%x", cpuid, cpyren_key, bbsram_size);
418 		return (EBUSY);
419 	}
420 
421 	/*
422 	 * Capture all CPUs (except for detaching proc) to prevent
423 	 * crosscalls to the detaching proc until it has cleared its
424 	 * bit in cpu_ready_set.
425 	 *
426 	 * The CPU's remain paused and the prom_mutex is known to be free.
427 	 * This prevents the x-trap victim from blocking when doing prom
428 	 * IEEE-1275 calls at a high PIL level.
429 	 */
430 
431 	promsafe_pause_cpus();
432 
433 	/*
434 	 * Quiesce interrupts on the target CPU. We do this by setting
435 	 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to
436 	 * prevent it from receiving cross calls and cross traps.
437 	 * This prevents the processor from receiving any new soft interrupts.
438 	 */
439 
440 	mp_cpu_quiesce(cp);
441 
442 	/* tell the prom the cpu is going away */
443 	if (SBDP_INJECT_ERROR(f, 2) || prom_serengeti_cpu_off(nodeid) != 0)
444 		return (EBUSY);
445 
446 	/*
447 	 * An sir instruction is issued at the end of the shutdown
448 	 * routine to make the CPU go through POST and re-enter OBP.
449 	 */
450 	xt_one_unchecked(cp->cpu_id, (xcfunc_t *)idle_stop_xcall,
451 	    (uint64_t)sbdp_cpu_shutdown_self, 0);
452 
453 	*sbdp_valp = 3ull;
454 
455 	start_cpus();
456 
457 	/*
458 	 * Wait until we reach the OBP idle loop or time out.
459 	 * prom_serengeti_wakeupcpu waits for up to 60 seconds for the
460 	 * CPU to reach OBP idle loop.
461 	 */
462 	if (SBDP_INJECT_ERROR(f, 3) ||
463 	    prom_serengeti_wakeupcpu(nodeid) != 0) {
464 
465 		/*
466 		 * If it fails here, we still consider the unconfigure
467 		 * operation as successful.
468 		 */
469 		cmn_err(CE_WARN, "cpu%d: CPU failed to enter OBP idle loop.\n",
470 		    cpuid);
471 	}
472 
473 	ASSERT(!(CPU_IN_SET(cpu_ready_set, cpuid)));
474 
475 	bbsram_pa = 0;
476 	bbsram_size = 0;
477 
478 	return (0);
479 }
480 
481 processorid_t
482 sbdp_get_cpuid(sbdp_handle_t *hp, dev_info_t *dip)
483 {
484 	int		cpuid;
485 	char		type[OBP_MAXPROPNAME];
486 	pnode_t		nodeid;
487 	sbd_error_t	*sep;
488 	static fn_t	f = "sbdp_get_cpuid";
489 
490 	SBDP_DBG_FUNC("%s\n", f);
491 
492 	nodeid = ddi_get_nodeid(dip);
493 	if (sbdp_is_node_bad(nodeid))
494 		return (-1);
495 
496 	sep = hp->h_err;
497 
498 	if (prom_getproplen(nodeid, "device_type") < OBP_MAXPROPNAME)
499 		(void) prom_getprop(nodeid, "device_type", (caddr_t)type);
500 	else {
501 		sbdp_set_err(sep, ESGT_NO_DEV_TYPE, NULL);
502 		return (-1);
503 	}
504 
505 	if (strcmp(type, "cpu") != 0) {
506 		sbdp_set_err(sep, ESGT_NOT_CPUTYPE, NULL);
507 		return (-1);
508 	}
509 
510 	/*
511 	 * Check to see if property "cpuid" exists first.
512 	 * If not, check for "portid".
513 	 */
514 	if (prom_getprop(nodeid, "cpuid", (caddr_t)&cpuid) == -1)
515 		if (prom_getprop(nodeid, "portid", (caddr_t)&cpuid) == -1) {
516 
517 			return (-1);
518 	}
519 
520 	return ((processorid_t)cpuid & SG_CPU_ID_MASK);
521 }
522 
523 int
524 sbdp_cpu_get_impl(sbdp_handle_t *hp, dev_info_t *dip)
525 {
526 	int		impl;
527 	char		type[OBP_MAXPROPNAME];
528 	pnode_t		nodeid;
529 	sbd_error_t	*sep;
530 	static fn_t	f = "sbdp_cpu_get_impl";
531 
532 	SBDP_DBG_FUNC("%s\n", f);
533 
534 	nodeid = ddi_get_nodeid(dip);
535 	if (sbdp_is_node_bad(nodeid))
536 		return (-1);
537 
538 	sep = hp->h_err;
539 
540 	if (prom_getproplen(nodeid, "device_type") < OBP_MAXPROPNAME)
541 		(void) prom_getprop(nodeid, "device_type", (caddr_t)type);
542 	else {
543 		sbdp_set_err(sep, ESGT_NO_DEV_TYPE, NULL);
544 		return (-1);
545 	}
546 
547 	if (strcmp(type, "cpu") != 0) {
548 		sbdp_set_err(sep, ESGT_NOT_CPUTYPE, NULL);
549 		return (-1);
550 	}
551 
552 	/*
553 	 * Get the implementation# property.
554 	 */
555 	if (prom_getprop(nodeid, "implementation#", (caddr_t)&impl) == -1)
556 		return (-1);
557 
558 	return (impl);
559 }
560 
561 struct sbdp_prom_get_node_args {
562 	pnode_t node;		/* current node */
563 	processorid_t portid;	/* portid we are looking for */
564 	pnode_t result_node;	/* node found with the above portid */
565 };
566 
567 pnode_t
568 sbdp_find_nearby_cpu_by_portid(pnode_t nodeid, processorid_t portid)
569 {
570 	struct sbdp_prom_get_node_args arg;
571 	static fn_t	f = "sbdp_find_nearby_cpu_by_portid";
572 
573 	SBDP_DBG_FUNC("%s\n", f);
574 
575 	arg.node = nodeid;
576 	arg.portid = portid;
577 	(void) prom_tree_access(sbdp_prom_get_cpu, &arg, NULL);
578 
579 	return (arg.result_node);
580 }
581 
582 /*ARGSUSED*/
583 static int
584 sbdp_prom_get_cpu(void *arg, int changed)
585 {
586 	int	portid;
587 	pnode_t	parent, cur_node;
588 	struct sbdp_prom_get_node_args *argp = arg;
589 	static fn_t	f = "sbdp_prom_get_cpu";
590 
591 	SBDP_DBG_FUNC("%s\n", f);
592 
593 	parent = prom_parentnode(argp->node);
594 
595 	for (cur_node = prom_childnode(parent); cur_node != OBP_NONODE;
596 	    cur_node = prom_nextnode(cur_node)) {
597 
598 		if (prom_getprop(cur_node, OBP_PORTID, (caddr_t)&portid) < 0)
599 			continue;
600 
601 		if ((portid == argp->portid) && (cur_node != argp->node))
602 			break;
603 	}
604 
605 	argp->result_node = cur_node;
606 
607 	return (0);
608 }
609 
610 
611 /*
612  * A detaching CPU is xcalled with an xtrap to sbdp_cpu_stop_self() after
613  * it has been offlined. The function of this routine is to get the cpu
614  * spinning in a safe place. The requirement is that the system will not
615  * reference anything on the detaching board (memory and i/o is detached
616  * elsewhere) and that the CPU not reference anything on any other board
617  * in the system.  This isolation is required during and after the writes
618  * to the domain masks to remove the board from the domain.
619  *
620  * To accomplish this isolation the following is done:
621  *	0) Map the CPUSRAM to obtain the correct address in SRAM
622  *      1) Create a locked mapping to a location in CPU SRAM where
623  *      the cpu will execute.
624  *      2) Copy the target function (sbdp_shutdown_asm) in which
625  *      the cpu will execute into CPU SRAM.
626  *      3) Jump into function with CPU SRAM.
627  *      Function will:
628  *      3.1) Flush its Ecache (displacement).
629  *      3.2) Flush its Dcache with HW mechanism.
630  *      3.3) Flush its Icache with HW mechanism.
631  *      3.4) Flush all valid and _unlocked_ D-TLB entries.
632  *      3.5) Flush all valid and _unlocked_ I-TLB entries.
633  *      4) Jump into a tight loop.
634  */
635 
636 static void
637 sbdp_cpu_stop_self(uint64_t pa)
638 {
639 	cpu_t		*cp = CPU;
640 	int		cpuid = cp->cpu_id;
641 	tte_t		tte;
642 	volatile uint_t	*src, *dst;
643 	uint_t		funclen;
644 	sbdp_shutdown_t	sht;
645 	uint_t		bbsram_pfn;
646 	uint64_t	bbsram_addr;
647 	void		(*bbsram_func)(sbdp_shutdown_t *);
648 	extern void	sbdp_shutdown_asm(sbdp_shutdown_t *);
649 	extern void	sbdp_shutdown_asm_end(void);
650 
651 	funclen = (uint_t)sbdp_shutdown_asm_end - (uint_t)sbdp_shutdown_asm;
652 	ASSERT(funclen <= MMU_PAGESIZE);
653 	ASSERT(bbsram_pa != 0);
654 	ASSERT((bbsram_pa & MMU_PAGEOFFSET) == 0);
655 	ASSERT(bbsram_size >= MMU_PAGESIZE);
656 
657 	stdphys(pa, 3);
658 	bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT);
659 
660 	bbsram_addr = (uint64_t)sbdp_shutdown_va;
661 	sht.estack = bbsram_addr + MMU_PAGESIZE;
662 	sht.flushaddr = ecache_flushaddr;
663 
664 	tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) |
665 	    TTE_PFN_INTHI(bbsram_pfn);
666 	tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) |
667 	    TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT;
668 	sfmmu_dtlb_ld_kva(sbdp_shutdown_va, &tte); /* load dtlb */
669 	sfmmu_itlb_ld_kva(sbdp_shutdown_va, &tte); /* load itlb */
670 
671 	for (src = (uint_t *)sbdp_shutdown_asm, dst = (uint_t *)bbsram_addr;
672 	    src < (uint_t *)sbdp_shutdown_asm_end; src++, dst++)
673 	*dst = *src;
674 
675 	bbsram_func = (void (*)())bbsram_addr;
676 	sht.size = (uint32_t)cpunodes[cpuid].ecache_size << 1;
677 	sht.linesize = (uint32_t)cpunodes[cpuid].ecache_linesize;
678 	sht.physaddr = pa;
679 
680 	/*
681 	 * Signal to sbdp_cpu_poweroff() that we're just
682 	 * about done.
683 	 */
684 	cp->cpu_m.in_prom = 1;
685 
686 	stdphys(pa, 4);
687 	(*bbsram_func)(&sht);
688 }
689 
690 /* ARGSUSED */
691 void
692 sbdp_get_cpu_sram_addr(uint64_t arg1, uint64_t arg2)
693 {
694 	uint64_t	*pap;
695 	uint_t		*sizep;
696 	struct iosram_toc *tocp;
697 	uint_t		offset;
698 	uint_t		size;
699 	sbdp_cpu_sram_map_t *map;
700 	int		i;
701 	fn_t		f = "sbdp_get_cpu_sram_addr";
702 
703 	SBDP_DBG_FUNC("%s\n", f);
704 
705 	map = (sbdp_cpu_sram_map_t *)arg1;
706 	tocp = (struct iosram_toc *)map->vaddr;
707 	pap = map->pa;
708 	sizep = map->size;
709 
710 	for (i = 0; i < tocp->iosram_tagno; i++) {
711 		if (strcmp(tocp->iosram_keys[i].key, cpyren_key) == 0)
712 			break;
713 	}
714 	if (i == tocp->iosram_tagno) {
715 		*pap = 0;
716 		*sizep = 0;
717 		return;
718 	}
719 	offset = tocp->iosram_keys[i].offset;
720 	size = tocp->iosram_keys[i].size;
721 
722 	/*
723 	 * The address we want is the begining of cpusram + offset
724 	 */
725 	*pap = SBDP_CPU_SRAM_ADDR + offset;
726 
727 	*sizep = size;
728 }
729 
730 static int
731 cpusram_map(caddr_t *vaddrp, pgcnt_t *npp)
732 {
733 	uint_t		pgoffset;
734 	pgcnt_t		npages;
735 	pfn_t		pfn;
736 	uint64_t	base;
737 	caddr_t		kaddr;
738 	uint_t		mapping_attr;
739 
740 	base = (uint64_t)SBDP_CPU_SRAM_ADDR & (~MMU_PAGEOFFSET);
741 	pfn = mmu_btop(base);
742 
743 	/*
744 	 * Do a quick sanity check to make sure we are in I/O space.
745 	 */
746 	if (pf_is_memory(pfn))
747 		return (DDI_FAILURE);
748 
749 	pgoffset = (ulong_t)SBDP_CPU_SRAM_ADDR & MMU_PAGEOFFSET;
750 	npages = mmu_btopr(SBDP_CPU_SRAM_SIZE + pgoffset);
751 
752 	kaddr = vmem_alloc(heap_arena, ptob(npages), VM_NOSLEEP);
753 	if (kaddr == NULL)
754 		return (DDI_ME_NORESOURCES);
755 
756 	mapping_attr = PROT_READ;
757 	/*
758 	 * Now map in the pages we've allocated...
759 	 */
760 	hat_devload(kas.a_hat, kaddr, ptob(npages), pfn, mapping_attr,
761 	    HAT_LOAD_LOCK);
762 
763 	*vaddrp = kaddr + pgoffset;
764 	*npp = npages;
765 
766 	return (DDI_SUCCESS);
767 }
768 
769 static void
770 cpusram_unmap(caddr_t *vaddrp, pgcnt_t npages)
771 {
772 	uint_t  pgoffset;
773 	caddr_t base;
774 	caddr_t addr = *vaddrp;
775 
776 
777 	pgoffset = (ulong_t)SBDP_CPU_SRAM_ADDR & MMU_PAGEOFFSET;
778 	base = addr - pgoffset;
779 	hat_unload(kas.a_hat, base, ptob(npages), HAT_UNLOAD_UNLOCK);
780 	vmem_free(heap_arena, base, ptob(npages));
781 
782 	*vaddrp = 0;
783 }
784 
785 
786 static void
787 sbdp_cpu_shutdown_self(void)
788 {
789 	cpu_t		*cp = CPU;
790 	int		cpuid = cp->cpu_id;
791 	extern void	flush_windows(void);
792 	uint64_t	pa = va_to_pa((void *)sbdp_valp);
793 
794 	stdphys(pa, 8);
795 	flush_windows();
796 
797 	(void) spl8();
798 
799 	stdphys(pa, 6);
800 
801 	ASSERT(cp->cpu_intr_actv == 0);
802 	ASSERT(cp->cpu_thread == cp->cpu_idle_thread ||
803 	    cp->cpu_thread == cp->cpu_startup_thread);
804 
805 	cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
806 
807 	CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid);
808 
809 	stdphys(pa, 7);
810 	sbdp_cpu_stop_self(pa);
811 
812 	cmn_err(CE_PANIC, "sbdp_cpu_shutdown_self: CPU %d FAILED TO SHUTDOWN",
813 	    cpuid);
814 }
815 
816 typedef struct {
817 	int	node;
818 	int	board;
819 	int 	non_panther_cpus;
820 } sbdp_node_walk_t;
821 
822 static int
823 sbdp_find_non_panther_cpus(dev_info_t *dip, void *node_args)
824 {
825 	int	impl, cpuid, portid;
826 	int	buflen;
827 	char	buf[OBP_MAXPROPNAME];
828 	sbdp_node_walk_t *args = (sbdp_node_walk_t *)node_args;
829 
830 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
831 	    DDI_PROP_DONTPASS, OBP_DEVICETYPE, (caddr_t)buf,
832 	    &buflen) != DDI_PROP_SUCCESS) {
833 		return (DDI_WALK_CONTINUE);
834 	}
835 
836 	if (strcmp(buf, "cpu") != 0) {
837 		return (DDI_WALK_CONTINUE);
838 	}
839 
840 	if ((impl = ddi_getprop(DDI_DEV_T_ANY, dip,
841 	    DDI_PROP_DONTPASS, "implementation#", -1)) == -1) {
842 		return (DDI_WALK_CONTINUE);
843 	}
844 
845 	if ((cpuid = ddi_getprop(DDI_DEV_T_ANY, dip,
846 	    DDI_PROP_DONTPASS, "cpuid", -1)) == -1) {
847 		return (DDI_WALK_CONTINUE);
848 	}
849 
850 	portid = SG_CPUID_TO_PORTID(cpuid);
851 
852 	/* filter out nodes not on this board */
853 	if (SG_PORTID_TO_BOARD_NUM(portid) != args->board ||
854 	    SG_PORTID_TO_NODEID(portid) != args->node) {
855 		return (DDI_WALK_PRUNECHILD);
856 	}
857 
858 	switch (impl) {
859 	case CHEETAH_IMPL:
860 	case CHEETAH_PLUS_IMPL:
861 	case JAGUAR_IMPL:
862 		args->non_panther_cpus++;
863 		break;
864 	case PANTHER_IMPL:
865 		break;
866 	default:
867 		ASSERT(0);
868 		args->non_panther_cpus++;
869 		break;
870 	}
871 
872 	SBDP_DBG_CPU("cpuid=0x%x, portid=0x%x, impl=0x%x, device_type=%s",
873 	    cpuid, portid, impl, buf);
874 
875 	return (DDI_WALK_CONTINUE);
876 }
877 
878 int
879 sbdp_board_non_panther_cpus(int node, int board)
880 {
881 	sbdp_node_walk_t arg = {0};
882 
883 	arg.node = node;
884 	arg.board = board;
885 
886 	/*
887 	 * Root node doesn't have to be held.
888 	 */
889 	ddi_walk_devs(ddi_root_node(), sbdp_find_non_panther_cpus,
890 	    (void *)&arg);
891 
892 	return (arg.non_panther_cpus);
893 }
894