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 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/machsystm.h>
     28 #include <sys/cpu_module.h>
     29 #include <sys/dtrace.h>
     30 #include <sys/cpu_sgnblk_defs.h>
     31 #include <sys/mach_descrip.h>
     32 #include <sys/ldoms.h>
     33 #include <sys/hypervisor_api.h>
     34 #include <sys/soft_state.h>
     35 #include <sys/mpo.h>
     36 
     37 /*
     38  * Useful for disabling MP bring-up for an MP capable kernel
     39  * (a kernel that was built with MP defined)
     40  */
     41 int use_mp = 1;			/* set to come up mp */
     42 
     43 /*
     44  * Init CPU info - get CPU type info for processor_info system call.
     45  */
     46 void
     47 init_cpu_info(struct cpu *cp)
     48 {
     49 	processor_info_t *pi = &cp->cpu_type_info;
     50 	int cpuid = cp->cpu_id;
     51 	struct cpu_node *cpunode = &cpunodes[cpuid];
     52 
     53 	cp->cpu_fpowner = NULL;		/* not used for V9 */
     54 
     55 	/*
     56 	 * Get clock-frequency property from cpunodes[] for the CPU.
     57 	 */
     58 	pi->pi_clock = (cpunode->clock_freq + 500000) / 1000000;
     59 
     60 	/*
     61 	 * Current frequency in Hz.
     62 	 */
     63 	cp->cpu_curr_clock = cpunode->clock_freq;
     64 
     65 	/*
     66 	 * Supported frequencies.
     67 	 */
     68 	cpu_set_supp_freqs(cp, NULL);
     69 
     70 	(void) strcpy(pi->pi_processor_type, "sparcv9");
     71 	(void) strcpy(pi->pi_fputypes, "sparcv9");
     72 
     73 	/*
     74 	 * StarFire requires the signature block stuff setup here
     75 	 */
     76 	CPU_SGN_MAPIN(cpuid);
     77 	if (cpuid == cpu0.cpu_id) {
     78 		/*
     79 		 * cpu0 starts out running.  Other cpus are
     80 		 * still in OBP land and we will leave them
     81 		 * alone for now.
     82 		 */
     83 		CPU_SIGNATURE(OS_SIG, SIGST_RUN, SIGSUBST_NULL, cpuid);
     84 		/*
     85 		 * On first cpu setup, tell hv we are booting
     86 		 */
     87 		mach_set_soft_state(SIS_TRANSITION,
     88 		    &SOLARIS_SOFT_STATE_BOOT_MSG);
     89 #ifdef	lint
     90 		cpuid = cpuid;
     91 #endif	/* lint */
     92 	}
     93 }
     94 
     95 /*
     96  * Routine used to cleanup a CPU that has been powered off. This will
     97  * destroy all per-cpu information related to this cpu.
     98  */
     99 int
    100 mp_cpu_unconfigure(int cpuid)
    101 {
    102 	int retval;
    103 	extern void empty_cpu(int);
    104 	extern int cleanup_cpu_common(int);
    105 
    106 	ASSERT(MUTEX_HELD(&cpu_lock));
    107 
    108 	retval = cleanup_cpu_common(cpuid);
    109 
    110 	empty_cpu(cpuid);
    111 
    112 	mpo_cpu_remove(cpuid);
    113 
    114 	return (retval);
    115 }
    116 
    117 struct mp_find_cpu_arg {
    118 	int cpuid;		/* set by mp_cpu_configure() */
    119 	dev_info_t *dip;	/* set by mp_find_cpu() */
    120 };
    121 
    122 int
    123 mp_find_cpu(dev_info_t *dip, void *arg)
    124 {
    125 	struct mp_find_cpu_arg *target = (struct mp_find_cpu_arg *)arg;
    126 	char	*type;
    127 	int	rv = DDI_WALK_CONTINUE;
    128 	int	cpuid;
    129 
    130 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
    131 	    DDI_PROP_DONTPASS, "device_type", &type))
    132 		return (DDI_WALK_CONTINUE);
    133 
    134 	if (strcmp(type, "cpu") != 0)
    135 		goto out;
    136 
    137 	cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
    138 	    DDI_PROP_DONTPASS, "reg", -1);
    139 
    140 	if (cpuid == -1) {
    141 		cmn_err(CE_PANIC, "reg prop not found in cpu node");
    142 	}
    143 
    144 	cpuid = PROM_CFGHDL_TO_CPUID(cpuid);
    145 
    146 	if (cpuid != target->cpuid)
    147 		goto out;
    148 
    149 	/* Found it */
    150 	rv = DDI_WALK_TERMINATE;
    151 	target->dip = dip;
    152 
    153 out:
    154 	ddi_prop_free(type);
    155 	return (rv);
    156 }
    157 
    158 /*
    159  * Routine used to setup a newly inserted CPU in preparation for starting
    160  * it running code.
    161  */
    162 int
    163 mp_cpu_configure(int cpuid)
    164 {
    165 	md_t		*mdp;
    166 	mde_cookie_t	rootnode, cpunode = MDE_INVAL_ELEM_COOKIE;
    167 	int		listsz, i;
    168 	mde_cookie_t	*listp = NULL;
    169 	int		num_nodes;
    170 	uint64_t	cpuid_prop;
    171 	cpu_t		*cpu;
    172 	processorid_t	id;
    173 
    174 	ASSERT(MUTEX_HELD(&cpu_lock));
    175 
    176 	if ((mdp = md_get_handle()) == NULL)
    177 		return (ENODEV);
    178 
    179 	rootnode = md_root_node(mdp);
    180 
    181 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
    182 
    183 	num_nodes = md_node_count(mdp);
    184 
    185 	ASSERT(num_nodes > 0);
    186 
    187 	listsz = num_nodes * sizeof (mde_cookie_t);
    188 	listp = kmem_zalloc(listsz, KM_SLEEP);
    189 
    190 	num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"),
    191 	    md_find_name(mdp, "fwd"), listp);
    192 
    193 	if (num_nodes < 0)
    194 		return (ENODEV);
    195 
    196 	for (i = 0; i < num_nodes; i++) {
    197 		if (md_get_prop_val(mdp, listp[i], "id", &cpuid_prop))
    198 			break;
    199 		if (cpuid_prop == (uint64_t)cpuid) {
    200 			cpunode = listp[i];
    201 			break;
    202 		}
    203 	}
    204 
    205 	if (cpunode == MDE_INVAL_ELEM_COOKIE)
    206 		return (ENODEV);
    207 
    208 	kmem_free(listp, listsz);
    209 
    210 	mpo_cpu_add(cpuid);
    211 
    212 	/*
    213 	 * Note: uses cpu_lock to protect cpunodes
    214 	 * which will be modified inside of fill_cpu and
    215 	 * setup_exec_unit_mappings.
    216 	 */
    217 	fill_cpu(mdp, cpunode);
    218 
    219 	/*
    220 	 * Adding a CPU may cause the execution unit sharing
    221 	 * relationships to change. Update the mappings in
    222 	 * the cpunode structures.
    223 	 */
    224 	setup_chip_mappings(mdp);
    225 	setup_exec_unit_mappings(mdp);
    226 
    227 	/* propagate the updated mappings to the CPU structures */
    228 	for (id = 0; id < NCPU; id++) {
    229 		if ((cpu = cpu_get(id)) == NULL)
    230 			continue;
    231 
    232 		cpu_map_exec_units(cpu);
    233 	}
    234 
    235 	(void) md_fini_handle(mdp);
    236 
    237 	if ((i = setup_cpu_common(cpuid)) != 0) {
    238 		(void) cleanup_cpu_common(cpuid);
    239 		return (i);
    240 	}
    241 
    242 	return (0);
    243 }
    244 
    245 /*
    246  * Platform-specific actions to be taken when all cpus are running
    247  * in the OS.
    248  */
    249 void
    250 cpu_mp_init(void)
    251 {
    252 	extern void recalc_xc_timeouts();
    253 	extern int cif_cpu_mp_ready;
    254 
    255 	/* N.B. This must happen after xc_init() has run. */
    256 	recalc_xc_timeouts();
    257 
    258 	if (!domaining_enabled())
    259 		return;
    260 
    261 	cif_cpu_mp_ready = 1;
    262 }
    263 
    264 void
    265 populate_idstr(struct cpu *cp)
    266 {
    267 	char buf[CPU_IDSTRLEN];
    268 	struct cpu_node *cpunode;
    269 	processor_info_t *pi;
    270 
    271 	cpunode = &cpunodes[cp->cpu_id];
    272 	pi = &cp->cpu_type_info;
    273 	if (cp->cpu_m.cpu_chip == CPU_CHIPID_INVALID) {
    274 		(void) snprintf(buf, sizeof (buf),
    275 		    "%s (cpuid %d, clock %d MHz)",
    276 		    cpunode->name, cpunode->cpuid, pi->pi_clock);
    277 	} else {
    278 		(void) snprintf(buf, sizeof (buf),
    279 		    "%s (chipid %d, clock %d MHz)",
    280 		    cpunode->name, cp->cpu_m.cpu_chip, pi->pi_clock);
    281 	}
    282 
    283 	cp->cpu_idstr = kmem_alloc(strlen(buf) + 1, KM_SLEEP);
    284 	(void) strcpy(cp->cpu_idstr, buf);
    285 
    286 	cp->cpu_brandstr = kmem_alloc(strlen(cpunode->name) + 1, KM_SLEEP);
    287 	(void) strcpy(cp->cpu_brandstr, cpunode->name);
    288 
    289 	cmn_err(CE_CONT, "?cpu%d: %s\n", cp->cpu_id, cp->cpu_idstr);
    290 }
    291