mp_startup.c revision bb121940c2fe627557326e0143391ace6e6b7372
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * CDDL HEADER START
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * The contents of this file are subject to the terms of the
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Common Development and Distribution License (the "License").
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * You may not use this file except in compliance with the License.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * See the License for the specific language governing permissions
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * and limitations under the License.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * CDDL HEADER END
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Use is subject to license terms.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore#pragma ident "%Z%%M% %I% %E% SMI"
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore#endif /* TRAPTRACE */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amoreextern void cpu_intrq_register(struct cpu *);
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amorestruct cpu *cpus; /* pointer to other cpus; dynamically allocate */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amorestruct cpu *cpu[NCPU]; /* pointers to all CPUs */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amoreuint64_t cpu_pa[NCPU]; /* pointers to all CPUs in PA */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amorecpu_core_t cpu_core[NCPU]; /* cpu_core structures */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amorecaddr_t ttrace_buf; /* bop alloced traptrace for all cpus except 0 */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore#endif /* TRAPTRACE */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore/* bit mask of cpus ready for x-calls, protected by cpu_lock */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore/* bit mask used to communicate with cpus during bringup */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amorestatic void slave_startup(void);
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Amount of time (in milliseconds) we should wait before giving up on CPU
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * initialization and assuming that the CPU we're trying to wake up is dead
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * or out of control.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * This function sets traptrace buffers for all cpus
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * other than boot cpu.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Note that the memory at base will be allocated later.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore return (vaddr + (TRAP_TSIZE * (max_ncpus - 1)));
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore#endif /* TRAPTRACE */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * common slave cpu initialization code
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Allocate and initialize the startup thread for this CPU.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore tp = thread_create(NULL, 0, slave_startup, NULL, 0, &p0,
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Set state to TS_ONPROC since this thread will start running
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * as soon as the CPU comes online.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * All the other fields of the thread structure are setup by
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * thread_create().
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Setup thread to start in slave_startup.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore tp->t_sp = (uintptr_t)((struct rwindow *)sp - 1) - STACK_BIAS;
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * parametric flag setting functions. these routines set the cpu
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * state just prior to releasing the slave cpu.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore cp->cpu_flags |= CPU_RUNNING | CPU_ENABLE | CPU_EXISTS;
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Add CPU_READY after the cpu_add_active() call
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * to avoid pausing cp.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * warm start activates cpus into the OFFLINE state
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore cp->cpu_flags |= CPU_RUNNING | CPU_READY | CPU_EXISTS
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Internal cpu startup sequencer
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * The sequence is as follows:
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * MASTER SLAVE
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * ------- ----------
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * assume the kernel data is initialized
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * clear the proxy bit
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * start the slave cpu
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * wait for the slave cpu to set the proxy
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * the slave runs slave_startup and then sets the proxy
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * the slave waits for the master to add slave to the ready set
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * the master finishes the initialization and
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * adds the slave to the ready set
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * the slave exits the startup thread and is running
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore extern void cpu_startup(int);
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Before we begin the dance, tell DTrace that we're about to start
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore /* start the slave cpu */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore if (prom_test("SUNW,start-cpu-by-cpuid") == 0) {
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore (void) prom_startcpu_bycpuid(cpuid, (caddr_t)&cpu_startup,
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore /* "by-cpuid" interface didn't exist. Do it the old way */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore (void) prom_startcpu(nodeid, (caddr_t)&cpu_startup, cpuid);
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore /* wait for the slave cpu to check in. */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore for (timout = CPU_WAKEUP_GRACE_MSEC; timout; timout--) {
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * The slave has started; we can tell DTrace that it's safe again.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore /* run the master side of stick synchronization for the slave cpu */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * deal with the cpu flags in a phase-specific manner
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * for various reasons, this needs to run after the slave
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * is checked in but before the slave is released.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore /* release the slave */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amoreint trap_tr0_inuse = 1; /* it is always used on the boot cpu */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore#endif /* TRAPTRACE */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Routine to set up a CPU to prepare for starting it up.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore#endif /* TRAPTRACE */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore extern void idle();
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * allocate a traptrace buffer for this CPU.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore for (tt_index = 0; tt_index < (max_ncpus-1); tt_index++)
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore newbuf = (caddr_t)(ttrace_buf + (tt_index * TRAP_TSIZE));
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore#endif /* TRAPTRACE */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * initialize hv traptrace buffer for this CPU
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Obtain pointer to the appropriate cpu structure.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * When dynamically allocating cpu structs,
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * cpus is used as a pointer to a list of freed
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * cpu structs.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore /* grab the first cpu struct on the free list */
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore cp = vmem_xalloc(static_alloc_arena, CPU_ALLOC_SIZE,
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore CPU_ALLOC_SIZE, 0, 0, NULL, NULL, VM_SLEEP);
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Initialize ptl1_panic stack
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Initialize the dispatcher for this CPU.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Now, initialize per-CPU idle thread for this CPU.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore tp = thread_create(NULL, 0, idle, NULL, 0, &p0, TS_ONPROC, -1);
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Registering a thread in the callback table is usually
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * done in the initialization code of the thread. In this
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * case, we do it right after thread creation to avoid
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * blocking idle thread while registering itself. It also
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * avoids the possibility of reregistration in case a CPU
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * restarts its idle thread.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Initialize the interrupt threads for this CPU
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Add CPU to list of available CPUs.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * It'll be on the active list after it is started.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Allocate and init cpu module private data structures,
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * including scrubber.
49ef7e0638c8b771d8a136eae78b1c0f99acc8e0Garrett D'Amore * Initialize the CPUs physical ID cache, and processor groups
#ifdef TRAPTRACE
#ifdef TRAPTRACE
trap_trace_inuse[i] = 0;
trap_tr0_inuse = 0;
cpuid);
if (cpus) {
extern void idle();
start_cpus();
/* call cmn_err outside pause_cpus/start_cpus to avoid deadlock */
cpuid);
slave_startup(void)
(void) spl0();
thread_exit();
extern void setup_cpu_common(int);
* depending on the number of processors supported (see cpuvar.h).
int cpuid;
extern void idlestop_init(void);
int bootcpu;
#ifdef MPSAS
if (&cpu_feature_init)
kcpc_hw_init();
if (!use_mp) {
cpuid);
if (&cpu_mp_init)
cpu_mp_init();