17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 211ae08745Sheppo 227c478bd9Sstevel@tonic-gate /* 23*f9e0b1dcSAlexandre Chartre * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 277c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 287c478bd9Sstevel@tonic-gate #include <sys/dtrace.h> 297c478bd9Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 301ae08745Sheppo #include <sys/mach_descrip.h> 31f273041fSjm22469 #include <sys/ldoms.h> 323b890a5bSjb145095 #include <sys/hypervisor_api.h> 333b890a5bSjb145095 #include <sys/soft_state.h> 34924db11bSjc25722 #include <sys/mpo.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate /* 377c478bd9Sstevel@tonic-gate * Useful for disabling MP bring-up for an MP capable kernel 387c478bd9Sstevel@tonic-gate * (a kernel that was built with MP defined) 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate int use_mp = 1; /* set to come up mp */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /* 437c478bd9Sstevel@tonic-gate * Init CPU info - get CPU type info for processor_info system call. 447c478bd9Sstevel@tonic-gate */ 457c478bd9Sstevel@tonic-gate void 467c478bd9Sstevel@tonic-gate init_cpu_info(struct cpu *cp) 477c478bd9Sstevel@tonic-gate { 487c478bd9Sstevel@tonic-gate processor_info_t *pi = &cp->cpu_type_info; 497c478bd9Sstevel@tonic-gate int cpuid = cp->cpu_id; 507c478bd9Sstevel@tonic-gate struct cpu_node *cpunode = &cpunodes[cpuid]; 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate cp->cpu_fpowner = NULL; /* not used for V9 */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 557c478bd9Sstevel@tonic-gate * Get clock-frequency property from cpunodes[] for the CPU. 567c478bd9Sstevel@tonic-gate */ 577c478bd9Sstevel@tonic-gate pi->pi_clock = (cpunode->clock_freq + 500000) / 1000000; 587c478bd9Sstevel@tonic-gate 595cff7825Smh27603 /* 605cff7825Smh27603 * Current frequency in Hz. 615cff7825Smh27603 */ 62cf74e62bSmh27603 cp->cpu_curr_clock = cpunode->clock_freq; 635cff7825Smh27603 6468afbec1Smh27603 /* 6568afbec1Smh27603 * Supported frequencies. 6668afbec1Smh27603 */ 6768afbec1Smh27603 cpu_set_supp_freqs(cp, NULL); 6868afbec1Smh27603 697c478bd9Sstevel@tonic-gate (void) strcpy(pi->pi_processor_type, "sparcv9"); 707c478bd9Sstevel@tonic-gate (void) strcpy(pi->pi_fputypes, "sparcv9"); 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate /* 737c478bd9Sstevel@tonic-gate * StarFire requires the signature block stuff setup here 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate CPU_SGN_MAPIN(cpuid); 76*f9e0b1dcSAlexandre Chartre 77*f9e0b1dcSAlexandre Chartre /* 78*f9e0b1dcSAlexandre Chartre * cpu0 is always initialized at boot time, but it can be initialized 79*f9e0b1dcSAlexandre Chartre * again if it is dynamically removed and then re-added. We check if 80*f9e0b1dcSAlexandre Chartre * we are booting by verifying cpu_list. During boot, cpu0 is already 81*f9e0b1dcSAlexandre Chartre * in cpu_list when this function is called. When a cpu is dynamically 82*f9e0b1dcSAlexandre Chartre * added (after the boot) then it is added to cpu_list after this 83*f9e0b1dcSAlexandre Chartre * function is called. 84*f9e0b1dcSAlexandre Chartre */ 85*f9e0b1dcSAlexandre Chartre if (cpuid == cpu0.cpu_id && ncpus == 1 && cpu_list[0].cpu_id == cpuid) { 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * cpu0 starts out running. Other cpus are 887c478bd9Sstevel@tonic-gate * still in OBP land and we will leave them 897c478bd9Sstevel@tonic-gate * alone for now. 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_RUN, SIGSUBST_NULL, cpuid); 923b890a5bSjb145095 /* 933b890a5bSjb145095 * On first cpu setup, tell hv we are booting 943b890a5bSjb145095 */ 953b890a5bSjb145095 mach_set_soft_state(SIS_TRANSITION, 963b890a5bSjb145095 &SOLARIS_SOFT_STATE_BOOT_MSG); 977c478bd9Sstevel@tonic-gate #ifdef lint 987c478bd9Sstevel@tonic-gate cpuid = cpuid; 997c478bd9Sstevel@tonic-gate #endif /* lint */ 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1047c478bd9Sstevel@tonic-gate * Routine used to cleanup a CPU that has been powered off. This will 1057c478bd9Sstevel@tonic-gate * destroy all per-cpu information related to this cpu. 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate int 1087c478bd9Sstevel@tonic-gate mp_cpu_unconfigure(int cpuid) 1097c478bd9Sstevel@tonic-gate { 1101ae08745Sheppo int retval; 1111ae08745Sheppo extern void empty_cpu(int); 1121ae08745Sheppo extern int cleanup_cpu_common(int); 1131ae08745Sheppo 1141ae08745Sheppo ASSERT(MUTEX_HELD(&cpu_lock)); 1151ae08745Sheppo 1161ae08745Sheppo retval = cleanup_cpu_common(cpuid); 1171ae08745Sheppo 1181ae08745Sheppo empty_cpu(cpuid); 1191ae08745Sheppo 120924db11bSjc25722 mpo_cpu_remove(cpuid); 121924db11bSjc25722 1221ae08745Sheppo return (retval); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1251ae08745Sheppo struct mp_find_cpu_arg { 1261ae08745Sheppo int cpuid; /* set by mp_cpu_configure() */ 1271ae08745Sheppo dev_info_t *dip; /* set by mp_find_cpu() */ 1281ae08745Sheppo }; 1291ae08745Sheppo 1307c478bd9Sstevel@tonic-gate int 1317c478bd9Sstevel@tonic-gate mp_find_cpu(dev_info_t *dip, void *arg) 1327c478bd9Sstevel@tonic-gate { 1331ae08745Sheppo struct mp_find_cpu_arg *target = (struct mp_find_cpu_arg *)arg; 1341ae08745Sheppo char *type; 1351ae08745Sheppo int rv = DDI_WALK_CONTINUE; 1361ae08745Sheppo int cpuid; 1371ae08745Sheppo 1381ae08745Sheppo if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 1391ae08745Sheppo DDI_PROP_DONTPASS, "device_type", &type)) 1401ae08745Sheppo return (DDI_WALK_CONTINUE); 1411ae08745Sheppo 1421ae08745Sheppo if (strcmp(type, "cpu") != 0) 1431ae08745Sheppo goto out; 1441ae08745Sheppo 1451ae08745Sheppo cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 1461ae08745Sheppo DDI_PROP_DONTPASS, "reg", -1); 1471ae08745Sheppo 1481ae08745Sheppo if (cpuid == -1) { 1491ae08745Sheppo cmn_err(CE_PANIC, "reg prop not found in cpu node"); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1521ae08745Sheppo cpuid = PROM_CFGHDL_TO_CPUID(cpuid); 1531ae08745Sheppo 1541ae08745Sheppo if (cpuid != target->cpuid) 1551ae08745Sheppo goto out; 1561ae08745Sheppo 1571ae08745Sheppo /* Found it */ 1581ae08745Sheppo rv = DDI_WALK_TERMINATE; 1591ae08745Sheppo target->dip = dip; 1601ae08745Sheppo 1611ae08745Sheppo out: 1621ae08745Sheppo ddi_prop_free(type); 1631ae08745Sheppo return (rv); 1641ae08745Sheppo } 1651ae08745Sheppo 1667c478bd9Sstevel@tonic-gate /* 1677c478bd9Sstevel@tonic-gate * Routine used to setup a newly inserted CPU in preparation for starting 1687c478bd9Sstevel@tonic-gate * it running code. 1697c478bd9Sstevel@tonic-gate */ 1707c478bd9Sstevel@tonic-gate int 1717c478bd9Sstevel@tonic-gate mp_cpu_configure(int cpuid) 1727c478bd9Sstevel@tonic-gate { 1731ae08745Sheppo md_t *mdp; 1741ae08745Sheppo mde_cookie_t rootnode, cpunode = MDE_INVAL_ELEM_COOKIE; 1751ae08745Sheppo int listsz, i; 1761ae08745Sheppo mde_cookie_t *listp = NULL; 1771ae08745Sheppo int num_nodes; 1781ae08745Sheppo uint64_t cpuid_prop; 179459190a5Srsmaeda cpu_t *cpu; 180459190a5Srsmaeda processorid_t id; 1811ae08745Sheppo 1821ae08745Sheppo ASSERT(MUTEX_HELD(&cpu_lock)); 1831ae08745Sheppo 1841ae08745Sheppo if ((mdp = md_get_handle()) == NULL) 1851ae08745Sheppo return (ENODEV); 1861ae08745Sheppo 1871ae08745Sheppo rootnode = md_root_node(mdp); 1881ae08745Sheppo 1891ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 1901ae08745Sheppo 1911ae08745Sheppo num_nodes = md_node_count(mdp); 1921ae08745Sheppo 1931ae08745Sheppo ASSERT(num_nodes > 0); 1941ae08745Sheppo 1951ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 1961ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 1971ae08745Sheppo 1981ae08745Sheppo num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"), 1991ae08745Sheppo md_find_name(mdp, "fwd"), listp); 2001ae08745Sheppo 2011ae08745Sheppo if (num_nodes < 0) 2021ae08745Sheppo return (ENODEV); 2031ae08745Sheppo 2041ae08745Sheppo for (i = 0; i < num_nodes; i++) { 2051ae08745Sheppo if (md_get_prop_val(mdp, listp[i], "id", &cpuid_prop)) 2061ae08745Sheppo break; 2071ae08745Sheppo if (cpuid_prop == (uint64_t)cpuid) { 2081ae08745Sheppo cpunode = listp[i]; 2091ae08745Sheppo break; 2101ae08745Sheppo } 2111ae08745Sheppo } 2121ae08745Sheppo 2131ae08745Sheppo if (cpunode == MDE_INVAL_ELEM_COOKIE) 2141ae08745Sheppo return (ENODEV); 2151ae08745Sheppo 2161ae08745Sheppo kmem_free(listp, listsz); 2171ae08745Sheppo 218183ef8a1SHaik Aftandilian mpo_cpu_add(mdp, cpuid); 219924db11bSjc25722 2201ae08745Sheppo /* 221ad8d2eb8Szx151605 * Note: uses cpu_lock to protect cpunodes 2221ae08745Sheppo * which will be modified inside of fill_cpu and 2231ae08745Sheppo * setup_exec_unit_mappings. 2241ae08745Sheppo */ 2251ae08745Sheppo fill_cpu(mdp, cpunode); 2261ae08745Sheppo 2271ae08745Sheppo /* 228459190a5Srsmaeda * Adding a CPU may cause the execution unit sharing 229459190a5Srsmaeda * relationships to change. Update the mappings in 230459190a5Srsmaeda * the cpunode structures. 2311ae08745Sheppo */ 2321a7b528fSjc25722 setup_chip_mappings(mdp); 2331ae08745Sheppo setup_exec_unit_mappings(mdp); 2341ae08745Sheppo 235459190a5Srsmaeda /* propagate the updated mappings to the CPU structures */ 236459190a5Srsmaeda for (id = 0; id < NCPU; id++) { 237459190a5Srsmaeda if ((cpu = cpu_get(id)) == NULL) 238459190a5Srsmaeda continue; 239459190a5Srsmaeda 240459190a5Srsmaeda cpu_map_exec_units(cpu); 241459190a5Srsmaeda } 242459190a5Srsmaeda 2431ae08745Sheppo (void) md_fini_handle(mdp); 2441ae08745Sheppo 245982b9107Sjb145095 if ((i = setup_cpu_common(cpuid)) != 0) { 246982b9107Sjb145095 (void) cleanup_cpu_common(cpuid); 247982b9107Sjb145095 return (i); 248982b9107Sjb145095 } 249459190a5Srsmaeda 2507c478bd9Sstevel@tonic-gate return (0); 2517c478bd9Sstevel@tonic-gate } 252f273041fSjm22469 253f273041fSjm22469 /* 254f273041fSjm22469 * Platform-specific actions to be taken when all cpus are running 255f273041fSjm22469 * in the OS. 256f273041fSjm22469 */ 257f273041fSjm22469 void 258f273041fSjm22469 cpu_mp_init(void) 259f273041fSjm22469 { 260f273041fSjm22469 extern void recalc_xc_timeouts(); 261f273041fSjm22469 extern int cif_cpu_mp_ready; 262f273041fSjm22469 263f273041fSjm22469 /* N.B. This must happen after xc_init() has run. */ 264f273041fSjm22469 recalc_xc_timeouts(); 265f273041fSjm22469 26622e19ac1Sjm22469 if (!domaining_enabled()) 267f273041fSjm22469 return; 268f273041fSjm22469 269f273041fSjm22469 cif_cpu_mp_ready = 1; 270f273041fSjm22469 } 2712f0fcb93SJason Beloro 2722f0fcb93SJason Beloro void 2732f0fcb93SJason Beloro populate_idstr(struct cpu *cp) 2742f0fcb93SJason Beloro { 2752f0fcb93SJason Beloro char buf[CPU_IDSTRLEN]; 2762f0fcb93SJason Beloro struct cpu_node *cpunode; 2772f0fcb93SJason Beloro processor_info_t *pi; 2782f0fcb93SJason Beloro 2792f0fcb93SJason Beloro cpunode = &cpunodes[cp->cpu_id]; 2802f0fcb93SJason Beloro pi = &cp->cpu_type_info; 2812f0fcb93SJason Beloro if (cp->cpu_m.cpu_chip == CPU_CHIPID_INVALID) { 2822f0fcb93SJason Beloro (void) snprintf(buf, sizeof (buf), 2832f0fcb93SJason Beloro "%s (cpuid %d, clock %d MHz)", 2842f0fcb93SJason Beloro cpunode->name, cpunode->cpuid, pi->pi_clock); 2852f0fcb93SJason Beloro } else { 2862f0fcb93SJason Beloro (void) snprintf(buf, sizeof (buf), 2872f0fcb93SJason Beloro "%s (chipid %d, clock %d MHz)", 2882f0fcb93SJason Beloro cpunode->name, cp->cpu_m.cpu_chip, pi->pi_clock); 2892f0fcb93SJason Beloro } 2902f0fcb93SJason Beloro 2912f0fcb93SJason Beloro cp->cpu_idstr = kmem_alloc(strlen(buf) + 1, KM_SLEEP); 2922f0fcb93SJason Beloro (void) strcpy(cp->cpu_idstr, buf); 2932f0fcb93SJason Beloro 2942f0fcb93SJason Beloro cp->cpu_brandstr = kmem_alloc(strlen(cpunode->name) + 1, KM_SLEEP); 2952f0fcb93SJason Beloro (void) strcpy(cp->cpu_brandstr, cpunode->name); 2962f0fcb93SJason Beloro 2972f0fcb93SJason Beloro cmn_err(CE_CONT, "?cpu%d: %s\n", cp->cpu_id, cp->cpu_idstr); 2982f0fcb93SJason Beloro } 299