Home | History | Annotate | Download | only in os
      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 #include <sys/sysmacros.h>
     28 #include <sys/prom_plat.h>
     29 #include <sys/prom_debug.h>
     30 #include <vm/hat_sfmmu.h>
     31 #include <vm/seg_kp.h>
     32 #include <vm/seg_kmem.h>
     33 #include <sys/machsystm.h>
     34 #include <sys/callb.h>
     35 #include <sys/cpu_module.h>
     36 #include <sys/pg.h>
     37 #include <sys/cmt.h>
     38 #include <sys/dtrace.h>
     39 #include <sys/reboot.h>
     40 #include <sys/kdi.h>
     41 #include <sys/traptrace.h>
     42 #ifdef TRAPTRACE
     43 #include <sys/bootconf.h>
     44 #endif /* TRAPTRACE */
     45 #include <sys/cpu_sgnblk_defs.h>
     46 
     47 extern int cpu_intrq_setup(struct cpu *);
     48 extern void cpu_intrq_cleanup(struct cpu *);
     49 extern void cpu_intrq_register(struct cpu *);
     50 
     51 struct cpu	*cpus;	/* pointer to other cpus; dynamically allocate */
     52 struct cpu	*cpu[NCPU];	/* pointers to all CPUs */
     53 uint64_t	cpu_pa[NCPU];	/* pointers to all CPUs in PA */
     54 cpu_core_t	cpu_core[NCPU];	/* cpu_core structures */
     55 
     56 #ifdef TRAPTRACE
     57 caddr_t	ttrace_buf;	/* kmem64 traptrace for all cpus except 0 */
     58 #endif /* TRAPTRACE */
     59 
     60 /* bit mask of cpus ready for x-calls, protected by cpu_lock */
     61 cpuset_t cpu_ready_set;
     62 
     63 /* bit mask used to communicate with cpus during bringup */
     64 static cpuset_t proxy_ready_set;
     65 
     66 static void	slave_startup(void);
     67 
     68 /*
     69  * Defined in $KARCH/os/mach_mp_startup.c
     70  */
     71 #pragma weak init_cpu_info
     72 
     73 /*
     74  * Amount of time (in milliseconds) we should wait before giving up on CPU
     75  * initialization and assuming that the CPU we're trying to wake up is dead
     76  * or out of control.
     77  */
     78 #define	CPU_WAKEUP_GRACE_MSEC 1000
     79 
     80 #ifdef	TRAPTRACE
     81 /*
     82  * This function sets traptrace buffers for all cpus
     83  * other than boot cpu.
     84  */
     85 size_t
     86 calc_traptrace_sz(void)
     87 {
     88 	return (TRAP_TSIZE * (max_ncpus - 1));
     89 }
     90 #endif	/* TRAPTRACE */
     91 
     92 
     93 /*
     94  * common slave cpu initialization code
     95  */
     96 void
     97 common_startup_init(cpu_t *cp, int cpuid)
     98 {
     99 	kthread_id_t tp;
    100 	sfmmu_t *sfmmup;
    101 	caddr_t	sp;
    102 
    103 	/*
    104 	 * Allocate and initialize the startup thread for this CPU.
    105 	 */
    106 	tp = thread_create(NULL, 0, slave_startup, NULL, 0, &p0,
    107 	    TS_STOPPED, maxclsyspri);
    108 
    109 	/*
    110 	 * Set state to TS_ONPROC since this thread will start running
    111 	 * as soon as the CPU comes online.
    112 	 *
    113 	 * All the other fields of the thread structure are setup by
    114 	 * thread_create().
    115 	 */
    116 	THREAD_ONPROC(tp, cp);
    117 	tp->t_preempt = 1;
    118 	tp->t_bound_cpu = cp;
    119 	tp->t_affinitycnt = 1;
    120 	tp->t_cpu = cp;
    121 	tp->t_disp_queue = cp->cpu_disp;
    122 
    123 	sfmmup = astosfmmu(&kas);
    124 	CPUSET_ADD(sfmmup->sfmmu_cpusran, cpuid);
    125 
    126 	/*
    127 	 * Setup thread to start in slave_startup.
    128 	 */
    129 	sp = tp->t_stk;
    130 	tp->t_pc = (uintptr_t)slave_startup - 8;
    131 	tp->t_sp = (uintptr_t)((struct rwindow *)sp - 1) - STACK_BIAS;
    132 
    133 	cp->cpu_id = cpuid;
    134 	cp->cpu_self = cp;
    135 	cp->cpu_thread = tp;
    136 	cp->cpu_lwp = NULL;
    137 	cp->cpu_dispthread = tp;
    138 	cp->cpu_dispatch_pri = DISP_PRIO(tp);
    139 	cp->cpu_startup_thread = tp;
    140 }
    141 
    142 /*
    143  * parametric flag setting functions.  these routines set the cpu
    144  * state just prior to releasing the slave cpu.
    145  */
    146 void
    147 cold_flag_set(int cpuid)
    148 {
    149 	cpu_t *cp;
    150 
    151 	ASSERT(MUTEX_HELD(&cpu_lock));
    152 
    153 	cp = cpu[cpuid];
    154 	cp->cpu_flags |= CPU_RUNNING | CPU_ENABLE | CPU_EXISTS;
    155 	cpu_add_active(cp);
    156 	/*
    157 	 * Add CPU_READY after the cpu_add_active() call
    158 	 * to avoid pausing cp.
    159 	 */
    160 	cp->cpu_flags |= CPU_READY;		/* ready */
    161 	cpu_set_state(cp);
    162 }
    163 
    164 static void
    165 warm_flag_set(int cpuid)
    166 {
    167 	cpu_t *cp;
    168 
    169 	ASSERT(MUTEX_HELD(&cpu_lock));
    170 
    171 	/*
    172 	 * warm start activates cpus into the OFFLINE state
    173 	 */
    174 	cp = cpu[cpuid];
    175 	cp->cpu_flags |= CPU_RUNNING | CPU_READY | CPU_EXISTS
    176 	    | CPU_OFFLINE | CPU_QUIESCED;
    177 	cpu_set_state(cp);
    178 }
    179 
    180 /*
    181  * Internal cpu startup sequencer
    182  * The sequence is as follows:
    183  *
    184  * MASTER	SLAVE
    185  * -------	----------
    186  * assume the kernel data is initialized
    187  * clear the proxy bit
    188  * start the slave cpu
    189  * wait for the slave cpu to set the proxy
    190  *
    191  *		the slave runs slave_startup and then sets the proxy
    192  *		the slave waits for the master to add slave to the ready set
    193  *
    194  * the master finishes the initialization and
    195  * adds the slave to the ready set
    196  *
    197  *		the slave exits the startup thread and is running
    198  */
    199 void
    200 start_cpu(int cpuid, void(*flag_func)(int))
    201 {
    202 	extern void cpu_startup(int);
    203 	int timout;
    204 
    205 	ASSERT(MUTEX_HELD(&cpu_lock));
    206 
    207 	/*
    208 	 * Before we begin the dance, tell DTrace that we're about to start
    209 	 * a CPU.
    210 	 */
    211 	if (dtrace_cpustart_init != NULL)
    212 		(*dtrace_cpustart_init)();
    213 
    214 	/* start the slave cpu */
    215 	CPUSET_DEL(proxy_ready_set, cpuid);
    216 	if (prom_test("SUNW,start-cpu-by-cpuid") == 0) {
    217 		(void) prom_startcpu_bycpuid(cpuid, (caddr_t)&cpu_startup,
    218 		    cpuid);
    219 	} else {
    220 		/* "by-cpuid" interface didn't exist.  Do it the old way */
    221 		pnode_t nodeid = cpunodes[cpuid].nodeid;
    222 
    223 		ASSERT(nodeid != (pnode_t)0);
    224 		(void) prom_startcpu(nodeid, (caddr_t)&cpu_startup, cpuid);
    225 	}
    226 
    227 	/* wait for the slave cpu to check in. */
    228 	for (timout = CPU_WAKEUP_GRACE_MSEC; timout; timout--) {
    229 		if (CPU_IN_SET(proxy_ready_set, cpuid))
    230 			break;
    231 		DELAY(1000);
    232 	}
    233 	if (timout == 0) {
    234 		panic("cpu%d failed to start (2)", cpuid);
    235 	}
    236 
    237 	/*
    238 	 * The slave has started; we can tell DTrace that it's safe again.
    239 	 */
    240 	if (dtrace_cpustart_fini != NULL)
    241 		(*dtrace_cpustart_fini)();
    242 
    243 	/* run the master side of stick synchronization for the slave cpu */
    244 	sticksync_master();
    245 
    246 	/*
    247 	 * deal with the cpu flags in a phase-specific manner
    248 	 * for various reasons, this needs to run after the slave
    249 	 * is checked in but before the slave is released.
    250 	 */
    251 	(*flag_func)(cpuid);
    252 
    253 	/* release the slave */
    254 	CPUSET_ADD(cpu_ready_set, cpuid);
    255 }
    256 
    257 #ifdef TRAPTRACE
    258 int trap_tr0_inuse = 1;	/* it is always used on the boot cpu */
    259 int trap_trace_inuse[NCPU];
    260 #endif /* TRAPTRACE */
    261 
    262 #define	cpu_next_free	cpu_prev
    263 
    264 /*
    265  * Routine to set up a CPU to prepare for starting it up.
    266  */
    267 int
    268 setup_cpu_common(int cpuid)
    269 {
    270 	struct cpu *cp = NULL;
    271 	kthread_id_t tp;
    272 #ifdef TRAPTRACE
    273 	int tt_index;
    274 	TRAP_TRACE_CTL	*ctlp;
    275 	caddr_t	newbuf;
    276 #endif /* TRAPTRACE */
    277 
    278 	extern void idle();
    279 	int	rval;
    280 
    281 	ASSERT(MUTEX_HELD(&cpu_lock));
    282 	ASSERT(cpu[cpuid] == NULL);
    283 
    284 	ASSERT(ncpus <= max_ncpus);
    285 
    286 #ifdef TRAPTRACE
    287 	/*
    288 	 * allocate a traptrace buffer for this CPU.
    289 	 */
    290 	ctlp = &trap_trace_ctl[cpuid];
    291 	if (!trap_tr0_inuse) {
    292 		trap_tr0_inuse = 1;
    293 		newbuf = trap_tr0;
    294 		tt_index = -1;
    295 	} else {
    296 		for (tt_index = 0; tt_index < (max_ncpus-1); tt_index++)
    297 			if (!trap_trace_inuse[tt_index])
    298 				break;
    299 		ASSERT(tt_index < max_ncpus - 1);
    300 		trap_trace_inuse[tt_index] = 1;
    301 		newbuf = (caddr_t)(ttrace_buf + (tt_index * TRAP_TSIZE));
    302 	}
    303 	ctlp->d.vaddr_base = newbuf;
    304 	ctlp->d.offset = ctlp->d.last_offset = 0;
    305 	ctlp->d.limit = trap_trace_bufsize;
    306 	ctlp->d.paddr_base = va_to_pa(newbuf);
    307 	ASSERT(ctlp->d.paddr_base != (uint64_t)-1);
    308 #endif /* TRAPTRACE */
    309 	/*
    310 	 * initialize hv traptrace buffer for this CPU
    311 	 */
    312 	mach_htraptrace_setup(cpuid);
    313 
    314 	/*
    315 	 * Obtain pointer to the appropriate cpu structure.
    316 	 */
    317 	if (cpu0.cpu_flags == 0) {
    318 		cp = &cpu0;
    319 	} else {
    320 		/*
    321 		 *  When dynamically allocating cpu structs,
    322 		 *  cpus is used as a pointer to a list of freed
    323 		 *  cpu structs.
    324 		 */
    325 		if (cpus) {
    326 			/* grab the first cpu struct on the free list */
    327 			cp = cpus;
    328 			if (cp->cpu_next_free)
    329 				cpus = cp->cpu_next_free;
    330 			else
    331 				cpus = NULL;
    332 		}
    333 	}
    334 
    335 	if (cp == NULL)
    336 		cp = vmem_xalloc(static_alloc_arena, CPU_ALLOC_SIZE,
    337 		    CPU_ALLOC_SIZE, 0, 0, NULL, NULL, VM_SLEEP);
    338 
    339 	bzero(cp, sizeof (*cp));
    340 
    341 	cp->cpu_id = cpuid;
    342 	cp->cpu_self = cp;
    343 
    344 	/*
    345 	 * Initialize ptl1_panic stack
    346 	 */
    347 	ptl1_init_cpu(cp);
    348 
    349 	/*
    350 	 * Initialize the dispatcher for this CPU.
    351 	 */
    352 	disp_cpu_init(cp);
    353 
    354 	/*
    355 	 * Bootstrap the CPU's PG data
    356 	 */
    357 	pg_cpu_bootstrap(cp);
    358 
    359 	cpu_vm_data_init(cp);
    360 
    361 	/*
    362 	 * Now, initialize per-CPU idle thread for this CPU.
    363 	 */
    364 	tp = thread_create(NULL, 0, idle, NULL, 0, &p0, TS_ONPROC, -1);
    365 
    366 	cp->cpu_idle_thread = tp;
    367 
    368 	tp->t_preempt = 1;
    369 	tp->t_bound_cpu = cp;
    370 	tp->t_affinitycnt = 1;
    371 	tp->t_cpu = cp;
    372 	tp->t_disp_queue = cp->cpu_disp;
    373 
    374 	/*
    375 	 * Registering a thread in the callback table is usually
    376 	 * done in the initialization code of the thread. In this
    377 	 * case, we do it right after thread creation to avoid
    378 	 * blocking idle thread while registering itself. It also
    379 	 * avoids the possibility of reregistration in case a CPU
    380 	 * restarts its idle thread.
    381 	 */
    382 	CALLB_CPR_INIT_SAFE(tp, "idle");
    383 
    384 	init_cpu_info(cp);
    385 
    386 	/*
    387 	 * Initialize the interrupt threads for this CPU
    388 	 */
    389 	cpu_intr_alloc(cp, NINTR_THREADS);
    390 
    391 	/*
    392 	 * Add CPU to list of available CPUs.
    393 	 * It'll be on the active list after it is started.
    394 	 */
    395 	cpu_add_unit(cp);
    396 
    397 	/*
    398 	 * Allocate and init cpu module private data structures,
    399 	 * including scrubber.
    400 	 */
    401 	cpu_init_private(cp);
    402 	populate_idstr(cp);
    403 
    404 	/*
    405 	 * Initialize the CPUs physical ID cache, and processor groups
    406 	 */
    407 	pghw_physid_create(cp);
    408 	(void) pg_cpu_init(cp, B_FALSE);
    409 
    410 	if ((rval = cpu_intrq_setup(cp)) != 0) {
    411 		return (rval);
    412 	}
    413 
    414 	/*
    415 	 * Initialize MMU context domain information.
    416 	 */
    417 	sfmmu_cpu_init(cp);
    418 
    419 	return (0);
    420 }
    421 
    422 /*
    423  * Routine to clean up a CPU after shutting it down.
    424  */
    425 int
    426 cleanup_cpu_common(int cpuid)
    427 {
    428 	struct cpu *cp;
    429 #ifdef TRAPTRACE
    430 	int i;
    431 	TRAP_TRACE_CTL	*ctlp;
    432 	caddr_t	newbuf;
    433 #endif /* TRAPTRACE */
    434 
    435 	ASSERT(MUTEX_HELD(&cpu_lock));
    436 	ASSERT(cpu[cpuid] != NULL);
    437 
    438 	cp = cpu[cpuid];
    439 
    440 	/* Free cpu module private data structures, including scrubber. */
    441 	cpu_uninit_private(cp);
    442 
    443 	/* Free cpu ID string and brand string. */
    444 	if (cp->cpu_idstr)
    445 		kmem_free(cp->cpu_idstr, strlen(cp->cpu_idstr) + 1);
    446 	if (cp->cpu_brandstr)
    447 		kmem_free(cp->cpu_brandstr, strlen(cp->cpu_brandstr) + 1);
    448 
    449 	cpu_vm_data_destroy(cp);
    450 
    451 	/*
    452 	 * Remove CPU from list of available CPUs.
    453 	 */
    454 	cpu_del_unit(cpuid);
    455 
    456 	/*
    457 	 * Clean any machine specific interrupt states.
    458 	 */
    459 	cpu_intrq_cleanup(cp);
    460 
    461 	/*
    462 	 * At this point, the only threads bound to this CPU should be
    463 	 * special per-cpu threads: it's idle thread, it's pause thread,
    464 	 * and it's interrupt threads.  Clean these up.
    465 	 */
    466 	cpu_destroy_bound_threads(cp);
    467 
    468 	/*
    469 	 * Free the interrupt stack.
    470 	 */
    471 	segkp_release(segkp, cp->cpu_intr_stack);
    472 
    473 	/*
    474 	 * Free hv traptrace buffer for this CPU.
    475 	 */
    476 	mach_htraptrace_cleanup(cpuid);
    477 #ifdef TRAPTRACE
    478 	/*
    479 	 * Free the traptrace buffer for this CPU.
    480 	 */
    481 	ctlp = &trap_trace_ctl[cpuid];
    482 	newbuf = ctlp->d.vaddr_base;
    483 	i = (newbuf - ttrace_buf) / (TRAP_TSIZE);
    484 	if (((newbuf - ttrace_buf) % (TRAP_TSIZE) == 0) &&
    485 	    ((i >= 0) && (i < (max_ncpus-1)))) {
    486 		/*
    487 		 * This CPU got it's trap trace buffer from the
    488 		 * boot-alloc'd bunch of them.
    489 		 */
    490 		trap_trace_inuse[i] = 0;
    491 		bzero(newbuf, (TRAP_TSIZE));
    492 	} else if (newbuf == trap_tr0) {
    493 		trap_tr0_inuse = 0;
    494 		bzero(trap_tr0, (TRAP_TSIZE));
    495 	} else {
    496 		cmn_err(CE_WARN, "failed to free trap trace buffer from cpu%d",
    497 		    cpuid);
    498 	}
    499 	bzero(ctlp, sizeof (*ctlp));
    500 #endif /* TRAPTRACE */
    501 
    502 	/*
    503 	 * There is a race condition with mutex_vector_enter() which
    504 	 * caches a cpu pointer. The race is detected by checking cpu_next.
    505 	 */
    506 	disp_cpu_fini(cp);
    507 	cpu_pa[cpuid] = 0;
    508 	if (CPU_MMU_CTXP(cp))
    509 		sfmmu_cpu_cleanup(cp);
    510 	bzero(cp, sizeof (*cp));
    511 
    512 	/*
    513 	 * Place the freed cpu structure on the list of freed cpus.
    514 	 */
    515 	if (cp != &cpu0) {
    516 		if (cpus) {
    517 			cp->cpu_next_free = cpus;
    518 			cpus = cp;
    519 		}
    520 		else
    521 			cpus = cp;
    522 	}
    523 
    524 	return (0);
    525 }
    526 
    527 /*
    528  * This routine is used to start a previously powered off processor.
    529  * Note that restarted cpus are initialized into the offline state.
    530  */
    531 void
    532 restart_other_cpu(int cpuid)
    533 {
    534 	struct cpu *cp;
    535 	kthread_id_t tp;
    536 	caddr_t	sp;
    537 	extern void idle();
    538 
    539 	ASSERT(MUTEX_HELD(&cpu_lock));
    540 	ASSERT(cpuid < NCPU && cpu[cpuid] != NULL);
    541 
    542 	/*
    543 	 * Obtain pointer to the appropriate cpu structure.
    544 	 */
    545 	cp = cpu[cpuid];
    546 
    547 	common_startup_init(cp, cpuid);
    548 
    549 	/*
    550 	 * idle thread t_lock is held when the idle thread is suspended.
    551 	 * Manually unlock the t_lock of idle loop so that we can resume
    552 	 * the suspended idle thread.
    553 	 * Also adjust the PC of idle thread for re-retry.
    554 	 */
    555 	cp->cpu_intr_actv = 0;	/* clear the value from previous life */
    556 	cp->cpu_m.mutex_ready = 0; /* we are not ready yet */
    557 	lock_clear(&cp->cpu_idle_thread->t_lock);
    558 	tp = cp->cpu_idle_thread;
    559 
    560 	sp = tp->t_stk;
    561 	tp->t_sp = (uintptr_t)((struct rwindow *)sp - 1) - STACK_BIAS;
    562 	tp->t_pc = (uintptr_t)idle - 8;
    563 
    564 	/*
    565 	 * restart the cpu now
    566 	 */
    567 	promsafe_pause_cpus();
    568 	start_cpu(cpuid, warm_flag_set);
    569 	start_cpus();
    570 
    571 	/* call cmn_err outside pause_cpus/start_cpus to avoid deadlock */
    572 	cmn_err(CE_CONT, "!cpu%d initialization complete - restarted\n",
    573 	    cpuid);
    574 }
    575 
    576 /*
    577  * Startup function executed on 'other' CPUs.  This is the first
    578  * C function after cpu_start sets up the cpu registers.
    579  */
    580 static void
    581 slave_startup(void)
    582 {
    583 	struct cpu	*cp = CPU;
    584 	ushort_t	original_flags = cp->cpu_flags;
    585 
    586 	mach_htraptrace_configure(cp->cpu_id);
    587 	cpu_intrq_register(CPU);
    588 	cp->cpu_m.mutex_ready = 1;
    589 	cp->cpu_m.poke_cpu_outstanding = B_FALSE;
    590 
    591 	/* acknowledge that we are done with initialization */
    592 	CPUSET_ADD(proxy_ready_set, cp->cpu_id);
    593 
    594 	/* synchronize STICK */
    595 	sticksync_slave();
    596 
    597 	if (boothowto & RB_DEBUG)
    598 		kdi_dvec_cpu_init(cp);
    599 
    600 	/*
    601 	 * the slave will wait here forever -- assuming that the master
    602 	 * will get back to us.  if it doesn't we've got bigger problems
    603 	 * than a master not replying to this slave.
    604 	 * the small delay improves the slave's responsiveness to the
    605 	 * master's ack and decreases the time window between master and
    606 	 * slave operations.
    607 	 */
    608 	while (!CPU_IN_SET(cpu_ready_set, cp->cpu_id))
    609 		DELAY(1);
    610 
    611 	/* enable interrupts */
    612 	(void) spl0();
    613 
    614 	/*
    615 	 * Signature block update to indicate that this CPU is in OS now.
    616 	 * This needs to be done after the PIL is lowered since on
    617 	 * some platforms the update code may block.
    618 	 */
    619 	CPU_SIGNATURE(OS_SIG, SIGST_RUN, SIGSUBST_NULL, cp->cpu_id);
    620 
    621 	/*
    622 	 * park the slave thread in a safe/quiet state and wait for the master
    623 	 * to finish configuring this CPU before proceeding to thread_exit().
    624 	 */
    625 	while (((volatile ushort_t)cp->cpu_flags) & CPU_QUIESCED)
    626 		DELAY(1);
    627 
    628 	/*
    629 	 * Initialize CPC CPU state.
    630 	 */
    631 	kcpc_hw_startup_cpu(original_flags);
    632 
    633 	/*
    634 	 * Notify the PG subsystem that the CPU  has started
    635 	 */
    636 	pg_cmt_cpu_startup(CPU);
    637 
    638 	/*
    639 	 * Now we are done with the startup thread, so free it up.
    640 	 */
    641 	thread_exit();
    642 	cmn_err(CE_PANIC, "slave_startup: cannot return");
    643 	/*NOTREACHED*/
    644 }
    645 
    646 extern struct cpu	*cpu[NCPU];	/* pointers to all CPUs */
    647 
    648 /*
    649  * cpu_bringup_set is a tunable (via /etc/system, debugger, etc.) that
    650  * can be used during debugging to control which processors are brought
    651  * online at boot time.  The variable represents a bitmap of the id's
    652  * of the processors that will be brought online.  The initialization
    653  * of this variable depends on the type of cpuset_t, which varies
    654  * depending on the number of processors supported (see cpuvar.h).
    655  */
    656 cpuset_t cpu_bringup_set;
    657 
    658 
    659 /*
    660  * Generic start-all cpus entry.  Typically used during cold initialization.
    661  * Note that cold start cpus are initialized into the online state.
    662  */
    663 /*ARGSUSED*/
    664 void
    665 start_other_cpus(int flag)
    666 {
    667 	int cpuid;
    668 	extern void idlestop_init(void);
    669 	int bootcpu;
    670 
    671 	/*
    672 	 * Check if cpu_bringup_set has been explicitly set before
    673 	 * initializing it.
    674 	 */
    675 	if (CPUSET_ISNULL(cpu_bringup_set)) {
    676 		CPUSET_ALL(cpu_bringup_set);
    677 	}
    678 
    679 	if (&cpu_feature_init)
    680 		cpu_feature_init();
    681 
    682 	/*
    683 	 * Initialize CPC.
    684 	 */
    685 	kcpc_hw_init();
    686 
    687 	mutex_enter(&cpu_lock);
    688 
    689 	/*
    690 	 * Initialize our own cpu_info.
    691 	 */
    692 	init_cpu_info(CPU);
    693 
    694 	/*
    695 	 * Initialize CPU 0 cpu module private data area, including scrubber.
    696 	 */
    697 	cpu_init_private(CPU);
    698 	populate_idstr(CPU);
    699 
    700 	/*
    701 	 * perform such initialization as is needed
    702 	 * to be able to take CPUs on- and off-line.
    703 	 */
    704 	cpu_pause_init();
    705 	xc_init();		/* initialize processor crosscalls */
    706 	idlestop_init();
    707 
    708 	if (!use_mp) {
    709 		mutex_exit(&cpu_lock);
    710 		cmn_err(CE_CONT, "?***** Not in MP mode\n");
    711 		return;
    712 	}
    713 	/*
    714 	 * should we be initializing this cpu?
    715 	 */
    716 	bootcpu = getprocessorid();
    717 
    718 	/*
    719 	 * launch all the slave cpus now
    720 	 */
    721 	for (cpuid = 0; cpuid < NCPU; cpuid++) {
    722 		pnode_t nodeid = cpunodes[cpuid].nodeid;
    723 
    724 		if (nodeid == (pnode_t)0)
    725 			continue;
    726 
    727 		if (cpuid == bootcpu) {
    728 			if (!CPU_IN_SET(cpu_bringup_set, cpuid)) {
    729 				cmn_err(CE_WARN, "boot cpu not a member "
    730 				    "of cpu_bringup_set, adding it");
    731 				CPUSET_ADD(cpu_bringup_set, cpuid);
    732 			}
    733 			continue;
    734 		}
    735 		if (!CPU_IN_SET(cpu_bringup_set, cpuid))
    736 			continue;
    737 
    738 		ASSERT(cpu[cpuid] == NULL);
    739 
    740 		if (setup_cpu_common(cpuid)) {
    741 			cmn_err(CE_PANIC, "cpu%d: setup failed", cpuid);
    742 		}
    743 
    744 		common_startup_init(cpu[cpuid], cpuid);
    745 
    746 		start_cpu(cpuid, cold_flag_set);
    747 		/*
    748 		 * Because slave_startup() gets fired off after init()
    749 		 * starts, we can't use the '?' trick to do 'boot -v'
    750 		 * printing - so we always direct the 'cpu .. online'
    751 		 * messages to the log.
    752 		 */
    753 		cmn_err(CE_CONT, "!cpu%d initialization complete - online\n",
    754 		    cpuid);
    755 
    756 		cpu_state_change_notify(cpuid, CPU_SETUP);
    757 
    758 		if (dtrace_cpu_init != NULL)
    759 			(*dtrace_cpu_init)(cpuid);
    760 	}
    761 
    762 	/*
    763 	 * since all the cpus are online now, redistribute interrupts to them.
    764 	 */
    765 	intr_redist_all_cpus();
    766 
    767 	mutex_exit(&cpu_lock);
    768 
    769 	/*
    770 	 * Start the Ecache scrubber.  Must be done after all calls to
    771 	 * cpu_init_private for every cpu (including CPU 0).
    772 	 */
    773 	cpu_init_cache_scrub();
    774 
    775 	if (&cpu_mp_init)
    776 		cpu_mp_init();
    777 }
    778