17aec1d6eScindi /* 27aec1d6eScindi * CDDL HEADER START 37aec1d6eScindi * 47aec1d6eScindi * The contents of this file are subject to the terms of the 53ad553a7Sgavinm * Common Development and Distribution License (the "License"). 63ad553a7Sgavinm * You may not use this file except in compliance with the License. 77aec1d6eScindi * 87aec1d6eScindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97aec1d6eScindi * or http://www.opensolaris.org/os/licensing. 107aec1d6eScindi * See the License for the specific language governing permissions 117aec1d6eScindi * and limitations under the License. 127aec1d6eScindi * 137aec1d6eScindi * When distributing Covered Code, include this CDDL HEADER in each 147aec1d6eScindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157aec1d6eScindi * If applicable, add the following below this CDDL HEADER, with the 167aec1d6eScindi * fields enclosed by brackets "[]" replaced with your own identifying 177aec1d6eScindi * information: Portions Copyright [yyyy] [name of copyright owner] 187aec1d6eScindi * 197aec1d6eScindi * CDDL HEADER END 207aec1d6eScindi */ 217aec1d6eScindi 227aec1d6eScindi /* 23e3d60c9bSAdrian Frost * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247aec1d6eScindi * Use is subject to license terms. 257aec1d6eScindi */ 267aec1d6eScindi 277aec1d6eScindi /* 287aec1d6eScindi * Generic x86 CPU Module 297aec1d6eScindi * 307aec1d6eScindi * This CPU module is used for generic x86 CPUs when Solaris has no other 317aec1d6eScindi * CPU-specific support module available. Code in this module should be the 327aec1d6eScindi * absolute bare-bones support and must be cognizant of both Intel and AMD etc. 337aec1d6eScindi */ 347aec1d6eScindi 357aec1d6eScindi #include <sys/types.h> 367aec1d6eScindi #include <sys/cpu_module_impl.h> 377aec1d6eScindi #include <sys/cpuvar.h> 387aec1d6eScindi #include <sys/kmem.h> 397aec1d6eScindi #include <sys/modctl.h> 4020c794b3Sgavinm #include <sys/pghw.h> 417aec1d6eScindi 427aec1d6eScindi #include "gcpu.h" 437aec1d6eScindi 4420c794b3Sgavinm /* 4520c794b3Sgavinm * Prevent generic cpu support from loading. 4620c794b3Sgavinm */ 4720c794b3Sgavinm int gcpu_disable = 0; 487aec1d6eScindi 4920c794b3Sgavinm #define GCPU_MAX_CHIPID 32 5020c794b3Sgavinm static struct gcpu_chipshared *gcpu_shared[GCPU_MAX_CHIPID]; 517aec1d6eScindi 5220c794b3Sgavinm /* 5320c794b3Sgavinm * Our cmi_init entry point, called during startup of each cpu instance. 5420c794b3Sgavinm */ 5520c794b3Sgavinm int 5620c794b3Sgavinm gcpu_init(cmi_hdl_t hdl, void **datap) 57843e1988Sjohnlev { 5820c794b3Sgavinm uint_t chipid = cmi_hdl_chipid(hdl); 5920c794b3Sgavinm struct gcpu_chipshared *sp, *osp; 6020c794b3Sgavinm gcpu_data_t *gcpu; 6120c794b3Sgavinm 6220c794b3Sgavinm if (gcpu_disable || chipid >= GCPU_MAX_CHIPID) 6320c794b3Sgavinm return (ENOTSUP); 6420c794b3Sgavinm 6520c794b3Sgavinm /* 6620c794b3Sgavinm * Allocate the state structure for this cpu. We will only 6720c794b3Sgavinm * allocate the bank logout areas in gcpu_mca_init once we 6820c794b3Sgavinm * know how many banks there are. 6920c794b3Sgavinm */ 7020c794b3Sgavinm gcpu = *datap = kmem_zalloc(sizeof (gcpu_data_t), KM_SLEEP); 7120c794b3Sgavinm cmi_hdl_hold(hdl); /* release in gcpu_fini */ 7220c794b3Sgavinm gcpu->gcpu_hdl = hdl; 7320c794b3Sgavinm 7420c794b3Sgavinm /* 7520c794b3Sgavinm * Allocate a chipshared structure if no sibling cpu has already 7620c794b3Sgavinm * allocated it, but allow for the fact that a sibling core may 7720c794b3Sgavinm * be starting up in parallel. 7820c794b3Sgavinm */ 7920c794b3Sgavinm if ((sp = gcpu_shared[chipid]) == NULL) { 8020c794b3Sgavinm sp = kmem_zalloc(sizeof (struct gcpu_chipshared), KM_SLEEP); 8120c794b3Sgavinm osp = atomic_cas_ptr(&gcpu_shared[chipid], NULL, sp); 8220c794b3Sgavinm if (osp == NULL) { 8320c794b3Sgavinm mutex_init(&sp->gcpus_poll_lock, NULL, MUTEX_DRIVER, 8420c794b3Sgavinm NULL); 8520c794b3Sgavinm mutex_init(&sp->gcpus_cfglock, NULL, MUTEX_DRIVER, 8620c794b3Sgavinm NULL); 8720c794b3Sgavinm } else { 8820c794b3Sgavinm kmem_free(sp, sizeof (struct gcpu_chipshared)); 8920c794b3Sgavinm sp = osp; 9020c794b3Sgavinm } 9120c794b3Sgavinm } 9220c794b3Sgavinm gcpu->gcpu_shared = sp; 93843e1988Sjohnlev 947aec1d6eScindi return (0); 957aec1d6eScindi } 967aec1d6eScindi 9720c794b3Sgavinm void 9820c794b3Sgavinm gcpu_post_startup(cmi_hdl_t hdl) 997aec1d6eScindi { 10020c794b3Sgavinm gcpu_data_t *gcpu = cmi_hdl_getcmidata(hdl); 10120c794b3Sgavinm 102*e4b86885SCheng Sean Ye if (gcpu_disable) 10320c794b3Sgavinm return; 1047aec1d6eScindi 105*e4b86885SCheng Sean Ye if (gcpu != NULL) 106*e4b86885SCheng Sean Ye cms_post_startup(hdl); 107*e4b86885SCheng Sean Ye #ifdef __xpv 108*e4b86885SCheng Sean Ye /* 109*e4b86885SCheng Sean Ye * All cpu handles are initialized so we can begin polling now. 110*e4b86885SCheng Sean Ye * Furthermore, our virq mechanism requires that everything 111*e4b86885SCheng Sean Ye * be run on cpu 0 so we can assure that by starting from here. 112*e4b86885SCheng Sean Ye */ 113*e4b86885SCheng Sean Ye gcpu_mca_poll_start(hdl); 114*e4b86885SCheng Sean Ye #endif 11520c794b3Sgavinm } 1167aec1d6eScindi 11720c794b3Sgavinm void 11820c794b3Sgavinm gcpu_post_mpstartup(cmi_hdl_t hdl) 119*e4b86885SCheng Sean Ye { 120*e4b86885SCheng Sean Ye if (gcpu_disable) 121*e4b86885SCheng Sean Ye return; 122*e4b86885SCheng Sean Ye 123*e4b86885SCheng Sean Ye cms_post_mpstartup(hdl); 124*e4b86885SCheng Sean Ye 125*e4b86885SCheng Sean Ye #ifndef __xpv 126*e4b86885SCheng Sean Ye /* 127*e4b86885SCheng Sean Ye * All cpu handles are initialized only once all cpus 128*e4b86885SCheng Sean Ye * are started, so we can begin polling post mp startup. 129*e4b86885SCheng Sean Ye */ 13020c794b3Sgavinm gcpu_mca_poll_start(hdl); 131*e4b86885SCheng Sean Ye #endif 1327aec1d6eScindi } 1337aec1d6eScindi 134*e4b86885SCheng Sean Ye #ifdef __xpv 135*e4b86885SCheng Sean Ye #define GCPU_OP(ntvop, xpvop) xpvop 136*e4b86885SCheng Sean Ye #else 137*e4b86885SCheng Sean Ye #define GCPU_OP(ntvop, xpvop) ntvop 138*e4b86885SCheng Sean Ye #endif 139*e4b86885SCheng Sean Ye 140*e4b86885SCheng Sean Ye cmi_api_ver_t _cmi_api_version = CMI_API_VERSION_3; 14120c794b3Sgavinm 1427aec1d6eScindi const cmi_ops_t _cmi_ops = { 14320c794b3Sgavinm gcpu_init, /* cmi_init */ 14420c794b3Sgavinm gcpu_post_startup, /* cmi_post_startup */ 14520c794b3Sgavinm gcpu_post_mpstartup, /* cmi_post_mpstartup */ 14620c794b3Sgavinm gcpu_faulted_enter, /* cmi_faulted_enter */ 14720c794b3Sgavinm gcpu_faulted_exit, /* cmi_faulted_exit */ 14820c794b3Sgavinm gcpu_mca_init, /* cmi_mca_init */ 149*e4b86885SCheng Sean Ye GCPU_OP(gcpu_mca_trap, NULL), /* cmi_mca_trap */ 150*e4b86885SCheng Sean Ye GCPU_OP(gcpu_cmci_trap, NULL), /* cmi_cmci_trap */ 15120c794b3Sgavinm gcpu_msrinject, /* cmi_msrinject */ 152*e4b86885SCheng Sean Ye GCPU_OP(gcpu_hdl_poke, NULL), /* cmi_hdl_poke */ 15320c794b3Sgavinm NULL, /* cmi_fini */ 154*e4b86885SCheng Sean Ye GCPU_OP(NULL, gcpu_xpv_panic_callback), /* cmi_panic_callback */ 1557aec1d6eScindi }; 1567aec1d6eScindi 1577aec1d6eScindi static struct modlcpu modlcpu = { 1587aec1d6eScindi &mod_cpuops, 1597aec1d6eScindi "Generic x86 CPU Module" 1607aec1d6eScindi }; 1617aec1d6eScindi 1627aec1d6eScindi static struct modlinkage modlinkage = { 1637aec1d6eScindi MODREV_1, 1647aec1d6eScindi (void *)&modlcpu, 1657aec1d6eScindi NULL 1667aec1d6eScindi }; 1677aec1d6eScindi 1687aec1d6eScindi int 1697aec1d6eScindi _init(void) 1707aec1d6eScindi { 1717aec1d6eScindi return (mod_install(&modlinkage)); 1727aec1d6eScindi } 1737aec1d6eScindi 1747aec1d6eScindi int 1757aec1d6eScindi _info(struct modinfo *modinfop) 1767aec1d6eScindi { 1777aec1d6eScindi return (mod_info(&modlinkage, modinfop)); 1787aec1d6eScindi } 1797aec1d6eScindi 1807aec1d6eScindi int 1817aec1d6eScindi _fini(void) 1827aec1d6eScindi { 1837aec1d6eScindi return (mod_remove(&modlinkage)); 1847aec1d6eScindi } 185