10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211991Sheppo 220Sstevel@tonic-gate /* 23*12013SHaik.Aftandilian@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <sys/machsystm.h> 280Sstevel@tonic-gate #include <sys/cpu_module.h> 290Sstevel@tonic-gate #include <sys/dtrace.h> 300Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 311991Sheppo #include <sys/mach_descrip.h> 322957Sjm22469 #include <sys/ldoms.h> 333266Sjb145095 #include <sys/hypervisor_api.h> 343266Sjb145095 #include <sys/soft_state.h> 355468Sjc25722 #include <sys/mpo.h> 360Sstevel@tonic-gate 370Sstevel@tonic-gate /* 380Sstevel@tonic-gate * Useful for disabling MP bring-up for an MP capable kernel 390Sstevel@tonic-gate * (a kernel that was built with MP defined) 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate int use_mp = 1; /* set to come up mp */ 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* 440Sstevel@tonic-gate * Init CPU info - get CPU type info for processor_info system call. 450Sstevel@tonic-gate */ 460Sstevel@tonic-gate void 470Sstevel@tonic-gate init_cpu_info(struct cpu *cp) 480Sstevel@tonic-gate { 490Sstevel@tonic-gate processor_info_t *pi = &cp->cpu_type_info; 500Sstevel@tonic-gate int cpuid = cp->cpu_id; 510Sstevel@tonic-gate struct cpu_node *cpunode = &cpunodes[cpuid]; 520Sstevel@tonic-gate 530Sstevel@tonic-gate cp->cpu_fpowner = NULL; /* not used for V9 */ 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * Get clock-frequency property from cpunodes[] for the CPU. 570Sstevel@tonic-gate */ 580Sstevel@tonic-gate pi->pi_clock = (cpunode->clock_freq + 500000) / 1000000; 590Sstevel@tonic-gate 604667Smh27603 /* 614667Smh27603 * Current frequency in Hz. 624667Smh27603 */ 634718Smh27603 cp->cpu_curr_clock = cpunode->clock_freq; 644667Smh27603 654877Smh27603 /* 664877Smh27603 * Supported frequencies. 674877Smh27603 */ 684877Smh27603 cpu_set_supp_freqs(cp, NULL); 694877Smh27603 700Sstevel@tonic-gate (void) strcpy(pi->pi_processor_type, "sparcv9"); 710Sstevel@tonic-gate (void) strcpy(pi->pi_fputypes, "sparcv9"); 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * StarFire requires the signature block stuff setup here 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate CPU_SGN_MAPIN(cpuid); 770Sstevel@tonic-gate if (cpuid == cpu0.cpu_id) { 780Sstevel@tonic-gate /* 790Sstevel@tonic-gate * cpu0 starts out running. Other cpus are 800Sstevel@tonic-gate * still in OBP land and we will leave them 810Sstevel@tonic-gate * alone for now. 820Sstevel@tonic-gate */ 830Sstevel@tonic-gate CPU_SIGNATURE(OS_SIG, SIGST_RUN, SIGSUBST_NULL, cpuid); 843266Sjb145095 /* 853266Sjb145095 * On first cpu setup, tell hv we are booting 863266Sjb145095 */ 873266Sjb145095 mach_set_soft_state(SIS_TRANSITION, 884677Szx151605 &SOLARIS_SOFT_STATE_BOOT_MSG); 890Sstevel@tonic-gate #ifdef lint 900Sstevel@tonic-gate cpuid = cpuid; 910Sstevel@tonic-gate #endif /* lint */ 920Sstevel@tonic-gate } 930Sstevel@tonic-gate } 940Sstevel@tonic-gate 950Sstevel@tonic-gate /* 961991Sheppo * Routine used to cleanup a CPU that has been powered off. This will 970Sstevel@tonic-gate * destroy all per-cpu information related to this cpu. 980Sstevel@tonic-gate */ 990Sstevel@tonic-gate int 1000Sstevel@tonic-gate mp_cpu_unconfigure(int cpuid) 1010Sstevel@tonic-gate { 1021991Sheppo int retval; 1031991Sheppo extern void empty_cpu(int); 1041991Sheppo extern int cleanup_cpu_common(int); 1051991Sheppo 1061991Sheppo ASSERT(MUTEX_HELD(&cpu_lock)); 1071991Sheppo 1081991Sheppo retval = cleanup_cpu_common(cpuid); 1091991Sheppo 1101991Sheppo empty_cpu(cpuid); 1111991Sheppo 1125468Sjc25722 mpo_cpu_remove(cpuid); 1135468Sjc25722 1141991Sheppo return (retval); 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate 1171991Sheppo struct mp_find_cpu_arg { 1181991Sheppo int cpuid; /* set by mp_cpu_configure() */ 1191991Sheppo dev_info_t *dip; /* set by mp_find_cpu() */ 1201991Sheppo }; 1211991Sheppo 1220Sstevel@tonic-gate int 1230Sstevel@tonic-gate mp_find_cpu(dev_info_t *dip, void *arg) 1240Sstevel@tonic-gate { 1251991Sheppo struct mp_find_cpu_arg *target = (struct mp_find_cpu_arg *)arg; 1261991Sheppo char *type; 1271991Sheppo int rv = DDI_WALK_CONTINUE; 1281991Sheppo int cpuid; 1291991Sheppo 1301991Sheppo if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 1311991Sheppo DDI_PROP_DONTPASS, "device_type", &type)) 1321991Sheppo return (DDI_WALK_CONTINUE); 1331991Sheppo 1341991Sheppo if (strcmp(type, "cpu") != 0) 1351991Sheppo goto out; 1361991Sheppo 1371991Sheppo cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 1381991Sheppo DDI_PROP_DONTPASS, "reg", -1); 1391991Sheppo 1401991Sheppo if (cpuid == -1) { 1411991Sheppo cmn_err(CE_PANIC, "reg prop not found in cpu node"); 1421991Sheppo } 1431991Sheppo 1441991Sheppo cpuid = PROM_CFGHDL_TO_CPUID(cpuid); 1451991Sheppo 1461991Sheppo if (cpuid != target->cpuid) 1471991Sheppo goto out; 1481991Sheppo 1491991Sheppo /* Found it */ 1501991Sheppo rv = DDI_WALK_TERMINATE; 1511991Sheppo target->dip = dip; 1521991Sheppo 1531991Sheppo out: 1541991Sheppo ddi_prop_free(type); 1551991Sheppo return (rv); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* 1590Sstevel@tonic-gate * Routine used to setup a newly inserted CPU in preparation for starting 1600Sstevel@tonic-gate * it running code. 1610Sstevel@tonic-gate */ 1620Sstevel@tonic-gate int 1630Sstevel@tonic-gate mp_cpu_configure(int cpuid) 1640Sstevel@tonic-gate { 1654203Srsmaeda md_t *mdp; 1664203Srsmaeda mde_cookie_t rootnode, cpunode = MDE_INVAL_ELEM_COOKIE; 1674203Srsmaeda int listsz, i; 1684203Srsmaeda mde_cookie_t *listp = NULL; 1694203Srsmaeda int num_nodes; 1704203Srsmaeda uint64_t cpuid_prop; 1714203Srsmaeda cpu_t *cpu; 1724203Srsmaeda processorid_t id; 1731991Sheppo 1741991Sheppo ASSERT(MUTEX_HELD(&cpu_lock)); 1751991Sheppo 1761991Sheppo if ((mdp = md_get_handle()) == NULL) 1771991Sheppo return (ENODEV); 1781991Sheppo 1791991Sheppo rootnode = md_root_node(mdp); 1801991Sheppo 1811991Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 1821991Sheppo 1831991Sheppo num_nodes = md_node_count(mdp); 1841991Sheppo 1851991Sheppo ASSERT(num_nodes > 0); 1861991Sheppo 1871991Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 1881991Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 1891991Sheppo 1901991Sheppo num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"), 1911991Sheppo md_find_name(mdp, "fwd"), listp); 1921991Sheppo 1931991Sheppo if (num_nodes < 0) 1941991Sheppo return (ENODEV); 1951991Sheppo 1961991Sheppo for (i = 0; i < num_nodes; i++) { 1971991Sheppo if (md_get_prop_val(mdp, listp[i], "id", &cpuid_prop)) 1981991Sheppo break; 1991991Sheppo if (cpuid_prop == (uint64_t)cpuid) { 2001991Sheppo cpunode = listp[i]; 2011991Sheppo break; 2021991Sheppo } 2031991Sheppo } 2041991Sheppo 2051991Sheppo if (cpunode == MDE_INVAL_ELEM_COOKIE) 2061991Sheppo return (ENODEV); 2071991Sheppo 2081991Sheppo kmem_free(listp, listsz); 2091991Sheppo 210*12013SHaik.Aftandilian@Sun.COM mpo_cpu_add(mdp, cpuid); 2115468Sjc25722 2121991Sheppo /* 2134677Szx151605 * Note: uses cpu_lock to protect cpunodes 2141991Sheppo * which will be modified inside of fill_cpu and 2151991Sheppo * setup_exec_unit_mappings. 2161991Sheppo */ 2171991Sheppo fill_cpu(mdp, cpunode); 2181991Sheppo 2191991Sheppo /* 2204203Srsmaeda * Adding a CPU may cause the execution unit sharing 2214203Srsmaeda * relationships to change. Update the mappings in 2224203Srsmaeda * the cpunode structures. 2231991Sheppo */ 2245000Sjc25722 setup_chip_mappings(mdp); 2251991Sheppo setup_exec_unit_mappings(mdp); 2261991Sheppo 2274203Srsmaeda /* propagate the updated mappings to the CPU structures */ 2284203Srsmaeda for (id = 0; id < NCPU; id++) { 2294203Srsmaeda if ((cpu = cpu_get(id)) == NULL) 2304203Srsmaeda continue; 2314203Srsmaeda 2324203Srsmaeda cpu_map_exec_units(cpu); 2334203Srsmaeda } 2344203Srsmaeda 2351991Sheppo (void) md_fini_handle(mdp); 2361991Sheppo 2374050Sjb145095 if ((i = setup_cpu_common(cpuid)) != 0) { 2384050Sjb145095 (void) cleanup_cpu_common(cpuid); 2394050Sjb145095 return (i); 2404050Sjb145095 } 2414203Srsmaeda 2420Sstevel@tonic-gate return (0); 2430Sstevel@tonic-gate } 2442957Sjm22469 2452957Sjm22469 /* 2462957Sjm22469 * Platform-specific actions to be taken when all cpus are running 2472957Sjm22469 * in the OS. 2482957Sjm22469 */ 2492957Sjm22469 void 2502957Sjm22469 cpu_mp_init(void) 2512957Sjm22469 { 2522957Sjm22469 extern void recalc_xc_timeouts(); 2532957Sjm22469 extern int cif_cpu_mp_ready; 2542957Sjm22469 2552957Sjm22469 /* N.B. This must happen after xc_init() has run. */ 2562957Sjm22469 recalc_xc_timeouts(); 2572957Sjm22469 2584776Sjm22469 if (!domaining_enabled()) 2592957Sjm22469 return; 2602957Sjm22469 2612957Sjm22469 cif_cpu_mp_ready = 1; 2622957Sjm22469 } 2637718SJason.Beloro@Sun.COM 2647718SJason.Beloro@Sun.COM void 2657718SJason.Beloro@Sun.COM populate_idstr(struct cpu *cp) 2667718SJason.Beloro@Sun.COM { 2677718SJason.Beloro@Sun.COM char buf[CPU_IDSTRLEN]; 2687718SJason.Beloro@Sun.COM struct cpu_node *cpunode; 2697718SJason.Beloro@Sun.COM processor_info_t *pi; 2707718SJason.Beloro@Sun.COM 2717718SJason.Beloro@Sun.COM cpunode = &cpunodes[cp->cpu_id]; 2727718SJason.Beloro@Sun.COM pi = &cp->cpu_type_info; 2737718SJason.Beloro@Sun.COM if (cp->cpu_m.cpu_chip == CPU_CHIPID_INVALID) { 2747718SJason.Beloro@Sun.COM (void) snprintf(buf, sizeof (buf), 2757718SJason.Beloro@Sun.COM "%s (cpuid %d, clock %d MHz)", 2767718SJason.Beloro@Sun.COM cpunode->name, cpunode->cpuid, pi->pi_clock); 2777718SJason.Beloro@Sun.COM } else { 2787718SJason.Beloro@Sun.COM (void) snprintf(buf, sizeof (buf), 2797718SJason.Beloro@Sun.COM "%s (chipid %d, clock %d MHz)", 2807718SJason.Beloro@Sun.COM cpunode->name, cp->cpu_m.cpu_chip, pi->pi_clock); 2817718SJason.Beloro@Sun.COM } 2827718SJason.Beloro@Sun.COM 2837718SJason.Beloro@Sun.COM cp->cpu_idstr = kmem_alloc(strlen(buf) + 1, KM_SLEEP); 2847718SJason.Beloro@Sun.COM (void) strcpy(cp->cpu_idstr, buf); 2857718SJason.Beloro@Sun.COM 2867718SJason.Beloro@Sun.COM cp->cpu_brandstr = kmem_alloc(strlen(cpunode->name) + 1, KM_SLEEP); 2877718SJason.Beloro@Sun.COM (void) strcpy(cp->cpu_brandstr, cpunode->name); 2887718SJason.Beloro@Sun.COM 2897718SJason.Beloro@Sun.COM cmn_err(CE_CONT, "?cpu%d: %s\n", cp->cpu_id, cp->cpu_idstr); 2907718SJason.Beloro@Sun.COM } 291