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 /* 23*e3d60c9bSAdrian 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 10220c794b3Sgavinm if (gcpu_disable || gcpu == NULL) 10320c794b3Sgavinm return; 1047aec1d6eScindi 10520c794b3Sgavinm cms_post_startup(hdl); 10620c794b3Sgavinm } 1077aec1d6eScindi 10820c794b3Sgavinm void 10920c794b3Sgavinm gcpu_post_mpstartup(cmi_hdl_t hdl) 11020c794b3Sgavinm { if (!gcpu_disable) { 11120c794b3Sgavinm cms_post_mpstartup(hdl); 11220c794b3Sgavinm gcpu_mca_poll_start(hdl); 11320c794b3Sgavinm } 1147aec1d6eScindi } 1157aec1d6eScindi 116*e3d60c9bSAdrian Frost cmi_api_ver_t _cmi_api_version = CMI_API_VERSION_2; 11720c794b3Sgavinm 1187aec1d6eScindi const cmi_ops_t _cmi_ops = { 11920c794b3Sgavinm gcpu_init, /* cmi_init */ 12020c794b3Sgavinm gcpu_post_startup, /* cmi_post_startup */ 12120c794b3Sgavinm gcpu_post_mpstartup, /* cmi_post_mpstartup */ 12220c794b3Sgavinm gcpu_faulted_enter, /* cmi_faulted_enter */ 12320c794b3Sgavinm gcpu_faulted_exit, /* cmi_faulted_exit */ 12420c794b3Sgavinm gcpu_mca_init, /* cmi_mca_init */ 12520c794b3Sgavinm gcpu_mca_trap, /* cmi_mca_trap */ 126*e3d60c9bSAdrian Frost gcpu_cmci_trap, /* cmi_cmci_trap */ 12720c794b3Sgavinm gcpu_msrinject, /* cmi_msrinject */ 12820c794b3Sgavinm gcpu_hdl_poke, /* cmi_hdl_poke */ 12920c794b3Sgavinm NULL, /* cmi_fini */ 1307aec1d6eScindi }; 1317aec1d6eScindi 1327aec1d6eScindi static struct modlcpu modlcpu = { 1337aec1d6eScindi &mod_cpuops, 1347aec1d6eScindi "Generic x86 CPU Module" 1357aec1d6eScindi }; 1367aec1d6eScindi 1377aec1d6eScindi static struct modlinkage modlinkage = { 1387aec1d6eScindi MODREV_1, 1397aec1d6eScindi (void *)&modlcpu, 1407aec1d6eScindi NULL 1417aec1d6eScindi }; 1427aec1d6eScindi 1437aec1d6eScindi int 1447aec1d6eScindi _init(void) 1457aec1d6eScindi { 1467aec1d6eScindi return (mod_install(&modlinkage)); 1477aec1d6eScindi } 1487aec1d6eScindi 1497aec1d6eScindi int 1507aec1d6eScindi _info(struct modinfo *modinfop) 1517aec1d6eScindi { 1527aec1d6eScindi return (mod_info(&modlinkage, modinfop)); 1537aec1d6eScindi } 1547aec1d6eScindi 1557aec1d6eScindi int 1567aec1d6eScindi _fini(void) 1577aec1d6eScindi { 1587aec1d6eScindi return (mod_remove(&modlinkage)); 1597aec1d6eScindi } 160