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