120c794b3Sgavinm /* 220c794b3Sgavinm * CDDL HEADER START 320c794b3Sgavinm * 420c794b3Sgavinm * The contents of this file are subject to the terms of the 520c794b3Sgavinm * Common Development and Distribution License (the "License"). 620c794b3Sgavinm * You may not use this file except in compliance with the License. 720c794b3Sgavinm * 820c794b3Sgavinm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 920c794b3Sgavinm * or http://www.opensolaris.org/os/licensing. 1020c794b3Sgavinm * See the License for the specific language governing permissions 1120c794b3Sgavinm * and limitations under the License. 1220c794b3Sgavinm * 1320c794b3Sgavinm * When distributing Covered Code, include this CDDL HEADER in each 1420c794b3Sgavinm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1520c794b3Sgavinm * If applicable, add the following below this CDDL HEADER, with the 1620c794b3Sgavinm * fields enclosed by brackets "[]" replaced with your own identifying 1720c794b3Sgavinm * information: Portions Copyright [yyyy] [name of copyright owner] 1820c794b3Sgavinm * 1920c794b3Sgavinm * CDDL HEADER END 2020c794b3Sgavinm */ 2120c794b3Sgavinm 2220c794b3Sgavinm /* 232d2efdc6SVuong Nguyen * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 2420c794b3Sgavinm */ 25a3114836SGerry Liu /* 26a3114836SGerry Liu * Copyright (c) 2010, Intel Corporation. 27a3114836SGerry Liu * All rights reserved. 28a3114836SGerry Liu */ 2920c794b3Sgavinm 3020c794b3Sgavinm /* 3120c794b3Sgavinm * CPU Module Interface - hardware abstraction. 3220c794b3Sgavinm */ 3320c794b3Sgavinm 34349b53ddSStuart Maybee #ifdef __xpv 35349b53ddSStuart Maybee #include <sys/xpv_user.h> 36349b53ddSStuart Maybee #endif 37349b53ddSStuart Maybee 3820c794b3Sgavinm #include <sys/types.h> 3920c794b3Sgavinm #include <sys/cpu_module.h> 4020c794b3Sgavinm #include <sys/kmem.h> 4120c794b3Sgavinm #include <sys/x86_archext.h> 4220c794b3Sgavinm #include <sys/cpuvar.h> 4320c794b3Sgavinm #include <sys/ksynch.h> 4420c794b3Sgavinm #include <sys/x_call.h> 4520c794b3Sgavinm #include <sys/pghw.h> 465667185bSSrihari Venkatesan #include <sys/pci_cfgacc.h> 4720c794b3Sgavinm #include <sys/pci_cfgspace.h> 4820c794b3Sgavinm #include <sys/archsystm.h> 4920c794b3Sgavinm #include <sys/ontrap.h> 5020c794b3Sgavinm #include <sys/controlregs.h> 5120c794b3Sgavinm #include <sys/sunddi.h> 52e3d60c9bSAdrian Frost #include <sys/trap.h> 53e4b86885SCheng Sean Ye #include <sys/mca_x86.h> 54e4b86885SCheng Sean Ye #include <sys/processor.h> 55074bb90dSTom Pothier #include <sys/cmn_err.h> 56074bb90dSTom Pothier #include <sys/nvpair.h> 57074bb90dSTom Pothier #include <sys/fm/util.h> 58074bb90dSTom Pothier #include <sys/fm/protocol.h> 59074bb90dSTom Pothier #include <sys/fm/smb/fmsmb.h> 60074bb90dSTom Pothier #include <sys/cpu_module_impl.h> 61074bb90dSTom Pothier 62074bb90dSTom Pothier /* 63074bb90dSTom Pothier * Variable which determines if the SMBIOS supports x86 generic topology; or 64074bb90dSTom Pothier * if legacy topolgy enumeration will occur. 65074bb90dSTom Pothier */ 66074bb90dSTom Pothier extern int x86gentopo_legacy; 67e4b86885SCheng Sean Ye 6820c794b3Sgavinm /* 6920c794b3Sgavinm * Outside of this file consumers use the opaque cmi_hdl_t. This 7020c794b3Sgavinm * definition is duplicated in the generic_cpu mdb module, so keep 7120c794b3Sgavinm * them in-sync when making changes. 7220c794b3Sgavinm */ 7320c794b3Sgavinm typedef struct cmi_hdl_impl { 7420c794b3Sgavinm enum cmi_hdl_class cmih_class; /* Handle nature */ 75e4b86885SCheng Sean Ye const struct cmi_hdl_ops *cmih_ops; /* Operations vector */ 7620c794b3Sgavinm uint_t cmih_chipid; /* Chipid of cpu resource */ 778031591dSSrihari Venkatesan uint_t cmih_procnodeid; /* Nodeid of cpu resource */ 7820c794b3Sgavinm uint_t cmih_coreid; /* Core within die */ 7920c794b3Sgavinm uint_t cmih_strandid; /* Thread within core */ 808031591dSSrihari Venkatesan uint_t cmih_procnodes_per_pkg; /* Nodes in a processor */ 81e4b86885SCheng Sean Ye boolean_t cmih_mstrand; /* cores are multithreaded */ 8220c794b3Sgavinm volatile uint32_t *cmih_refcntp; /* Reference count pointer */ 8320c794b3Sgavinm uint64_t cmih_msrsrc; /* MSR data source flags */ 8420c794b3Sgavinm void *cmih_hdlpriv; /* cmi_hw.c private data */ 8520c794b3Sgavinm void *cmih_spec; /* cmi_hdl_{set,get}_specific */ 8620c794b3Sgavinm void *cmih_cmi; /* cpu mod control structure */ 8720c794b3Sgavinm void *cmih_cmidata; /* cpu mod private data */ 8820c794b3Sgavinm const struct cmi_mc_ops *cmih_mcops; /* Memory-controller ops */ 8920c794b3Sgavinm void *cmih_mcdata; /* Memory-controller data */ 90e4b86885SCheng Sean Ye uint64_t cmih_flags; /* See CMIH_F_* below */ 91074bb90dSTom Pothier uint16_t cmih_smbiosid; /* SMBIOS Type 4 struct ID */ 92074bb90dSTom Pothier uint_t cmih_smb_chipid; /* SMBIOS factored chipid */ 93074bb90dSTom Pothier nvlist_t *cmih_smb_bboard; /* SMBIOS bboard nvlist */ 9420c794b3Sgavinm } cmi_hdl_impl_t; 9520c794b3Sgavinm 9620c794b3Sgavinm #define IMPLHDL(ophdl) ((cmi_hdl_impl_t *)ophdl) 97e4b86885SCheng Sean Ye #define HDLOPS(hdl) ((hdl)->cmih_ops) 98e4b86885SCheng Sean Ye 99e4b86885SCheng Sean Ye #define CMIH_F_INJACTV 0x1ULL 100a3114836SGerry Liu #define CMIH_F_DEAD 0x2ULL 101e4b86885SCheng Sean Ye 102e4b86885SCheng Sean Ye /* 103e4b86885SCheng Sean Ye * Ops structure for handle operations. 104e4b86885SCheng Sean Ye */ 105e4b86885SCheng Sean Ye struct cmi_hdl_ops { 106e4b86885SCheng Sean Ye /* 107e4b86885SCheng Sean Ye * These ops are required in an implementation. 108e4b86885SCheng Sean Ye */ 109e4b86885SCheng Sean Ye uint_t (*cmio_vendor)(cmi_hdl_impl_t *); 110e4b86885SCheng Sean Ye const char *(*cmio_vendorstr)(cmi_hdl_impl_t *); 111e4b86885SCheng Sean Ye uint_t (*cmio_family)(cmi_hdl_impl_t *); 112e4b86885SCheng Sean Ye uint_t (*cmio_model)(cmi_hdl_impl_t *); 113e4b86885SCheng Sean Ye uint_t (*cmio_stepping)(cmi_hdl_impl_t *); 114e4b86885SCheng Sean Ye uint_t (*cmio_chipid)(cmi_hdl_impl_t *); 1158031591dSSrihari Venkatesan uint_t (*cmio_procnodeid)(cmi_hdl_impl_t *); 116e4b86885SCheng Sean Ye uint_t (*cmio_coreid)(cmi_hdl_impl_t *); 117e4b86885SCheng Sean Ye uint_t (*cmio_strandid)(cmi_hdl_impl_t *); 1188031591dSSrihari Venkatesan uint_t (*cmio_procnodes_per_pkg)(cmi_hdl_impl_t *); 119074bb90dSTom Pothier uint_t (*cmio_strand_apicid)(cmi_hdl_impl_t *); 120e4b86885SCheng Sean Ye uint32_t (*cmio_chiprev)(cmi_hdl_impl_t *); 121e4b86885SCheng Sean Ye const char *(*cmio_chiprevstr)(cmi_hdl_impl_t *); 122e4b86885SCheng Sean Ye uint32_t (*cmio_getsockettype)(cmi_hdl_impl_t *); 12389e921d5SKuriakose Kuruvilla const char *(*cmio_getsocketstr)(cmi_hdl_impl_t *); 12489e921d5SKuriakose Kuruvilla 125e4b86885SCheng Sean Ye id_t (*cmio_logical_id)(cmi_hdl_impl_t *); 126e4b86885SCheng Sean Ye /* 127e4b86885SCheng Sean Ye * These ops are optional in an implementation. 128e4b86885SCheng Sean Ye */ 129e4b86885SCheng Sean Ye ulong_t (*cmio_getcr4)(cmi_hdl_impl_t *); 130e4b86885SCheng Sean Ye void (*cmio_setcr4)(cmi_hdl_impl_t *, ulong_t); 131e4b86885SCheng Sean Ye cmi_errno_t (*cmio_rdmsr)(cmi_hdl_impl_t *, uint_t, uint64_t *); 132e4b86885SCheng Sean Ye cmi_errno_t (*cmio_wrmsr)(cmi_hdl_impl_t *, uint_t, uint64_t); 133e4b86885SCheng Sean Ye cmi_errno_t (*cmio_msrinterpose)(cmi_hdl_impl_t *, uint_t, uint64_t); 134e4b86885SCheng Sean Ye void (*cmio_int)(cmi_hdl_impl_t *, int); 135e4b86885SCheng Sean Ye int (*cmio_online)(cmi_hdl_impl_t *, int, int *); 136074bb90dSTom Pothier uint16_t (*cmio_smbiosid) (cmi_hdl_impl_t *); 137074bb90dSTom Pothier uint_t (*cmio_smb_chipid)(cmi_hdl_impl_t *); 138074bb90dSTom Pothier nvlist_t *(*cmio_smb_bboard)(cmi_hdl_impl_t *); 139e4b86885SCheng Sean Ye }; 140e4b86885SCheng Sean Ye 141e4b86885SCheng Sean Ye static const struct cmi_hdl_ops cmi_hdl_ops; 14220c794b3Sgavinm 14320c794b3Sgavinm /* 14420c794b3Sgavinm * Handles are looked up from contexts such as polling, injection etc 14520c794b3Sgavinm * where the context is reasonably well defined (although a poller could 14620c794b3Sgavinm * interrupt any old thread holding any old lock). They are also looked 14720c794b3Sgavinm * up by machine check handlers, which may strike at inconvenient times 14820c794b3Sgavinm * such as during handle initialization or destruction or during handle 14920c794b3Sgavinm * lookup (which the #MC handler itself will also have to perform). 15020c794b3Sgavinm * 15120c794b3Sgavinm * So keeping handles in a linked list makes locking difficult when we 1522d39cb4cSVuong Nguyen * consider #MC handlers. Our solution is to have a look-up table indexed 15320c794b3Sgavinm * by that which uniquely identifies a handle - chip/core/strand id - 1542d39cb4cSVuong Nguyen * with each entry a structure including a pointer to a handle 15520c794b3Sgavinm * structure for the resource, and a reference count for the handle. 15620c794b3Sgavinm * Reference counts are modified atomically. The public cmi_hdl_hold 15720c794b3Sgavinm * always succeeds because this can only be used after handle creation 158e4b86885SCheng Sean Ye * and before the call to destruct, so the hold count is already at least one. 15920c794b3Sgavinm * In other functions that lookup a handle (cmi_hdl_lookup, cmi_hdl_any) 16020c794b3Sgavinm * we must be certain that the count has not already decrmented to zero 16120c794b3Sgavinm * before applying our hold. 16220c794b3Sgavinm * 1632d39cb4cSVuong Nguyen * The table is an array of maximum number of chips defined in 1642d39cb4cSVuong Nguyen * CMI_CHIPID_ARR_SZ indexed by the chip id. If the chip is not present, the 1652d39cb4cSVuong Nguyen * entry is NULL. Each entry is a pointer to another array which contains a 1662d39cb4cSVuong Nguyen * list of all strands of the chip. This first level table is allocated when 1672d39cb4cSVuong Nguyen * first we want to populate an entry. The size of the latter (per chip) table 1682d39cb4cSVuong Nguyen * is CMI_MAX_STRANDS_PER_CHIP and it is populated when one of its cpus starts. 1692d39cb4cSVuong Nguyen * 1702d39cb4cSVuong Nguyen * Ideally we should only allocate to the actual number of chips, cores per 1712d39cb4cSVuong Nguyen * chip and strand per core. The number of chips is not available until all 1722d39cb4cSVuong Nguyen * of them are passed. The number of cores and strands are partially available. 1732d39cb4cSVuong Nguyen * For now we stick with the above approach. 17420c794b3Sgavinm */ 1752d39cb4cSVuong Nguyen #define CMI_MAX_CHIPID_NBITS 6 /* max chipid of 63 */ 1762d39cb4cSVuong Nguyen #define CMI_MAX_CORES_PER_CHIP_NBITS 4 /* 16 cores per chip max */ 1772d39cb4cSVuong Nguyen #define CMI_MAX_STRANDS_PER_CORE_NBITS 3 /* 8 strands per core max */ 178a3c46958Sgavinm 1792d39cb4cSVuong Nguyen #define CMI_MAX_CHIPID ((1 << (CMI_MAX_CHIPID_NBITS)) - 1) 1802d2efdc6SVuong Nguyen #define CMI_MAX_CORES_PER_CHIP(cbits) (1 << (cbits)) 1812d2efdc6SVuong Nguyen #define CMI_MAX_COREID(cbits) ((1 << (cbits)) - 1) 1822d2efdc6SVuong Nguyen #define CMI_MAX_STRANDS_PER_CORE(sbits) (1 << (sbits)) 1832d2efdc6SVuong Nguyen #define CMI_MAX_STRANDID(sbits) ((1 << (sbits)) - 1) 1842d2efdc6SVuong Nguyen #define CMI_MAX_STRANDS_PER_CHIP(cbits, sbits) \ 1852d2efdc6SVuong Nguyen (CMI_MAX_CORES_PER_CHIP(cbits) * CMI_MAX_STRANDS_PER_CORE(sbits)) 186a3c46958Sgavinm 1872d39cb4cSVuong Nguyen #define CMI_CHIPID_ARR_SZ (1 << CMI_MAX_CHIPID_NBITS) 18820c794b3Sgavinm 1892d39cb4cSVuong Nguyen typedef struct cmi_hdl_ent { 190a3c46958Sgavinm volatile uint32_t cmae_refcnt; 191a3c46958Sgavinm cmi_hdl_impl_t *cmae_hdlp; 1922d39cb4cSVuong Nguyen } cmi_hdl_ent_t; 19320c794b3Sgavinm 1942d39cb4cSVuong Nguyen static cmi_hdl_ent_t *cmi_chip_tab[CMI_CHIPID_ARR_SZ]; 19520c794b3Sgavinm 19620c794b3Sgavinm /* 1972d2efdc6SVuong Nguyen * Default values for the number of core and strand bits. 1982d2efdc6SVuong Nguyen */ 1992d2efdc6SVuong Nguyen uint_t cmi_core_nbits = CMI_MAX_CORES_PER_CHIP_NBITS; 2002d2efdc6SVuong Nguyen uint_t cmi_strand_nbits = CMI_MAX_STRANDS_PER_CORE_NBITS; 2012d2efdc6SVuong Nguyen static int cmi_ext_topo_check = 0; 2022d2efdc6SVuong Nguyen 2032d2efdc6SVuong Nguyen /* 20420c794b3Sgavinm * Controls where we will source PCI config space data. 20520c794b3Sgavinm */ 20620c794b3Sgavinm #define CMI_PCICFG_FLAG_RD_HWOK 0x0001 20720c794b3Sgavinm #define CMI_PCICFG_FLAG_RD_INTERPOSEOK 0X0002 20820c794b3Sgavinm #define CMI_PCICFG_FLAG_WR_HWOK 0x0004 20920c794b3Sgavinm #define CMI_PCICFG_FLAG_WR_INTERPOSEOK 0X0008 21020c794b3Sgavinm 21120c794b3Sgavinm static uint64_t cmi_pcicfg_flags = 21220c794b3Sgavinm CMI_PCICFG_FLAG_RD_HWOK | CMI_PCICFG_FLAG_RD_INTERPOSEOK | 21320c794b3Sgavinm CMI_PCICFG_FLAG_WR_HWOK | CMI_PCICFG_FLAG_WR_INTERPOSEOK; 21420c794b3Sgavinm 21520c794b3Sgavinm /* 21620c794b3Sgavinm * The flags for individual cpus are kept in their per-cpu handle cmih_msrsrc 21720c794b3Sgavinm */ 21820c794b3Sgavinm #define CMI_MSR_FLAG_RD_HWOK 0x0001 21920c794b3Sgavinm #define CMI_MSR_FLAG_RD_INTERPOSEOK 0x0002 22020c794b3Sgavinm #define CMI_MSR_FLAG_WR_HWOK 0x0004 22120c794b3Sgavinm #define CMI_MSR_FLAG_WR_INTERPOSEOK 0x0008 22220c794b3Sgavinm 22320c794b3Sgavinm int cmi_call_func_ntv_tries = 3; 22420c794b3Sgavinm 22520c794b3Sgavinm static cmi_errno_t 22620c794b3Sgavinm call_func_ntv(int cpuid, xc_func_t func, xc_arg_t arg1, xc_arg_t arg2) 22720c794b3Sgavinm { 22820c794b3Sgavinm cmi_errno_t rc = -1; 22920c794b3Sgavinm int i; 23020c794b3Sgavinm 23120c794b3Sgavinm kpreempt_disable(); 23220c794b3Sgavinm 23320c794b3Sgavinm if (CPU->cpu_id == cpuid) { 23420c794b3Sgavinm (*func)(arg1, arg2, (xc_arg_t)&rc); 23520c794b3Sgavinm } else { 23620c794b3Sgavinm /* 23720c794b3Sgavinm * This should not happen for a #MC trap or a poll, so 23820c794b3Sgavinm * this is likely an error injection or similar. 23920c794b3Sgavinm * We will try to cross call with xc_trycall - we 24020c794b3Sgavinm * can't guarantee success with xc_call because 24120c794b3Sgavinm * the interrupt code in the case of a #MC may 24220c794b3Sgavinm * already hold the xc mutex. 24320c794b3Sgavinm */ 24420c794b3Sgavinm for (i = 0; i < cmi_call_func_ntv_tries; i++) { 24520c794b3Sgavinm cpuset_t cpus; 24620c794b3Sgavinm 24720c794b3Sgavinm CPUSET_ONLY(cpus, cpuid); 248f34a7178SJoe Bonasera xc_priority(arg1, arg2, (xc_arg_t)&rc, 249f34a7178SJoe Bonasera CPUSET2BV(cpus), func); 25020c794b3Sgavinm if (rc != -1) 25120c794b3Sgavinm break; 25220c794b3Sgavinm 25320c794b3Sgavinm DELAY(1); 25420c794b3Sgavinm } 25520c794b3Sgavinm } 25620c794b3Sgavinm 25720c794b3Sgavinm kpreempt_enable(); 25820c794b3Sgavinm 25920c794b3Sgavinm return (rc != -1 ? rc : CMIERR_DEADLOCK); 26020c794b3Sgavinm } 26120c794b3Sgavinm 262e4b86885SCheng Sean Ye static uint64_t injcnt; 263e4b86885SCheng Sean Ye 264e4b86885SCheng Sean Ye void 265e4b86885SCheng Sean Ye cmi_hdl_inj_begin(cmi_hdl_t ophdl) 266e4b86885SCheng Sean Ye { 267e4b86885SCheng Sean Ye cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 268e4b86885SCheng Sean Ye 269e4b86885SCheng Sean Ye if (hdl != NULL) 270e4b86885SCheng Sean Ye hdl->cmih_flags |= CMIH_F_INJACTV; 271e4b86885SCheng Sean Ye if (injcnt++ == 0) { 272e4b86885SCheng Sean Ye cmn_err(CE_NOTE, "Hardware error injection/simulation " 273e4b86885SCheng Sean Ye "activity noted"); 274e4b86885SCheng Sean Ye } 275e4b86885SCheng Sean Ye } 276e4b86885SCheng Sean Ye 277e4b86885SCheng Sean Ye void 278e4b86885SCheng Sean Ye cmi_hdl_inj_end(cmi_hdl_t ophdl) 279e4b86885SCheng Sean Ye { 280e4b86885SCheng Sean Ye cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 281e4b86885SCheng Sean Ye 282e4b86885SCheng Sean Ye ASSERT(hdl == NULL || hdl->cmih_flags & CMIH_F_INJACTV); 283e4b86885SCheng Sean Ye if (hdl != NULL) 284e4b86885SCheng Sean Ye hdl->cmih_flags &= ~CMIH_F_INJACTV; 285e4b86885SCheng Sean Ye } 286e4b86885SCheng Sean Ye 287e4b86885SCheng Sean Ye boolean_t 288e4b86885SCheng Sean Ye cmi_inj_tainted(void) 289e4b86885SCheng Sean Ye { 290e4b86885SCheng Sean Ye return (injcnt != 0 ? B_TRUE : B_FALSE); 291e4b86885SCheng Sean Ye } 292e4b86885SCheng Sean Ye 29320c794b3Sgavinm /* 29420c794b3Sgavinm * ======================================================= 29520c794b3Sgavinm * | MSR Interposition | 29620c794b3Sgavinm * | ----------------- | 29720c794b3Sgavinm * | | 29820c794b3Sgavinm * ------------------------------------------------------- 29920c794b3Sgavinm */ 30020c794b3Sgavinm 30120c794b3Sgavinm #define CMI_MSRI_HASHSZ 16 30220c794b3Sgavinm #define CMI_MSRI_HASHIDX(hdl, msr) \ 30320c794b3Sgavinm (((uintptr_t)(hdl) >> 3 + (msr)) % (CMI_MSRI_HASHSZ - 1)) 30420c794b3Sgavinm 30520c794b3Sgavinm struct cmi_msri_bkt { 30620c794b3Sgavinm kmutex_t msrib_lock; 30720c794b3Sgavinm struct cmi_msri_hashent *msrib_head; 30820c794b3Sgavinm }; 30920c794b3Sgavinm 31020c794b3Sgavinm struct cmi_msri_hashent { 31120c794b3Sgavinm struct cmi_msri_hashent *msrie_next; 31220c794b3Sgavinm struct cmi_msri_hashent *msrie_prev; 31320c794b3Sgavinm cmi_hdl_impl_t *msrie_hdl; 31420c794b3Sgavinm uint_t msrie_msrnum; 31520c794b3Sgavinm uint64_t msrie_msrval; 31620c794b3Sgavinm }; 31720c794b3Sgavinm 31820c794b3Sgavinm #define CMI_MSRI_MATCH(ent, hdl, req_msr) \ 31920c794b3Sgavinm ((ent)->msrie_hdl == (hdl) && (ent)->msrie_msrnum == (req_msr)) 32020c794b3Sgavinm 32120c794b3Sgavinm static struct cmi_msri_bkt msrihash[CMI_MSRI_HASHSZ]; 32220c794b3Sgavinm 32320c794b3Sgavinm static void 324e4b86885SCheng Sean Ye msri_addent(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val) 32520c794b3Sgavinm { 326e4b86885SCheng Sean Ye int idx = CMI_MSRI_HASHIDX(hdl, msr); 32720c794b3Sgavinm struct cmi_msri_bkt *hbp = &msrihash[idx]; 32820c794b3Sgavinm struct cmi_msri_hashent *hep; 32920c794b3Sgavinm 33020c794b3Sgavinm mutex_enter(&hbp->msrib_lock); 33120c794b3Sgavinm 33220c794b3Sgavinm for (hep = hbp->msrib_head; hep != NULL; hep = hep->msrie_next) { 333e4b86885SCheng Sean Ye if (CMI_MSRI_MATCH(hep, hdl, msr)) 33420c794b3Sgavinm break; 33520c794b3Sgavinm } 33620c794b3Sgavinm 33720c794b3Sgavinm if (hep != NULL) { 338e4b86885SCheng Sean Ye hep->msrie_msrval = val; 33920c794b3Sgavinm } else { 34020c794b3Sgavinm hep = kmem_alloc(sizeof (*hep), KM_SLEEP); 34120c794b3Sgavinm hep->msrie_hdl = hdl; 342e4b86885SCheng Sean Ye hep->msrie_msrnum = msr; 343e4b86885SCheng Sean Ye hep->msrie_msrval = val; 34420c794b3Sgavinm 34520c794b3Sgavinm if (hbp->msrib_head != NULL) 34620c794b3Sgavinm hbp->msrib_head->msrie_prev = hep; 34720c794b3Sgavinm hep->msrie_next = hbp->msrib_head; 34820c794b3Sgavinm hep->msrie_prev = NULL; 34920c794b3Sgavinm hbp->msrib_head = hep; 35020c794b3Sgavinm } 35120c794b3Sgavinm 35220c794b3Sgavinm mutex_exit(&hbp->msrib_lock); 35320c794b3Sgavinm } 35420c794b3Sgavinm 35520c794b3Sgavinm /* 35620c794b3Sgavinm * Look for a match for the given hanlde and msr. Return 1 with valp 35720c794b3Sgavinm * filled if a match is found, otherwise return 0 with valp untouched. 35820c794b3Sgavinm */ 35920c794b3Sgavinm static int 36020c794b3Sgavinm msri_lookup(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t *valp) 36120c794b3Sgavinm { 36220c794b3Sgavinm int idx = CMI_MSRI_HASHIDX(hdl, msr); 36320c794b3Sgavinm struct cmi_msri_bkt *hbp = &msrihash[idx]; 36420c794b3Sgavinm struct cmi_msri_hashent *hep; 36520c794b3Sgavinm 36620c794b3Sgavinm /* 36720c794b3Sgavinm * This function is called during #MC trap handling, so we should 36820c794b3Sgavinm * consider the possibility that the hash mutex is held by the 36920c794b3Sgavinm * interrupted thread. This should not happen because interposition 37020c794b3Sgavinm * is an artificial injection mechanism and the #MC is requested 37120c794b3Sgavinm * after adding entries, but just in case of a real #MC at an 37220c794b3Sgavinm * unlucky moment we'll use mutex_tryenter here. 37320c794b3Sgavinm */ 37420c794b3Sgavinm if (!mutex_tryenter(&hbp->msrib_lock)) 37520c794b3Sgavinm return (0); 37620c794b3Sgavinm 37720c794b3Sgavinm for (hep = hbp->msrib_head; hep != NULL; hep = hep->msrie_next) { 37820c794b3Sgavinm if (CMI_MSRI_MATCH(hep, hdl, msr)) { 37920c794b3Sgavinm *valp = hep->msrie_msrval; 38020c794b3Sgavinm break; 38120c794b3Sgavinm } 38220c794b3Sgavinm } 38320c794b3Sgavinm 38420c794b3Sgavinm mutex_exit(&hbp->msrib_lock); 38520c794b3Sgavinm 38620c794b3Sgavinm return (hep != NULL); 38720c794b3Sgavinm } 38820c794b3Sgavinm 38920c794b3Sgavinm /* 39020c794b3Sgavinm * Remove any interposed value that matches. 39120c794b3Sgavinm */ 39220c794b3Sgavinm static void 39320c794b3Sgavinm msri_rment(cmi_hdl_impl_t *hdl, uint_t msr) 39420c794b3Sgavinm { 39520c794b3Sgavinm 39620c794b3Sgavinm int idx = CMI_MSRI_HASHIDX(hdl, msr); 39720c794b3Sgavinm struct cmi_msri_bkt *hbp = &msrihash[idx]; 39820c794b3Sgavinm struct cmi_msri_hashent *hep; 39920c794b3Sgavinm 40020c794b3Sgavinm if (!mutex_tryenter(&hbp->msrib_lock)) 40120c794b3Sgavinm return; 40220c794b3Sgavinm 40320c794b3Sgavinm for (hep = hbp->msrib_head; hep != NULL; hep = hep->msrie_next) { 40420c794b3Sgavinm if (CMI_MSRI_MATCH(hep, hdl, msr)) { 40520c794b3Sgavinm if (hep->msrie_prev != NULL) 40620c794b3Sgavinm hep->msrie_prev->msrie_next = hep->msrie_next; 40720c794b3Sgavinm 40820c794b3Sgavinm if (hep->msrie_next != NULL) 40920c794b3Sgavinm hep->msrie_next->msrie_prev = hep->msrie_prev; 41020c794b3Sgavinm 41120c794b3Sgavinm if (hbp->msrib_head == hep) 41220c794b3Sgavinm hbp->msrib_head = hep->msrie_next; 41320c794b3Sgavinm 41420c794b3Sgavinm kmem_free(hep, sizeof (*hep)); 41520c794b3Sgavinm break; 41620c794b3Sgavinm } 41720c794b3Sgavinm } 41820c794b3Sgavinm 41920c794b3Sgavinm mutex_exit(&hbp->msrib_lock); 42020c794b3Sgavinm } 42120c794b3Sgavinm 42220c794b3Sgavinm /* 42320c794b3Sgavinm * ======================================================= 42420c794b3Sgavinm * | PCI Config Space Interposition | 42520c794b3Sgavinm * | ------------------------------ | 42620c794b3Sgavinm * | | 42720c794b3Sgavinm * ------------------------------------------------------- 42820c794b3Sgavinm */ 42920c794b3Sgavinm 43020c794b3Sgavinm /* 43120c794b3Sgavinm * Hash for interposed PCI config space values. We lookup on bus/dev/fun/offset 43220c794b3Sgavinm * and then record whether the value stashed was made with a byte, word or 43320c794b3Sgavinm * doubleword access; we will only return a hit for an access of the 43420c794b3Sgavinm * same size. If you access say a 32-bit register using byte accesses 43520c794b3Sgavinm * and then attempt to read the full 32-bit value back you will not obtain 43620c794b3Sgavinm * any sort of merged result - you get a lookup miss. 43720c794b3Sgavinm */ 43820c794b3Sgavinm 43920c794b3Sgavinm #define CMI_PCII_HASHSZ 16 44020c794b3Sgavinm #define CMI_PCII_HASHIDX(b, d, f, o) \ 44120c794b3Sgavinm (((b) + (d) + (f) + (o)) % (CMI_PCII_HASHSZ - 1)) 44220c794b3Sgavinm 44320c794b3Sgavinm struct cmi_pcii_bkt { 44420c794b3Sgavinm kmutex_t pciib_lock; 44520c794b3Sgavinm struct cmi_pcii_hashent *pciib_head; 44620c794b3Sgavinm }; 44720c794b3Sgavinm 44820c794b3Sgavinm struct cmi_pcii_hashent { 44920c794b3Sgavinm struct cmi_pcii_hashent *pcii_next; 45020c794b3Sgavinm struct cmi_pcii_hashent *pcii_prev; 45120c794b3Sgavinm int pcii_bus; 45220c794b3Sgavinm int pcii_dev; 45320c794b3Sgavinm int pcii_func; 45420c794b3Sgavinm int pcii_reg; 45520c794b3Sgavinm int pcii_asize; 45620c794b3Sgavinm uint32_t pcii_val; 45720c794b3Sgavinm }; 45820c794b3Sgavinm 45920c794b3Sgavinm #define CMI_PCII_MATCH(ent, b, d, f, r, asz) \ 46020c794b3Sgavinm ((ent)->pcii_bus == (b) && (ent)->pcii_dev == (d) && \ 46120c794b3Sgavinm (ent)->pcii_func == (f) && (ent)->pcii_reg == (r) && \ 46220c794b3Sgavinm (ent)->pcii_asize == (asz)) 46320c794b3Sgavinm 46420c794b3Sgavinm static struct cmi_pcii_bkt pciihash[CMI_PCII_HASHSZ]; 46520c794b3Sgavinm 46620c794b3Sgavinm 46720c794b3Sgavinm /* 46820c794b3Sgavinm * Add a new entry to the PCI interpose hash, overwriting any existing 46920c794b3Sgavinm * entry that is found. 47020c794b3Sgavinm */ 47120c794b3Sgavinm static void 47220c794b3Sgavinm pcii_addent(int bus, int dev, int func, int reg, uint32_t val, int asz) 47320c794b3Sgavinm { 47420c794b3Sgavinm int idx = CMI_PCII_HASHIDX(bus, dev, func, reg); 47520c794b3Sgavinm struct cmi_pcii_bkt *hbp = &pciihash[idx]; 47620c794b3Sgavinm struct cmi_pcii_hashent *hep; 47720c794b3Sgavinm 478e4b86885SCheng Sean Ye cmi_hdl_inj_begin(NULL); 479e4b86885SCheng Sean Ye 48020c794b3Sgavinm mutex_enter(&hbp->pciib_lock); 48120c794b3Sgavinm 48220c794b3Sgavinm for (hep = hbp->pciib_head; hep != NULL; hep = hep->pcii_next) { 48320c794b3Sgavinm if (CMI_PCII_MATCH(hep, bus, dev, func, reg, asz)) 48420c794b3Sgavinm break; 48520c794b3Sgavinm } 48620c794b3Sgavinm 48720c794b3Sgavinm if (hep != NULL) { 48820c794b3Sgavinm hep->pcii_val = val; 48920c794b3Sgavinm } else { 49020c794b3Sgavinm hep = kmem_alloc(sizeof (*hep), KM_SLEEP); 49120c794b3Sgavinm hep->pcii_bus = bus; 49220c794b3Sgavinm hep->pcii_dev = dev; 49320c794b3Sgavinm hep->pcii_func = func; 49420c794b3Sgavinm hep->pcii_reg = reg; 49520c794b3Sgavinm hep->pcii_asize = asz; 49620c794b3Sgavinm hep->pcii_val = val; 49720c794b3Sgavinm 49820c794b3Sgavinm if (hbp->pciib_head != NULL) 49920c794b3Sgavinm hbp->pciib_head->pcii_prev = hep; 50020c794b3Sgavinm hep->pcii_next = hbp->pciib_head; 50120c794b3Sgavinm hep->pcii_prev = NULL; 50220c794b3Sgavinm hbp->pciib_head = hep; 50320c794b3Sgavinm } 50420c794b3Sgavinm 50520c794b3Sgavinm mutex_exit(&hbp->pciib_lock); 506e4b86885SCheng Sean Ye 507e4b86885SCheng Sean Ye cmi_hdl_inj_end(NULL); 50820c794b3Sgavinm } 50920c794b3Sgavinm 51020c794b3Sgavinm /* 51120c794b3Sgavinm * Look for a match for the given bus/dev/func/reg; return 1 with valp 51220c794b3Sgavinm * filled if a match is found, otherwise return 0 with valp untouched. 51320c794b3Sgavinm */ 51420c794b3Sgavinm static int 51520c794b3Sgavinm pcii_lookup(int bus, int dev, int func, int reg, int asz, uint32_t *valp) 51620c794b3Sgavinm { 51720c794b3Sgavinm int idx = CMI_PCII_HASHIDX(bus, dev, func, reg); 51820c794b3Sgavinm struct cmi_pcii_bkt *hbp = &pciihash[idx]; 51920c794b3Sgavinm struct cmi_pcii_hashent *hep; 52020c794b3Sgavinm 52120c794b3Sgavinm if (!mutex_tryenter(&hbp->pciib_lock)) 52220c794b3Sgavinm return (0); 52320c794b3Sgavinm 52420c794b3Sgavinm for (hep = hbp->pciib_head; hep != NULL; hep = hep->pcii_next) { 52520c794b3Sgavinm if (CMI_PCII_MATCH(hep, bus, dev, func, reg, asz)) { 52620c794b3Sgavinm *valp = hep->pcii_val; 52720c794b3Sgavinm break; 52820c794b3Sgavinm } 52920c794b3Sgavinm } 53020c794b3Sgavinm 53120c794b3Sgavinm mutex_exit(&hbp->pciib_lock); 53220c794b3Sgavinm 53320c794b3Sgavinm return (hep != NULL); 53420c794b3Sgavinm } 53520c794b3Sgavinm 53620c794b3Sgavinm static void 53720c794b3Sgavinm pcii_rment(int bus, int dev, int func, int reg, int asz) 53820c794b3Sgavinm { 53920c794b3Sgavinm int idx = CMI_PCII_HASHIDX(bus, dev, func, reg); 54020c794b3Sgavinm struct cmi_pcii_bkt *hbp = &pciihash[idx]; 54120c794b3Sgavinm struct cmi_pcii_hashent *hep; 54220c794b3Sgavinm 54320c794b3Sgavinm mutex_enter(&hbp->pciib_lock); 54420c794b3Sgavinm 54520c794b3Sgavinm for (hep = hbp->pciib_head; hep != NULL; hep = hep->pcii_next) { 54620c794b3Sgavinm if (CMI_PCII_MATCH(hep, bus, dev, func, reg, asz)) { 54720c794b3Sgavinm if (hep->pcii_prev != NULL) 54820c794b3Sgavinm hep->pcii_prev->pcii_next = hep->pcii_next; 54920c794b3Sgavinm 55020c794b3Sgavinm if (hep->pcii_next != NULL) 55120c794b3Sgavinm hep->pcii_next->pcii_prev = hep->pcii_prev; 55220c794b3Sgavinm 55320c794b3Sgavinm if (hbp->pciib_head == hep) 55420c794b3Sgavinm hbp->pciib_head = hep->pcii_next; 55520c794b3Sgavinm 55620c794b3Sgavinm kmem_free(hep, sizeof (*hep)); 55720c794b3Sgavinm break; 55820c794b3Sgavinm } 55920c794b3Sgavinm } 56020c794b3Sgavinm 56120c794b3Sgavinm mutex_exit(&hbp->pciib_lock); 56220c794b3Sgavinm } 56320c794b3Sgavinm 564e4b86885SCheng Sean Ye #ifndef __xpv 565e4b86885SCheng Sean Ye 56620c794b3Sgavinm /* 56720c794b3Sgavinm * ======================================================= 56820c794b3Sgavinm * | Native methods | 56920c794b3Sgavinm * | -------------- | 57020c794b3Sgavinm * | | 57120c794b3Sgavinm * | These are used when we are running native on bare- | 57220c794b3Sgavinm * | metal, or simply don't know any better. | 57320c794b3Sgavinm * --------------------------------------------------------- 57420c794b3Sgavinm */ 57520c794b3Sgavinm 576e4b86885SCheng Sean Ye #define HDLPRIV(hdl) ((cpu_t *)(hdl)->cmih_hdlpriv) 577e4b86885SCheng Sean Ye 57820c794b3Sgavinm static uint_t 57920c794b3Sgavinm ntv_vendor(cmi_hdl_impl_t *hdl) 58020c794b3Sgavinm { 581e4b86885SCheng Sean Ye return (cpuid_getvendor(HDLPRIV(hdl))); 58220c794b3Sgavinm } 58320c794b3Sgavinm 58420c794b3Sgavinm static const char * 58520c794b3Sgavinm ntv_vendorstr(cmi_hdl_impl_t *hdl) 58620c794b3Sgavinm { 587e4b86885SCheng Sean Ye return (cpuid_getvendorstr(HDLPRIV(hdl))); 58820c794b3Sgavinm } 58920c794b3Sgavinm 59020c794b3Sgavinm static uint_t 59120c794b3Sgavinm ntv_family(cmi_hdl_impl_t *hdl) 59220c794b3Sgavinm { 593e4b86885SCheng Sean Ye return (cpuid_getfamily(HDLPRIV(hdl))); 59420c794b3Sgavinm } 59520c794b3Sgavinm 59620c794b3Sgavinm static uint_t 59720c794b3Sgavinm ntv_model(cmi_hdl_impl_t *hdl) 59820c794b3Sgavinm { 599e4b86885SCheng Sean Ye return (cpuid_getmodel(HDLPRIV(hdl))); 60020c794b3Sgavinm } 60120c794b3Sgavinm 60220c794b3Sgavinm static uint_t 60320c794b3Sgavinm ntv_stepping(cmi_hdl_impl_t *hdl) 60420c794b3Sgavinm { 605e4b86885SCheng Sean Ye return (cpuid_getstep(HDLPRIV(hdl))); 60620c794b3Sgavinm } 60720c794b3Sgavinm 60820c794b3Sgavinm static uint_t 60920c794b3Sgavinm ntv_chipid(cmi_hdl_impl_t *hdl) 61020c794b3Sgavinm { 61120c794b3Sgavinm return (hdl->cmih_chipid); 61220c794b3Sgavinm 61320c794b3Sgavinm } 61420c794b3Sgavinm 61520c794b3Sgavinm static uint_t 6168031591dSSrihari Venkatesan ntv_procnodeid(cmi_hdl_impl_t *hdl) 6178031591dSSrihari Venkatesan { 6188031591dSSrihari Venkatesan return (hdl->cmih_procnodeid); 6198031591dSSrihari Venkatesan } 6208031591dSSrihari Venkatesan 6218031591dSSrihari Venkatesan static uint_t 6228031591dSSrihari Venkatesan ntv_procnodes_per_pkg(cmi_hdl_impl_t *hdl) 6238031591dSSrihari Venkatesan { 6248031591dSSrihari Venkatesan return (hdl->cmih_procnodes_per_pkg); 6258031591dSSrihari Venkatesan } 6268031591dSSrihari Venkatesan 6278031591dSSrihari Venkatesan static uint_t 62820c794b3Sgavinm ntv_coreid(cmi_hdl_impl_t *hdl) 62920c794b3Sgavinm { 63020c794b3Sgavinm return (hdl->cmih_coreid); 63120c794b3Sgavinm } 63220c794b3Sgavinm 63320c794b3Sgavinm static uint_t 63420c794b3Sgavinm ntv_strandid(cmi_hdl_impl_t *hdl) 63520c794b3Sgavinm { 63620c794b3Sgavinm return (hdl->cmih_strandid); 63720c794b3Sgavinm } 63820c794b3Sgavinm 639074bb90dSTom Pothier static uint_t 640074bb90dSTom Pothier ntv_strand_apicid(cmi_hdl_impl_t *hdl) 641074bb90dSTom Pothier { 642074bb90dSTom Pothier return (cpuid_get_apicid(HDLPRIV(hdl))); 643074bb90dSTom Pothier } 644074bb90dSTom Pothier 645074bb90dSTom Pothier static uint16_t 646074bb90dSTom Pothier ntv_smbiosid(cmi_hdl_impl_t *hdl) 647074bb90dSTom Pothier { 648074bb90dSTom Pothier return (hdl->cmih_smbiosid); 649074bb90dSTom Pothier } 650074bb90dSTom Pothier 651074bb90dSTom Pothier static uint_t 652074bb90dSTom Pothier ntv_smb_chipid(cmi_hdl_impl_t *hdl) 653074bb90dSTom Pothier { 654074bb90dSTom Pothier return (hdl->cmih_smb_chipid); 655074bb90dSTom Pothier } 656074bb90dSTom Pothier 657074bb90dSTom Pothier static nvlist_t * 658074bb90dSTom Pothier ntv_smb_bboard(cmi_hdl_impl_t *hdl) 659074bb90dSTom Pothier { 660074bb90dSTom Pothier return (hdl->cmih_smb_bboard); 661074bb90dSTom Pothier } 662074bb90dSTom Pothier 66320c794b3Sgavinm static uint32_t 66420c794b3Sgavinm ntv_chiprev(cmi_hdl_impl_t *hdl) 66520c794b3Sgavinm { 666e4b86885SCheng Sean Ye return (cpuid_getchiprev(HDLPRIV(hdl))); 66720c794b3Sgavinm } 66820c794b3Sgavinm 66920c794b3Sgavinm static const char * 67020c794b3Sgavinm ntv_chiprevstr(cmi_hdl_impl_t *hdl) 67120c794b3Sgavinm { 672e4b86885SCheng Sean Ye return (cpuid_getchiprevstr(HDLPRIV(hdl))); 67320c794b3Sgavinm } 67420c794b3Sgavinm 67520c794b3Sgavinm static uint32_t 67620c794b3Sgavinm ntv_getsockettype(cmi_hdl_impl_t *hdl) 67720c794b3Sgavinm { 678e4b86885SCheng Sean Ye return (cpuid_getsockettype(HDLPRIV(hdl))); 679e4b86885SCheng Sean Ye } 680e4b86885SCheng Sean Ye 68189e921d5SKuriakose Kuruvilla static const char * 68289e921d5SKuriakose Kuruvilla ntv_getsocketstr(cmi_hdl_impl_t *hdl) 68389e921d5SKuriakose Kuruvilla { 68489e921d5SKuriakose Kuruvilla return (cpuid_getsocketstr(HDLPRIV(hdl))); 68589e921d5SKuriakose Kuruvilla } 68689e921d5SKuriakose Kuruvilla 687e4b86885SCheng Sean Ye static id_t 688e4b86885SCheng Sean Ye ntv_logical_id(cmi_hdl_impl_t *hdl) 689e4b86885SCheng Sean Ye { 690e4b86885SCheng Sean Ye return (HDLPRIV(hdl)->cpu_id); 69120c794b3Sgavinm } 69220c794b3Sgavinm 69320c794b3Sgavinm /*ARGSUSED*/ 69420c794b3Sgavinm static int 69520c794b3Sgavinm ntv_getcr4_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3) 69620c794b3Sgavinm { 69720c794b3Sgavinm ulong_t *dest = (ulong_t *)arg1; 69820c794b3Sgavinm cmi_errno_t *rcp = (cmi_errno_t *)arg3; 69920c794b3Sgavinm 70020c794b3Sgavinm *dest = getcr4(); 70120c794b3Sgavinm *rcp = CMI_SUCCESS; 70220c794b3Sgavinm 70320c794b3Sgavinm return (0); 70420c794b3Sgavinm } 70520c794b3Sgavinm 70620c794b3Sgavinm static ulong_t 70720c794b3Sgavinm ntv_getcr4(cmi_hdl_impl_t *hdl) 70820c794b3Sgavinm { 709e4b86885SCheng Sean Ye cpu_t *cp = HDLPRIV(hdl); 71020c794b3Sgavinm ulong_t val; 71120c794b3Sgavinm 71220c794b3Sgavinm (void) call_func_ntv(cp->cpu_id, ntv_getcr4_xc, (xc_arg_t)&val, NULL); 71320c794b3Sgavinm 71420c794b3Sgavinm return (val); 71520c794b3Sgavinm } 71620c794b3Sgavinm 71720c794b3Sgavinm /*ARGSUSED*/ 71820c794b3Sgavinm static int 71920c794b3Sgavinm ntv_setcr4_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3) 72020c794b3Sgavinm { 72120c794b3Sgavinm ulong_t val = (ulong_t)arg1; 72220c794b3Sgavinm cmi_errno_t *rcp = (cmi_errno_t *)arg3; 72320c794b3Sgavinm 72420c794b3Sgavinm setcr4(val); 72520c794b3Sgavinm *rcp = CMI_SUCCESS; 72620c794b3Sgavinm 72720c794b3Sgavinm return (0); 72820c794b3Sgavinm } 72920c794b3Sgavinm 73020c794b3Sgavinm static void 73120c794b3Sgavinm ntv_setcr4(cmi_hdl_impl_t *hdl, ulong_t val) 73220c794b3Sgavinm { 733e4b86885SCheng Sean Ye cpu_t *cp = HDLPRIV(hdl); 73420c794b3Sgavinm 73520c794b3Sgavinm (void) call_func_ntv(cp->cpu_id, ntv_setcr4_xc, (xc_arg_t)val, NULL); 73620c794b3Sgavinm } 73720c794b3Sgavinm 738a4e4e13fSgavinm volatile uint32_t cmi_trapped_rdmsr; 739a4e4e13fSgavinm 74020c794b3Sgavinm /*ARGSUSED*/ 74120c794b3Sgavinm static int 74220c794b3Sgavinm ntv_rdmsr_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3) 74320c794b3Sgavinm { 74420c794b3Sgavinm uint_t msr = (uint_t)arg1; 74520c794b3Sgavinm uint64_t *valp = (uint64_t *)arg2; 74620c794b3Sgavinm cmi_errno_t *rcp = (cmi_errno_t *)arg3; 74720c794b3Sgavinm 74820c794b3Sgavinm on_trap_data_t otd; 74920c794b3Sgavinm 75020c794b3Sgavinm if (on_trap(&otd, OT_DATA_ACCESS) == 0) { 75120c794b3Sgavinm if (checked_rdmsr(msr, valp) == 0) 75220c794b3Sgavinm *rcp = CMI_SUCCESS; 75320c794b3Sgavinm else 75420c794b3Sgavinm *rcp = CMIERR_NOTSUP; 75520c794b3Sgavinm } else { 75620c794b3Sgavinm *rcp = CMIERR_MSRGPF; 757a4e4e13fSgavinm atomic_inc_32(&cmi_trapped_rdmsr); 75820c794b3Sgavinm } 75920c794b3Sgavinm no_trap(); 76020c794b3Sgavinm 76120c794b3Sgavinm return (0); 76220c794b3Sgavinm } 76320c794b3Sgavinm 76420c794b3Sgavinm static cmi_errno_t 76520c794b3Sgavinm ntv_rdmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t *valp) 76620c794b3Sgavinm { 767e4b86885SCheng Sean Ye cpu_t *cp = HDLPRIV(hdl); 768e4b86885SCheng Sean Ye 769e4b86885SCheng Sean Ye if (!(hdl->cmih_msrsrc & CMI_MSR_FLAG_RD_HWOK)) 770e4b86885SCheng Sean Ye return (CMIERR_INTERPOSE); 77120c794b3Sgavinm 77220c794b3Sgavinm return (call_func_ntv(cp->cpu_id, ntv_rdmsr_xc, 77320c794b3Sgavinm (xc_arg_t)msr, (xc_arg_t)valp)); 77420c794b3Sgavinm } 77520c794b3Sgavinm 776a4e4e13fSgavinm volatile uint32_t cmi_trapped_wrmsr; 777a4e4e13fSgavinm 77820c794b3Sgavinm /*ARGSUSED*/ 77920c794b3Sgavinm static int 78020c794b3Sgavinm ntv_wrmsr_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3) 78120c794b3Sgavinm { 78220c794b3Sgavinm uint_t msr = (uint_t)arg1; 78320c794b3Sgavinm uint64_t val = *((uint64_t *)arg2); 78420c794b3Sgavinm cmi_errno_t *rcp = (cmi_errno_t *)arg3; 78520c794b3Sgavinm on_trap_data_t otd; 78620c794b3Sgavinm 78720c794b3Sgavinm if (on_trap(&otd, OT_DATA_ACCESS) == 0) { 78820c794b3Sgavinm if (checked_wrmsr(msr, val) == 0) 78920c794b3Sgavinm *rcp = CMI_SUCCESS; 79020c794b3Sgavinm else 79120c794b3Sgavinm *rcp = CMIERR_NOTSUP; 79220c794b3Sgavinm } else { 79320c794b3Sgavinm *rcp = CMIERR_MSRGPF; 794a4e4e13fSgavinm atomic_inc_32(&cmi_trapped_wrmsr); 79520c794b3Sgavinm } 79620c794b3Sgavinm no_trap(); 79720c794b3Sgavinm 79820c794b3Sgavinm return (0); 79920c794b3Sgavinm 80020c794b3Sgavinm } 80120c794b3Sgavinm 80220c794b3Sgavinm static cmi_errno_t 80320c794b3Sgavinm ntv_wrmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val) 80420c794b3Sgavinm { 805e4b86885SCheng Sean Ye cpu_t *cp = HDLPRIV(hdl); 806e4b86885SCheng Sean Ye 807e4b86885SCheng Sean Ye if (!(hdl->cmih_msrsrc & CMI_MSR_FLAG_WR_HWOK)) 808e4b86885SCheng Sean Ye return (CMI_SUCCESS); 80920c794b3Sgavinm 81020c794b3Sgavinm return (call_func_ntv(cp->cpu_id, ntv_wrmsr_xc, 81120c794b3Sgavinm (xc_arg_t)msr, (xc_arg_t)&val)); 81220c794b3Sgavinm } 81320c794b3Sgavinm 814e4b86885SCheng Sean Ye static cmi_errno_t 815e4b86885SCheng Sean Ye ntv_msrinterpose(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val) 816e4b86885SCheng Sean Ye { 817e4b86885SCheng Sean Ye msri_addent(hdl, msr, val); 818e4b86885SCheng Sean Ye return (CMI_SUCCESS); 819e4b86885SCheng Sean Ye } 820e4b86885SCheng Sean Ye 82120c794b3Sgavinm /*ARGSUSED*/ 82220c794b3Sgavinm static int 823e3d60c9bSAdrian Frost ntv_int_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3) 82420c794b3Sgavinm { 82520c794b3Sgavinm cmi_errno_t *rcp = (cmi_errno_t *)arg3; 826e3d60c9bSAdrian Frost int int_no = (int)arg1; 82720c794b3Sgavinm 828e3d60c9bSAdrian Frost if (int_no == T_MCE) 82920c794b3Sgavinm int18(); 830e3d60c9bSAdrian Frost else 831e3d60c9bSAdrian Frost int_cmci(); 83220c794b3Sgavinm *rcp = CMI_SUCCESS; 83320c794b3Sgavinm 83420c794b3Sgavinm return (0); 83520c794b3Sgavinm } 83620c794b3Sgavinm 83720c794b3Sgavinm static void 838e3d60c9bSAdrian Frost ntv_int(cmi_hdl_impl_t *hdl, int int_no) 83920c794b3Sgavinm { 840e4b86885SCheng Sean Ye cpu_t *cp = HDLPRIV(hdl); 84120c794b3Sgavinm 842e3d60c9bSAdrian Frost (void) call_func_ntv(cp->cpu_id, ntv_int_xc, (xc_arg_t)int_no, NULL); 84320c794b3Sgavinm } 84420c794b3Sgavinm 845e4b86885SCheng Sean Ye static int 846e4b86885SCheng Sean Ye ntv_online(cmi_hdl_impl_t *hdl, int new_status, int *old_status) 84720c794b3Sgavinm { 848a3114836SGerry Liu int rc; 849e4b86885SCheng Sean Ye processorid_t cpuid = HDLPRIV(hdl)->cpu_id; 850e4b86885SCheng Sean Ye 851a3114836SGerry Liu while (mutex_tryenter(&cpu_lock) == 0) { 852a3114836SGerry Liu if (hdl->cmih_flags & CMIH_F_DEAD) 853a3114836SGerry Liu return (EBUSY); 854a3114836SGerry Liu delay(1); 855a3114836SGerry Liu } 856a3114836SGerry Liu rc = p_online_internal_locked(cpuid, new_status, old_status); 857a3114836SGerry Liu mutex_exit(&cpu_lock); 858a3114836SGerry Liu 859a3114836SGerry Liu return (rc); 860e4b86885SCheng Sean Ye } 861e4b86885SCheng Sean Ye 862e4b86885SCheng Sean Ye #else /* __xpv */ 863e4b86885SCheng Sean Ye 864e4b86885SCheng Sean Ye /* 865e4b86885SCheng Sean Ye * ======================================================= 866e4b86885SCheng Sean Ye * | xVM dom0 methods | 867e4b86885SCheng Sean Ye * | ---------------- | 868e4b86885SCheng Sean Ye * | | 869e4b86885SCheng Sean Ye * | These are used when we are running as dom0 in | 870e4b86885SCheng Sean Ye * | a Solaris xVM context. | 871e4b86885SCheng Sean Ye * --------------------------------------------------------- 872e4b86885SCheng Sean Ye */ 873e4b86885SCheng Sean Ye 874e4b86885SCheng Sean Ye #define HDLPRIV(hdl) ((xen_mc_lcpu_cookie_t)(hdl)->cmih_hdlpriv) 875e4b86885SCheng Sean Ye 876e4b86885SCheng Sean Ye extern uint_t _cpuid_vendorstr_to_vendorcode(char *); 877e4b86885SCheng Sean Ye 878e4b86885SCheng Sean Ye 879e4b86885SCheng Sean Ye static uint_t 880e4b86885SCheng Sean Ye xpv_vendor(cmi_hdl_impl_t *hdl) 881e4b86885SCheng Sean Ye { 882e4b86885SCheng Sean Ye return (_cpuid_vendorstr_to_vendorcode((char *)xen_physcpu_vendorstr( 883e4b86885SCheng Sean Ye HDLPRIV(hdl)))); 884e4b86885SCheng Sean Ye } 885e4b86885SCheng Sean Ye 886e4b86885SCheng Sean Ye static const char * 887e4b86885SCheng Sean Ye xpv_vendorstr(cmi_hdl_impl_t *hdl) 888e4b86885SCheng Sean Ye { 889e4b86885SCheng Sean Ye return (xen_physcpu_vendorstr(HDLPRIV(hdl))); 890e4b86885SCheng Sean Ye } 891e4b86885SCheng Sean Ye 892e4b86885SCheng Sean Ye static uint_t 893e4b86885SCheng Sean Ye xpv_family(cmi_hdl_impl_t *hdl) 894e4b86885SCheng Sean Ye { 895e4b86885SCheng Sean Ye return (xen_physcpu_family(HDLPRIV(hdl))); 896e4b86885SCheng Sean Ye } 897e4b86885SCheng Sean Ye 898e4b86885SCheng Sean Ye static uint_t 899e4b86885SCheng Sean Ye xpv_model(cmi_hdl_impl_t *hdl) 900e4b86885SCheng Sean Ye { 901e4b86885SCheng Sean Ye return (xen_physcpu_model(HDLPRIV(hdl))); 902e4b86885SCheng Sean Ye } 903e4b86885SCheng Sean Ye 904e4b86885SCheng Sean Ye static uint_t 905e4b86885SCheng Sean Ye xpv_stepping(cmi_hdl_impl_t *hdl) 906e4b86885SCheng Sean Ye { 907e4b86885SCheng Sean Ye return (xen_physcpu_stepping(HDLPRIV(hdl))); 908e4b86885SCheng Sean Ye } 909e4b86885SCheng Sean Ye 910e4b86885SCheng Sean Ye static uint_t 911e4b86885SCheng Sean Ye xpv_chipid(cmi_hdl_impl_t *hdl) 912e4b86885SCheng Sean Ye { 913e4b86885SCheng Sean Ye return (hdl->cmih_chipid); 914e4b86885SCheng Sean Ye } 915e4b86885SCheng Sean Ye 916e4b86885SCheng Sean Ye static uint_t 9178031591dSSrihari Venkatesan xpv_procnodeid(cmi_hdl_impl_t *hdl) 9188031591dSSrihari Venkatesan { 9198031591dSSrihari Venkatesan return (hdl->cmih_procnodeid); 9208031591dSSrihari Venkatesan } 9218031591dSSrihari Venkatesan 9228031591dSSrihari Venkatesan static uint_t 9238031591dSSrihari Venkatesan xpv_procnodes_per_pkg(cmi_hdl_impl_t *hdl) 9248031591dSSrihari Venkatesan { 9258031591dSSrihari Venkatesan return (hdl->cmih_procnodes_per_pkg); 9268031591dSSrihari Venkatesan } 9278031591dSSrihari Venkatesan 9288031591dSSrihari Venkatesan static uint_t 929e4b86885SCheng Sean Ye xpv_coreid(cmi_hdl_impl_t *hdl) 930e4b86885SCheng Sean Ye { 931e4b86885SCheng Sean Ye return (hdl->cmih_coreid); 932e4b86885SCheng Sean Ye } 933e4b86885SCheng Sean Ye 934e4b86885SCheng Sean Ye static uint_t 935e4b86885SCheng Sean Ye xpv_strandid(cmi_hdl_impl_t *hdl) 936e4b86885SCheng Sean Ye { 937e4b86885SCheng Sean Ye return (hdl->cmih_strandid); 938e4b86885SCheng Sean Ye } 939e4b86885SCheng Sean Ye 940074bb90dSTom Pothier static uint_t 941074bb90dSTom Pothier xpv_strand_apicid(cmi_hdl_impl_t *hdl) 942074bb90dSTom Pothier { 943074bb90dSTom Pothier return (xen_physcpu_initial_apicid(HDLPRIV(hdl))); 944074bb90dSTom Pothier } 945074bb90dSTom Pothier 946074bb90dSTom Pothier static uint16_t 947074bb90dSTom Pothier xpv_smbiosid(cmi_hdl_impl_t *hdl) 948074bb90dSTom Pothier { 949074bb90dSTom Pothier return (hdl->cmih_smbiosid); 950074bb90dSTom Pothier } 951074bb90dSTom Pothier 952074bb90dSTom Pothier static uint_t 953074bb90dSTom Pothier xpv_smb_chipid(cmi_hdl_impl_t *hdl) 954074bb90dSTom Pothier { 955074bb90dSTom Pothier return (hdl->cmih_smb_chipid); 956074bb90dSTom Pothier } 957074bb90dSTom Pothier 958074bb90dSTom Pothier static nvlist_t * 959074bb90dSTom Pothier xpv_smb_bboard(cmi_hdl_impl_t *hdl) 960074bb90dSTom Pothier { 961074bb90dSTom Pothier return (hdl->cmih_smb_bboard); 962074bb90dSTom Pothier } 963074bb90dSTom Pothier 964e4b86885SCheng Sean Ye extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t); 965e4b86885SCheng Sean Ye 966e4b86885SCheng Sean Ye static uint32_t 967e4b86885SCheng Sean Ye xpv_chiprev(cmi_hdl_impl_t *hdl) 968e4b86885SCheng Sean Ye { 969e4b86885SCheng Sean Ye return (_cpuid_chiprev(xpv_vendor(hdl), xpv_family(hdl), 970e4b86885SCheng Sean Ye xpv_model(hdl), xpv_stepping(hdl))); 971e4b86885SCheng Sean Ye } 972e4b86885SCheng Sean Ye 973e4b86885SCheng Sean Ye extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t); 974e4b86885SCheng Sean Ye 975e4b86885SCheng Sean Ye static const char * 976e4b86885SCheng Sean Ye xpv_chiprevstr(cmi_hdl_impl_t *hdl) 977e4b86885SCheng Sean Ye { 978e4b86885SCheng Sean Ye return (_cpuid_chiprevstr(xpv_vendor(hdl), xpv_family(hdl), 979e4b86885SCheng Sean Ye xpv_model(hdl), xpv_stepping(hdl))); 980e4b86885SCheng Sean Ye } 981e4b86885SCheng Sean Ye 982e4b86885SCheng Sean Ye extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t); 983e4b86885SCheng Sean Ye 984e4b86885SCheng Sean Ye static uint32_t 985e4b86885SCheng Sean Ye xpv_getsockettype(cmi_hdl_impl_t *hdl) 986e4b86885SCheng Sean Ye { 987e4b86885SCheng Sean Ye return (_cpuid_skt(xpv_vendor(hdl), xpv_family(hdl), 988e4b86885SCheng Sean Ye xpv_model(hdl), xpv_stepping(hdl))); 989e4b86885SCheng Sean Ye } 990e4b86885SCheng Sean Ye 99189e921d5SKuriakose Kuruvilla extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t); 99289e921d5SKuriakose Kuruvilla 99389e921d5SKuriakose Kuruvilla static const char * 99489e921d5SKuriakose Kuruvilla xpv_getsocketstr(cmi_hdl_impl_t *hdl) 99589e921d5SKuriakose Kuruvilla { 99689e921d5SKuriakose Kuruvilla return (_cpuid_sktstr(xpv_vendor(hdl), xpv_family(hdl), 99789e921d5SKuriakose Kuruvilla xpv_model(hdl), xpv_stepping(hdl))); 99889e921d5SKuriakose Kuruvilla } 99989e921d5SKuriakose Kuruvilla 1000e4b86885SCheng Sean Ye static id_t 1001e4b86885SCheng Sean Ye xpv_logical_id(cmi_hdl_impl_t *hdl) 1002e4b86885SCheng Sean Ye { 1003e4b86885SCheng Sean Ye return (xen_physcpu_logical_id(HDLPRIV(hdl))); 1004e4b86885SCheng Sean Ye } 1005e4b86885SCheng Sean Ye 1006e4b86885SCheng Sean Ye static cmi_errno_t 1007e4b86885SCheng Sean Ye xpv_rdmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t *valp) 1008e4b86885SCheng Sean Ye { 1009e4b86885SCheng Sean Ye switch (msr) { 1010e4b86885SCheng Sean Ye case IA32_MSR_MCG_CAP: 1011e4b86885SCheng Sean Ye *valp = xen_physcpu_mcg_cap(HDLPRIV(hdl)); 1012e4b86885SCheng Sean Ye break; 1013e4b86885SCheng Sean Ye 1014e4b86885SCheng Sean Ye default: 1015e4b86885SCheng Sean Ye return (CMIERR_NOTSUP); 1016e4b86885SCheng Sean Ye } 1017e4b86885SCheng Sean Ye 1018e4b86885SCheng Sean Ye return (CMI_SUCCESS); 1019e4b86885SCheng Sean Ye } 1020e4b86885SCheng Sean Ye 1021e4b86885SCheng Sean Ye /* 1022e4b86885SCheng Sean Ye * Request the hypervisor to write an MSR for us. The hypervisor 1023e4b86885SCheng Sean Ye * will only accept MCA-related MSRs, as this is for MCA error 1024e4b86885SCheng Sean Ye * simulation purposes alone. We will pre-screen MSRs for injection 1025e4b86885SCheng Sean Ye * so we don't bother the HV with bogus requests. We will permit 1026e4b86885SCheng Sean Ye * injection to any MCA bank register, and to MCG_STATUS. 1027e4b86885SCheng Sean Ye */ 1028e4b86885SCheng Sean Ye 1029e4b86885SCheng Sean Ye #define IS_MCA_INJ_MSR(msr) \ 1030e4b86885SCheng Sean Ye (((msr) >= IA32_MSR_MC(0, CTL) && (msr) <= IA32_MSR_MC(10, MISC)) || \ 1031e4b86885SCheng Sean Ye (msr) == IA32_MSR_MCG_STATUS) 1032e4b86885SCheng Sean Ye 1033e4b86885SCheng Sean Ye static cmi_errno_t 1034e4b86885SCheng Sean Ye xpv_wrmsr_cmn(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val, boolean_t intpose) 1035e4b86885SCheng Sean Ye { 1036ad09f8b8SMark Johnson xen_mc_t xmc; 1037ad09f8b8SMark Johnson struct xen_mc_msrinject *mci = &xmc.u.mc_msrinject; 1038e4b86885SCheng Sean Ye 1039e4b86885SCheng Sean Ye if (!(hdl->cmih_flags & CMIH_F_INJACTV)) 1040e4b86885SCheng Sean Ye return (CMIERR_NOTSUP); /* for injection use only! */ 1041e4b86885SCheng Sean Ye 1042e4b86885SCheng Sean Ye if (!IS_MCA_INJ_MSR(msr)) 1043e4b86885SCheng Sean Ye return (CMIERR_API); 1044e4b86885SCheng Sean Ye 1045e4b86885SCheng Sean Ye if (panicstr) 1046e4b86885SCheng Sean Ye return (CMIERR_DEADLOCK); 1047e4b86885SCheng Sean Ye 1048ad09f8b8SMark Johnson mci->mcinj_cpunr = xen_physcpu_logical_id(HDLPRIV(hdl)); 1049ad09f8b8SMark Johnson mci->mcinj_flags = intpose ? MC_MSRINJ_F_INTERPOSE : 0; 1050ad09f8b8SMark Johnson mci->mcinj_count = 1; /* learn to batch sometime */ 1051ad09f8b8SMark Johnson mci->mcinj_msr[0].reg = msr; 1052ad09f8b8SMark Johnson mci->mcinj_msr[0].value = val; 1053e4b86885SCheng Sean Ye 1054ad09f8b8SMark Johnson return (HYPERVISOR_mca(XEN_MC_msrinject, &xmc) == 1055349b53ddSStuart Maybee 0 ? CMI_SUCCESS : CMIERR_NOTSUP); 1056e4b86885SCheng Sean Ye } 1057e4b86885SCheng Sean Ye 1058e4b86885SCheng Sean Ye static cmi_errno_t 1059e4b86885SCheng Sean Ye xpv_wrmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val) 1060e4b86885SCheng Sean Ye { 1061e4b86885SCheng Sean Ye return (xpv_wrmsr_cmn(hdl, msr, val, B_FALSE)); 1062e4b86885SCheng Sean Ye } 1063e4b86885SCheng Sean Ye 1064e4b86885SCheng Sean Ye 1065e4b86885SCheng Sean Ye static cmi_errno_t 1066e4b86885SCheng Sean Ye xpv_msrinterpose(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val) 1067e4b86885SCheng Sean Ye { 1068e4b86885SCheng Sean Ye return (xpv_wrmsr_cmn(hdl, msr, val, B_TRUE)); 1069e4b86885SCheng Sean Ye } 1070e4b86885SCheng Sean Ye 1071e4b86885SCheng Sean Ye static void 1072e4b86885SCheng Sean Ye xpv_int(cmi_hdl_impl_t *hdl, int int_no) 1073e4b86885SCheng Sean Ye { 1074ad09f8b8SMark Johnson xen_mc_t xmc; 1075ad09f8b8SMark Johnson struct xen_mc_mceinject *mce = &xmc.u.mc_mceinject; 1076e4b86885SCheng Sean Ye 1077e4b86885SCheng Sean Ye if (!(hdl->cmih_flags & CMIH_F_INJACTV)) 1078e4b86885SCheng Sean Ye return; 1079e4b86885SCheng Sean Ye 1080e4b86885SCheng Sean Ye if (int_no != T_MCE) { 1081e4b86885SCheng Sean Ye cmn_err(CE_WARN, "xpv_int: int_no %d unimplemented\n", 1082e4b86885SCheng Sean Ye int_no); 1083e4b86885SCheng Sean Ye } 1084e4b86885SCheng Sean Ye 1085ad09f8b8SMark Johnson mce->mceinj_cpunr = xen_physcpu_logical_id(HDLPRIV(hdl)); 1086e4b86885SCheng Sean Ye 1087ad09f8b8SMark Johnson (void) HYPERVISOR_mca(XEN_MC_mceinject, &xmc); 1088e4b86885SCheng Sean Ye } 1089e4b86885SCheng Sean Ye 1090e4b86885SCheng Sean Ye static int 1091e4b86885SCheng Sean Ye xpv_online(cmi_hdl_impl_t *hdl, int new_status, int *old_status) 1092e4b86885SCheng Sean Ye { 1093349b53ddSStuart Maybee xen_sysctl_t xs; 1094349b53ddSStuart Maybee int op, rc, status; 1095e4b86885SCheng Sean Ye 1096e4b86885SCheng Sean Ye new_status &= ~P_FORCED; 1097e4b86885SCheng Sean Ye 1098349b53ddSStuart Maybee switch (new_status) { 1099349b53ddSStuart Maybee case P_STATUS: 1100349b53ddSStuart Maybee op = XEN_SYSCTL_CPU_HOTPLUG_STATUS; 1101349b53ddSStuart Maybee break; 1102349b53ddSStuart Maybee case P_FAULTED: 1103349b53ddSStuart Maybee case P_OFFLINE: 1104349b53ddSStuart Maybee op = XEN_SYSCTL_CPU_HOTPLUG_OFFLINE; 1105349b53ddSStuart Maybee break; 1106349b53ddSStuart Maybee case P_ONLINE: 1107349b53ddSStuart Maybee op = XEN_SYSCTL_CPU_HOTPLUG_ONLINE; 1108349b53ddSStuart Maybee break; 1109349b53ddSStuart Maybee default: 1110349b53ddSStuart Maybee return (-1); 1111349b53ddSStuart Maybee } 1112e4b86885SCheng Sean Ye 1113349b53ddSStuart Maybee xs.cmd = XEN_SYSCTL_cpu_hotplug; 1114349b53ddSStuart Maybee xs.interface_version = XEN_SYSCTL_INTERFACE_VERSION; 1115349b53ddSStuart Maybee xs.u.cpu_hotplug.cpu = xen_physcpu_logical_id(HDLPRIV(hdl)); 1116349b53ddSStuart Maybee xs.u.cpu_hotplug.op = op; 1117e4b86885SCheng Sean Ye 1118349b53ddSStuart Maybee if ((rc = HYPERVISOR_sysctl(&xs)) >= 0) { 1119349b53ddSStuart Maybee status = rc; 1120349b53ddSStuart Maybee rc = 0; 1121349b53ddSStuart Maybee switch (status) { 1122349b53ddSStuart Maybee case XEN_CPU_HOTPLUG_STATUS_NEW: 1123349b53ddSStuart Maybee *old_status = P_OFFLINE; 1124349b53ddSStuart Maybee break; 1125349b53ddSStuart Maybee case XEN_CPU_HOTPLUG_STATUS_OFFLINE: 1126349b53ddSStuart Maybee *old_status = P_FAULTED; 1127349b53ddSStuart Maybee break; 1128349b53ddSStuart Maybee case XEN_CPU_HOTPLUG_STATUS_ONLINE: 1129349b53ddSStuart Maybee *old_status = P_ONLINE; 1130349b53ddSStuart Maybee break; 1131349b53ddSStuart Maybee default: 1132349b53ddSStuart Maybee return (-1); 1133349b53ddSStuart Maybee } 1134e4b86885SCheng Sean Ye } 1135e4b86885SCheng Sean Ye 1136e4b86885SCheng Sean Ye return (-rc); 1137e4b86885SCheng Sean Ye } 1138e4b86885SCheng Sean Ye 1139e4b86885SCheng Sean Ye #endif 1140e4b86885SCheng Sean Ye 1141e4b86885SCheng Sean Ye /*ARGSUSED*/ 114220c794b3Sgavinm static void * 114320c794b3Sgavinm cpu_search(enum cmi_hdl_class class, uint_t chipid, uint_t coreid, 114420c794b3Sgavinm uint_t strandid) 114520c794b3Sgavinm { 1146e4b86885SCheng Sean Ye #ifdef __xpv 1147e4b86885SCheng Sean Ye xen_mc_lcpu_cookie_t cpi; 1148e4b86885SCheng Sean Ye 1149e4b86885SCheng Sean Ye for (cpi = xen_physcpu_next(NULL); cpi != NULL; 1150e4b86885SCheng Sean Ye cpi = xen_physcpu_next(cpi)) { 1151e4b86885SCheng Sean Ye if (xen_physcpu_chipid(cpi) == chipid && 1152e4b86885SCheng Sean Ye xen_physcpu_coreid(cpi) == coreid && 1153e4b86885SCheng Sean Ye xen_physcpu_strandid(cpi) == strandid) 1154e4b86885SCheng Sean Ye return ((void *)cpi); 1155e4b86885SCheng Sean Ye } 1156e4b86885SCheng Sean Ye return (NULL); 1157e4b86885SCheng Sean Ye 1158e4b86885SCheng Sean Ye #else /* __xpv */ 1159e4b86885SCheng Sean Ye 116020c794b3Sgavinm cpu_t *cp, *startcp; 116120c794b3Sgavinm 116220c794b3Sgavinm kpreempt_disable(); 116320c794b3Sgavinm cp = startcp = CPU; 116420c794b3Sgavinm do { 116520c794b3Sgavinm if (cmi_ntv_hwchipid(cp) == chipid && 116620c794b3Sgavinm cmi_ntv_hwcoreid(cp) == coreid && 116720c794b3Sgavinm cmi_ntv_hwstrandid(cp) == strandid) { 116820c794b3Sgavinm kpreempt_enable(); 116920c794b3Sgavinm return ((void *)cp); 117020c794b3Sgavinm } 117120c794b3Sgavinm 117220c794b3Sgavinm cp = cp->cpu_next; 117320c794b3Sgavinm } while (cp != startcp); 117420c794b3Sgavinm kpreempt_enable(); 117520c794b3Sgavinm return (NULL); 1176e4b86885SCheng Sean Ye #endif /* __ xpv */ 117720c794b3Sgavinm } 117820c794b3Sgavinm 1179e4b86885SCheng Sean Ye static boolean_t 1180e4b86885SCheng Sean Ye cpu_is_cmt(void *priv) 1181e4b86885SCheng Sean Ye { 1182e4b86885SCheng Sean Ye #ifdef __xpv 1183e4b86885SCheng Sean Ye return (xen_physcpu_is_cmt((xen_mc_lcpu_cookie_t)priv)); 1184e4b86885SCheng Sean Ye #else /* __xpv */ 1185e4b86885SCheng Sean Ye cpu_t *cp = (cpu_t *)priv; 1186e4b86885SCheng Sean Ye 1187e4b86885SCheng Sean Ye int strands_per_core = cpuid_get_ncpu_per_chip(cp) / 1188e4b86885SCheng Sean Ye cpuid_get_ncore_per_chip(cp); 1189e4b86885SCheng Sean Ye 1190e4b86885SCheng Sean Ye return (strands_per_core > 1); 1191e4b86885SCheng Sean Ye #endif /* __xpv */ 119220c794b3Sgavinm } 119320c794b3Sgavinm 11942d39cb4cSVuong Nguyen /* 11952d39cb4cSVuong Nguyen * Find the handle entry of a given cpu identified by a <chip,core,strand> 11962d39cb4cSVuong Nguyen * tuple. 11972d39cb4cSVuong Nguyen */ 11982d39cb4cSVuong Nguyen static cmi_hdl_ent_t * 11992d39cb4cSVuong Nguyen cmi_hdl_ent_lookup(uint_t chipid, uint_t coreid, uint_t strandid) 12002d39cb4cSVuong Nguyen { 12012d2efdc6SVuong Nguyen int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits, 12022d2efdc6SVuong Nguyen cmi_strand_nbits); 12032d2efdc6SVuong Nguyen 12042d39cb4cSVuong Nguyen /* 12052d39cb4cSVuong Nguyen * Allocate per-chip table which contains a list of handle of 12062d39cb4cSVuong Nguyen * all strands of the chip. 12072d39cb4cSVuong Nguyen */ 12082d39cb4cSVuong Nguyen if (cmi_chip_tab[chipid] == NULL) { 12092d39cb4cSVuong Nguyen size_t sz; 12102d39cb4cSVuong Nguyen cmi_hdl_ent_t *pg; 12112d39cb4cSVuong Nguyen 12122d2efdc6SVuong Nguyen sz = max_strands * sizeof (cmi_hdl_ent_t); 12132d39cb4cSVuong Nguyen pg = kmem_zalloc(sz, KM_SLEEP); 12142d39cb4cSVuong Nguyen 12152d39cb4cSVuong Nguyen /* test and set the per-chip table if it is not allocated */ 12162d39cb4cSVuong Nguyen if (atomic_cas_ptr(&cmi_chip_tab[chipid], NULL, pg) != NULL) 12172d2efdc6SVuong Nguyen kmem_free(pg, sz); /* someone beats us */ 12182d39cb4cSVuong Nguyen } 12192d39cb4cSVuong Nguyen 12202d2efdc6SVuong Nguyen return (cmi_chip_tab[chipid] + 12212d2efdc6SVuong Nguyen ((((coreid) & CMI_MAX_COREID(cmi_core_nbits)) << cmi_strand_nbits) | 12222d2efdc6SVuong Nguyen ((strandid) & CMI_MAX_STRANDID(cmi_strand_nbits)))); 12232d39cb4cSVuong Nguyen } 12242d39cb4cSVuong Nguyen 12252d2efdc6SVuong Nguyen extern void cpuid_get_ext_topo(uint_t, uint_t *, uint_t *); 12262d2efdc6SVuong Nguyen 122720c794b3Sgavinm cmi_hdl_t 122820c794b3Sgavinm cmi_hdl_create(enum cmi_hdl_class class, uint_t chipid, uint_t coreid, 1229e4b86885SCheng Sean Ye uint_t strandid) 123020c794b3Sgavinm { 123120c794b3Sgavinm cmi_hdl_impl_t *hdl; 1232e4b86885SCheng Sean Ye void *priv; 12332d39cb4cSVuong Nguyen cmi_hdl_ent_t *ent; 12342d2efdc6SVuong Nguyen uint_t vendor; 123520c794b3Sgavinm 1236e4b86885SCheng Sean Ye #ifdef __xpv 1237e4b86885SCheng Sean Ye ASSERT(class == CMI_HDL_SOLARIS_xVM_MCA); 1238e4b86885SCheng Sean Ye #else 1239e4b86885SCheng Sean Ye ASSERT(class == CMI_HDL_NATIVE); 1240e4b86885SCheng Sean Ye #endif 1241e4b86885SCheng Sean Ye 12422d2efdc6SVuong Nguyen if ((priv = cpu_search(class, chipid, coreid, strandid)) == NULL) 124320c794b3Sgavinm return (NULL); 124420c794b3Sgavinm 12452d2efdc6SVuong Nguyen /* 12462d2efdc6SVuong Nguyen * Assume all chips in the system are the same type. 12472d2efdc6SVuong Nguyen * For Intel, attempt to check if extended topology is available 12482d2efdc6SVuong Nguyen * CPUID.EAX=0xB. If so, get the number of core and strand bits. 12492d2efdc6SVuong Nguyen */ 12502d2efdc6SVuong Nguyen #ifdef __xpv 12512d2efdc6SVuong Nguyen vendor = _cpuid_vendorstr_to_vendorcode( 12522d2efdc6SVuong Nguyen (char *)xen_physcpu_vendorstr((xen_mc_lcpu_cookie_t)priv)); 12532d2efdc6SVuong Nguyen #else 12542d2efdc6SVuong Nguyen vendor = cpuid_getvendor((cpu_t *)priv); 12552d2efdc6SVuong Nguyen #endif 12562d2efdc6SVuong Nguyen if (vendor == X86_VENDOR_Intel && cmi_ext_topo_check == 0) { 12572d2efdc6SVuong Nguyen cpuid_get_ext_topo(vendor, &cmi_core_nbits, &cmi_strand_nbits); 12582d2efdc6SVuong Nguyen cmi_ext_topo_check = 1; 12592d2efdc6SVuong Nguyen } 12602d2efdc6SVuong Nguyen 12612d2efdc6SVuong Nguyen if (chipid > CMI_MAX_CHIPID || 12622d2efdc6SVuong Nguyen coreid > CMI_MAX_COREID(cmi_core_nbits) || 12632d2efdc6SVuong Nguyen strandid > CMI_MAX_STRANDID(cmi_strand_nbits)) 126420c794b3Sgavinm return (NULL); 126520c794b3Sgavinm 126620c794b3Sgavinm hdl = kmem_zalloc(sizeof (*hdl), KM_SLEEP); 126720c794b3Sgavinm 126820c794b3Sgavinm hdl->cmih_class = class; 1269e4b86885SCheng Sean Ye HDLOPS(hdl) = &cmi_hdl_ops; 127020c794b3Sgavinm hdl->cmih_chipid = chipid; 127120c794b3Sgavinm hdl->cmih_coreid = coreid; 127220c794b3Sgavinm hdl->cmih_strandid = strandid; 1273e4b86885SCheng Sean Ye hdl->cmih_mstrand = cpu_is_cmt(priv); 127420c794b3Sgavinm hdl->cmih_hdlpriv = priv; 1275e4b86885SCheng Sean Ye #ifdef __xpv 1276e4b86885SCheng Sean Ye hdl->cmih_msrsrc = CMI_MSR_FLAG_RD_INTERPOSEOK | 1277e4b86885SCheng Sean Ye CMI_MSR_FLAG_WR_INTERPOSEOK; 12788031591dSSrihari Venkatesan 12798031591dSSrihari Venkatesan /* 12808031591dSSrihari Venkatesan * XXX: need hypervisor support for procnodeid, for now assume 12818031591dSSrihari Venkatesan * single-node processors (procnodeid = chipid) 12828031591dSSrihari Venkatesan */ 12838031591dSSrihari Venkatesan hdl->cmih_procnodeid = xen_physcpu_chipid((xen_mc_lcpu_cookie_t)priv); 12848031591dSSrihari Venkatesan hdl->cmih_procnodes_per_pkg = 1; 1285e4b86885SCheng Sean Ye #else /* __xpv */ 128620c794b3Sgavinm hdl->cmih_msrsrc = CMI_MSR_FLAG_RD_HWOK | CMI_MSR_FLAG_RD_INTERPOSEOK | 128720c794b3Sgavinm CMI_MSR_FLAG_WR_HWOK | CMI_MSR_FLAG_WR_INTERPOSEOK; 12888031591dSSrihari Venkatesan hdl->cmih_procnodeid = cpuid_get_procnodeid((cpu_t *)priv); 12898031591dSSrihari Venkatesan hdl->cmih_procnodes_per_pkg = 12908031591dSSrihari Venkatesan cpuid_get_procnodes_per_pkg((cpu_t *)priv); 12918031591dSSrihari Venkatesan #endif /* __xpv */ 129220c794b3Sgavinm 12932d39cb4cSVuong Nguyen ent = cmi_hdl_ent_lookup(chipid, coreid, strandid); 12942d39cb4cSVuong Nguyen if (ent->cmae_refcnt != 0 || ent->cmae_hdlp != NULL) { 129510569901Sgavinm /* 129610569901Sgavinm * Somehow this (chipid, coreid, strandid) id tuple has 129710569901Sgavinm * already been assigned! This indicates that the 129810569901Sgavinm * callers logic in determining these values is busted, 129910569901Sgavinm * or perhaps undermined by bad BIOS setup. Complain, 130010569901Sgavinm * and refuse to initialize this tuple again as bad things 130110569901Sgavinm * will happen. 130210569901Sgavinm */ 130310569901Sgavinm cmn_err(CE_NOTE, "cmi_hdl_create: chipid %d coreid %d " 130410569901Sgavinm "strandid %d handle already allocated!", 130510569901Sgavinm chipid, coreid, strandid); 130610569901Sgavinm kmem_free(hdl, sizeof (*hdl)); 130710569901Sgavinm return (NULL); 130810569901Sgavinm } 130920c794b3Sgavinm 131020c794b3Sgavinm /* 131120c794b3Sgavinm * Once we store a nonzero reference count others can find this 131220c794b3Sgavinm * handle via cmi_hdl_lookup etc. This initial hold on the handle 131320c794b3Sgavinm * is to be dropped only if some other part of cmi initialization 131420c794b3Sgavinm * fails or, if it succeeds, at later cpu deconfigure. Note the 131520c794b3Sgavinm * the module private data we hold in cmih_cmi and cmih_cmidata 131620c794b3Sgavinm * is still NULL at this point (the caller will fill it with 131720c794b3Sgavinm * cmi_hdl_setcmi if it initializes) so consumers of handles 131820c794b3Sgavinm * should always be ready for that possibility. 131920c794b3Sgavinm */ 13202d39cb4cSVuong Nguyen ent->cmae_hdlp = hdl; 13212d39cb4cSVuong Nguyen hdl->cmih_refcntp = &ent->cmae_refcnt; 13222d39cb4cSVuong Nguyen ent->cmae_refcnt = 1; 132320c794b3Sgavinm 132420c794b3Sgavinm return ((cmi_hdl_t)hdl); 132520c794b3Sgavinm } 132620c794b3Sgavinm 132720c794b3Sgavinm void 1328074bb90dSTom Pothier cmi_read_smbios(cmi_hdl_t ophdl) 1329074bb90dSTom Pothier { 1330074bb90dSTom Pothier 1331bb1fad37SSrihari Venkatesan uint_t strand_apicid = UINT_MAX; 1332bb1fad37SSrihari Venkatesan uint_t chip_inst = UINT_MAX; 1333bb1fad37SSrihari Venkatesan uint16_t smb_id = USHRT_MAX; 1334074bb90dSTom Pothier int rc = 0; 1335074bb90dSTom Pothier 1336074bb90dSTom Pothier cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 1337074bb90dSTom Pothier 1338074bb90dSTom Pothier /* set x86gentopo compatibility */ 1339074bb90dSTom Pothier fm_smb_fmacompat(); 1340074bb90dSTom Pothier 1341074bb90dSTom Pothier #ifndef __xpv 1342074bb90dSTom Pothier strand_apicid = ntv_strand_apicid(hdl); 1343074bb90dSTom Pothier #else 1344074bb90dSTom Pothier strand_apicid = xpv_strand_apicid(hdl); 1345074bb90dSTom Pothier #endif 1346074bb90dSTom Pothier 1347074bb90dSTom Pothier if (!x86gentopo_legacy) { 1348074bb90dSTom Pothier /* 1349074bb90dSTom Pothier * If fm_smb_chipinst() or fm_smb_bboard() fails, 1350074bb90dSTom Pothier * topo reverts to legacy mode 1351074bb90dSTom Pothier */ 1352074bb90dSTom Pothier rc = fm_smb_chipinst(strand_apicid, &chip_inst, &smb_id); 1353074bb90dSTom Pothier if (rc == 0) { 1354074bb90dSTom Pothier hdl->cmih_smb_chipid = chip_inst; 1355074bb90dSTom Pothier hdl->cmih_smbiosid = smb_id; 1356074bb90dSTom Pothier } else { 1357074bb90dSTom Pothier #ifdef DEBUG 13587991dd24STom Pothier cmn_err(CE_NOTE, "!cmi reads smbios chip info failed"); 1359074bb90dSTom Pothier #endif /* DEBUG */ 1360074bb90dSTom Pothier return; 1361074bb90dSTom Pothier } 1362074bb90dSTom Pothier 1363074bb90dSTom Pothier hdl->cmih_smb_bboard = fm_smb_bboard(strand_apicid); 1364074bb90dSTom Pothier #ifdef DEBUG 1365074bb90dSTom Pothier if (hdl->cmih_smb_bboard == NULL) 1366074bb90dSTom Pothier cmn_err(CE_NOTE, 13677991dd24STom Pothier "!cmi reads smbios base boards info failed"); 1368074bb90dSTom Pothier #endif /* DEBUG */ 1369074bb90dSTom Pothier } 1370074bb90dSTom Pothier } 1371074bb90dSTom Pothier 1372074bb90dSTom Pothier void 137320c794b3Sgavinm cmi_hdl_hold(cmi_hdl_t ophdl) 137420c794b3Sgavinm { 137520c794b3Sgavinm cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 137620c794b3Sgavinm 137720c794b3Sgavinm ASSERT(*hdl->cmih_refcntp != 0); /* must not be the initial hold */ 137820c794b3Sgavinm 137920c794b3Sgavinm atomic_inc_32(hdl->cmih_refcntp); 138020c794b3Sgavinm } 138120c794b3Sgavinm 138220c794b3Sgavinm static int 13832d39cb4cSVuong Nguyen cmi_hdl_canref(cmi_hdl_ent_t *ent) 138420c794b3Sgavinm { 138520c794b3Sgavinm volatile uint32_t *refcntp; 138620c794b3Sgavinm uint32_t refcnt; 138720c794b3Sgavinm 13882d39cb4cSVuong Nguyen refcntp = &ent->cmae_refcnt; 138920c794b3Sgavinm refcnt = *refcntp; 139020c794b3Sgavinm 139120c794b3Sgavinm if (refcnt == 0) { 139220c794b3Sgavinm /* 139320c794b3Sgavinm * Associated object never existed, is being destroyed, 139420c794b3Sgavinm * or has been destroyed. 139520c794b3Sgavinm */ 139620c794b3Sgavinm return (0); 139720c794b3Sgavinm } 139820c794b3Sgavinm 139920c794b3Sgavinm /* 140020c794b3Sgavinm * We cannot use atomic increment here because once the reference 140120c794b3Sgavinm * count reaches zero it must never be bumped up again. 140220c794b3Sgavinm */ 140320c794b3Sgavinm while (refcnt != 0) { 140420c794b3Sgavinm if (atomic_cas_32(refcntp, refcnt, refcnt + 1) == refcnt) 140520c794b3Sgavinm return (1); 140620c794b3Sgavinm refcnt = *refcntp; 140720c794b3Sgavinm } 140820c794b3Sgavinm 140920c794b3Sgavinm /* 141020c794b3Sgavinm * Somebody dropped the reference count to 0 after our initial 141120c794b3Sgavinm * check. 141220c794b3Sgavinm */ 141320c794b3Sgavinm return (0); 141420c794b3Sgavinm } 141520c794b3Sgavinm 141620c794b3Sgavinm 141720c794b3Sgavinm void 141820c794b3Sgavinm cmi_hdl_rele(cmi_hdl_t ophdl) 141920c794b3Sgavinm { 142020c794b3Sgavinm cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 142120c794b3Sgavinm 142220c794b3Sgavinm ASSERT(*hdl->cmih_refcntp > 0); 1423*640c1670SJosef 'Jeff' Sipek atomic_dec_32(hdl->cmih_refcntp); 1424a3114836SGerry Liu } 142520c794b3Sgavinm 1426a3114836SGerry Liu void 1427a3114836SGerry Liu cmi_hdl_destroy(cmi_hdl_t ophdl) 1428a3114836SGerry Liu { 1429a3114836SGerry Liu cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 1430a3114836SGerry Liu cmi_hdl_ent_t *ent; 1431a3114836SGerry Liu 1432a3114836SGerry Liu /* Release the reference count held by cmi_hdl_create(). */ 1433a3114836SGerry Liu ASSERT(*hdl->cmih_refcntp > 0); 1434*640c1670SJosef 'Jeff' Sipek atomic_dec_32(hdl->cmih_refcntp); 1435a3114836SGerry Liu hdl->cmih_flags |= CMIH_F_DEAD; 143620c794b3Sgavinm 14372d39cb4cSVuong Nguyen ent = cmi_hdl_ent_lookup(hdl->cmih_chipid, hdl->cmih_coreid, 143820c794b3Sgavinm hdl->cmih_strandid); 1439a3114836SGerry Liu /* 1440a3114836SGerry Liu * Use busy polling instead of condition variable here because 1441a3114836SGerry Liu * cmi_hdl_rele() may be called from #MC handler. 1442a3114836SGerry Liu */ 1443a3114836SGerry Liu while (cmi_hdl_canref(ent)) { 1444a3114836SGerry Liu cmi_hdl_rele(ophdl); 1445a3114836SGerry Liu delay(1); 1446a3114836SGerry Liu } 14472d39cb4cSVuong Nguyen ent->cmae_hdlp = NULL; 144820c794b3Sgavinm 144920c794b3Sgavinm kmem_free(hdl, sizeof (*hdl)); 145020c794b3Sgavinm } 145120c794b3Sgavinm 145220c794b3Sgavinm void 145320c794b3Sgavinm cmi_hdl_setspecific(cmi_hdl_t ophdl, void *arg) 145420c794b3Sgavinm { 145520c794b3Sgavinm IMPLHDL(ophdl)->cmih_spec = arg; 145620c794b3Sgavinm } 145720c794b3Sgavinm 145820c794b3Sgavinm void * 145920c794b3Sgavinm cmi_hdl_getspecific(cmi_hdl_t ophdl) 146020c794b3Sgavinm { 146120c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_spec); 146220c794b3Sgavinm } 146320c794b3Sgavinm 146420c794b3Sgavinm void 146520c794b3Sgavinm cmi_hdl_setmc(cmi_hdl_t ophdl, const struct cmi_mc_ops *mcops, void *mcdata) 146620c794b3Sgavinm { 146720c794b3Sgavinm cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 146820c794b3Sgavinm 146920c794b3Sgavinm ASSERT(hdl->cmih_mcops == NULL && hdl->cmih_mcdata == NULL); 147020c794b3Sgavinm hdl->cmih_mcops = mcops; 147120c794b3Sgavinm hdl->cmih_mcdata = mcdata; 147220c794b3Sgavinm } 147320c794b3Sgavinm 147420c794b3Sgavinm const struct cmi_mc_ops * 147520c794b3Sgavinm cmi_hdl_getmcops(cmi_hdl_t ophdl) 147620c794b3Sgavinm { 147720c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_mcops); 147820c794b3Sgavinm } 147920c794b3Sgavinm 148020c794b3Sgavinm void * 148120c794b3Sgavinm cmi_hdl_getmcdata(cmi_hdl_t ophdl) 148220c794b3Sgavinm { 148320c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_mcdata); 148420c794b3Sgavinm } 148520c794b3Sgavinm 148620c794b3Sgavinm cmi_hdl_t 148720c794b3Sgavinm cmi_hdl_lookup(enum cmi_hdl_class class, uint_t chipid, uint_t coreid, 148820c794b3Sgavinm uint_t strandid) 148920c794b3Sgavinm { 14902d39cb4cSVuong Nguyen cmi_hdl_ent_t *ent; 14914071b45aSstephh 14922d39cb4cSVuong Nguyen if (chipid > CMI_MAX_CHIPID || 14932d2efdc6SVuong Nguyen coreid > CMI_MAX_COREID(cmi_core_nbits) || 14942d2efdc6SVuong Nguyen strandid > CMI_MAX_STRANDID(cmi_strand_nbits)) 14954071b45aSstephh return (NULL); 14964071b45aSstephh 14972d39cb4cSVuong Nguyen ent = cmi_hdl_ent_lookup(chipid, coreid, strandid); 149820c794b3Sgavinm 1499e4b86885SCheng Sean Ye if (class == CMI_HDL_NEUTRAL) 1500e4b86885SCheng Sean Ye #ifdef __xpv 1501e4b86885SCheng Sean Ye class = CMI_HDL_SOLARIS_xVM_MCA; 1502e4b86885SCheng Sean Ye #else 1503e4b86885SCheng Sean Ye class = CMI_HDL_NATIVE; 1504e4b86885SCheng Sean Ye #endif 1505e4b86885SCheng Sean Ye 15062d39cb4cSVuong Nguyen if (!cmi_hdl_canref(ent)) 150720c794b3Sgavinm return (NULL); 150820c794b3Sgavinm 15092d39cb4cSVuong Nguyen if (ent->cmae_hdlp->cmih_class != class) { 15102d39cb4cSVuong Nguyen cmi_hdl_rele((cmi_hdl_t)ent->cmae_hdlp); 151120c794b3Sgavinm return (NULL); 151220c794b3Sgavinm } 151320c794b3Sgavinm 15142d39cb4cSVuong Nguyen return ((cmi_hdl_t)ent->cmae_hdlp); 151520c794b3Sgavinm } 151620c794b3Sgavinm 151720c794b3Sgavinm cmi_hdl_t 151820c794b3Sgavinm cmi_hdl_any(void) 151920c794b3Sgavinm { 15202d39cb4cSVuong Nguyen int i, j; 15212d39cb4cSVuong Nguyen cmi_hdl_ent_t *ent; 15222d2efdc6SVuong Nguyen int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits, 15232d2efdc6SVuong Nguyen cmi_strand_nbits); 152420c794b3Sgavinm 15252d39cb4cSVuong Nguyen for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) { 15262d39cb4cSVuong Nguyen if (cmi_chip_tab[i] == NULL) 15272d39cb4cSVuong Nguyen continue; 15282d2efdc6SVuong Nguyen for (j = 0, ent = cmi_chip_tab[i]; j < max_strands; 15292d39cb4cSVuong Nguyen j++, ent++) { 15302d39cb4cSVuong Nguyen if (cmi_hdl_canref(ent)) 15312d39cb4cSVuong Nguyen return ((cmi_hdl_t)ent->cmae_hdlp); 15322d39cb4cSVuong Nguyen } 153320c794b3Sgavinm } 153420c794b3Sgavinm 153520c794b3Sgavinm return (NULL); 153620c794b3Sgavinm } 153720c794b3Sgavinm 153820c794b3Sgavinm void 153920c794b3Sgavinm cmi_hdl_walk(int (*cbfunc)(cmi_hdl_t, void *, void *, void *), 154020c794b3Sgavinm void *arg1, void *arg2, void *arg3) 154120c794b3Sgavinm { 15422d39cb4cSVuong Nguyen int i, j; 15432d39cb4cSVuong Nguyen cmi_hdl_ent_t *ent; 15442d2efdc6SVuong Nguyen int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits, 15452d2efdc6SVuong Nguyen cmi_strand_nbits); 154620c794b3Sgavinm 15472d39cb4cSVuong Nguyen for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) { 15482d39cb4cSVuong Nguyen if (cmi_chip_tab[i] == NULL) 15492d39cb4cSVuong Nguyen continue; 15502d2efdc6SVuong Nguyen for (j = 0, ent = cmi_chip_tab[i]; j < max_strands; 15512d39cb4cSVuong Nguyen j++, ent++) { 15522d39cb4cSVuong Nguyen if (cmi_hdl_canref(ent)) { 15532d39cb4cSVuong Nguyen cmi_hdl_impl_t *hdl = ent->cmae_hdlp; 15542d39cb4cSVuong Nguyen if ((*cbfunc)((cmi_hdl_t)hdl, arg1, arg2, arg3) 15552d39cb4cSVuong Nguyen == CMI_HDL_WALK_DONE) { 155620c794b3Sgavinm cmi_hdl_rele((cmi_hdl_t)hdl); 15572d39cb4cSVuong Nguyen return; 155820c794b3Sgavinm } 155920c794b3Sgavinm cmi_hdl_rele((cmi_hdl_t)hdl); 156020c794b3Sgavinm } 156120c794b3Sgavinm } 156220c794b3Sgavinm } 15632d39cb4cSVuong Nguyen } 156420c794b3Sgavinm 156520c794b3Sgavinm void 156620c794b3Sgavinm cmi_hdl_setcmi(cmi_hdl_t ophdl, void *cmi, void *cmidata) 156720c794b3Sgavinm { 156820c794b3Sgavinm IMPLHDL(ophdl)->cmih_cmidata = cmidata; 156920c794b3Sgavinm IMPLHDL(ophdl)->cmih_cmi = cmi; 157020c794b3Sgavinm } 157120c794b3Sgavinm 157220c794b3Sgavinm void * 157320c794b3Sgavinm cmi_hdl_getcmi(cmi_hdl_t ophdl) 157420c794b3Sgavinm { 157520c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_cmi); 157620c794b3Sgavinm } 157720c794b3Sgavinm 157820c794b3Sgavinm void * 157920c794b3Sgavinm cmi_hdl_getcmidata(cmi_hdl_t ophdl) 158020c794b3Sgavinm { 158120c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_cmidata); 158220c794b3Sgavinm } 158320c794b3Sgavinm 158420c794b3Sgavinm enum cmi_hdl_class 158520c794b3Sgavinm cmi_hdl_class(cmi_hdl_t ophdl) 158620c794b3Sgavinm { 158720c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_class); 158820c794b3Sgavinm } 158920c794b3Sgavinm 159020c794b3Sgavinm #define CMI_HDL_OPFUNC(what, type) \ 159120c794b3Sgavinm type \ 159220c794b3Sgavinm cmi_hdl_##what(cmi_hdl_t ophdl) \ 159320c794b3Sgavinm { \ 1594e4b86885SCheng Sean Ye return (HDLOPS(IMPLHDL(ophdl))-> \ 159520c794b3Sgavinm cmio_##what(IMPLHDL(ophdl))); \ 159620c794b3Sgavinm } 159720c794b3Sgavinm 159820c794b3Sgavinm CMI_HDL_OPFUNC(vendor, uint_t) 159920c794b3Sgavinm CMI_HDL_OPFUNC(vendorstr, const char *) 160020c794b3Sgavinm CMI_HDL_OPFUNC(family, uint_t) 160120c794b3Sgavinm CMI_HDL_OPFUNC(model, uint_t) 160220c794b3Sgavinm CMI_HDL_OPFUNC(stepping, uint_t) 160320c794b3Sgavinm CMI_HDL_OPFUNC(chipid, uint_t) 16048031591dSSrihari Venkatesan CMI_HDL_OPFUNC(procnodeid, uint_t) 160520c794b3Sgavinm CMI_HDL_OPFUNC(coreid, uint_t) 160620c794b3Sgavinm CMI_HDL_OPFUNC(strandid, uint_t) 16078031591dSSrihari Venkatesan CMI_HDL_OPFUNC(procnodes_per_pkg, uint_t) 1608074bb90dSTom Pothier CMI_HDL_OPFUNC(strand_apicid, uint_t) 160920c794b3Sgavinm CMI_HDL_OPFUNC(chiprev, uint32_t) 161020c794b3Sgavinm CMI_HDL_OPFUNC(chiprevstr, const char *) 161120c794b3Sgavinm CMI_HDL_OPFUNC(getsockettype, uint32_t) 161289e921d5SKuriakose Kuruvilla CMI_HDL_OPFUNC(getsocketstr, const char *) 1613e4b86885SCheng Sean Ye CMI_HDL_OPFUNC(logical_id, id_t) 1614074bb90dSTom Pothier CMI_HDL_OPFUNC(smbiosid, uint16_t) 1615074bb90dSTom Pothier CMI_HDL_OPFUNC(smb_chipid, uint_t) 1616074bb90dSTom Pothier CMI_HDL_OPFUNC(smb_bboard, nvlist_t *) 1617e4b86885SCheng Sean Ye 1618e4b86885SCheng Sean Ye boolean_t 1619e4b86885SCheng Sean Ye cmi_hdl_is_cmt(cmi_hdl_t ophdl) 1620e4b86885SCheng Sean Ye { 1621e4b86885SCheng Sean Ye return (IMPLHDL(ophdl)->cmih_mstrand); 1622e4b86885SCheng Sean Ye } 162320c794b3Sgavinm 162420c794b3Sgavinm void 1625e3d60c9bSAdrian Frost cmi_hdl_int(cmi_hdl_t ophdl, int num) 162620c794b3Sgavinm { 1627e4b86885SCheng Sean Ye if (HDLOPS(IMPLHDL(ophdl))->cmio_int == NULL) 1628e4b86885SCheng Sean Ye return; 1629e4b86885SCheng Sean Ye 1630e4b86885SCheng Sean Ye cmi_hdl_inj_begin(ophdl); 1631e4b86885SCheng Sean Ye HDLOPS(IMPLHDL(ophdl))->cmio_int(IMPLHDL(ophdl), num); 1632e4b86885SCheng Sean Ye cmi_hdl_inj_end(NULL); 1633e4b86885SCheng Sean Ye } 1634e4b86885SCheng Sean Ye 1635e4b86885SCheng Sean Ye int 1636e4b86885SCheng Sean Ye cmi_hdl_online(cmi_hdl_t ophdl, int new_status, int *old_status) 1637e4b86885SCheng Sean Ye { 1638e4b86885SCheng Sean Ye return (HDLOPS(IMPLHDL(ophdl))->cmio_online(IMPLHDL(ophdl), 1639e4b86885SCheng Sean Ye new_status, old_status)); 164020c794b3Sgavinm } 164120c794b3Sgavinm 164220c794b3Sgavinm #ifndef __xpv 164320c794b3Sgavinm /* 164420c794b3Sgavinm * Return hardware chip instance; cpuid_get_chipid provides this directly. 164520c794b3Sgavinm */ 164620c794b3Sgavinm uint_t 164720c794b3Sgavinm cmi_ntv_hwchipid(cpu_t *cp) 164820c794b3Sgavinm { 164920c794b3Sgavinm return (cpuid_get_chipid(cp)); 165020c794b3Sgavinm } 165120c794b3Sgavinm 165220c794b3Sgavinm /* 16538031591dSSrihari Venkatesan * Return hardware node instance; cpuid_get_procnodeid provides this directly. 16548031591dSSrihari Venkatesan */ 16558031591dSSrihari Venkatesan uint_t 16568031591dSSrihari Venkatesan cmi_ntv_hwprocnodeid(cpu_t *cp) 16578031591dSSrihari Venkatesan { 16588031591dSSrihari Venkatesan return (cpuid_get_procnodeid(cp)); 16598031591dSSrihari Venkatesan } 16608031591dSSrihari Venkatesan 16618031591dSSrihari Venkatesan /* 166210569901Sgavinm * Return core instance within a single chip. 166320c794b3Sgavinm */ 166420c794b3Sgavinm uint_t 166520c794b3Sgavinm cmi_ntv_hwcoreid(cpu_t *cp) 166620c794b3Sgavinm { 166710569901Sgavinm return (cpuid_get_pkgcoreid(cp)); 166820c794b3Sgavinm } 166920c794b3Sgavinm 167020c794b3Sgavinm /* 167120c794b3Sgavinm * Return strand number within a single core. cpuid_get_clogid numbers 167220c794b3Sgavinm * all execution units (strands, or cores in unstranded models) sequentially 167320c794b3Sgavinm * within a single chip. 167420c794b3Sgavinm */ 167520c794b3Sgavinm uint_t 167620c794b3Sgavinm cmi_ntv_hwstrandid(cpu_t *cp) 167720c794b3Sgavinm { 167820c794b3Sgavinm int strands_per_core = cpuid_get_ncpu_per_chip(cp) / 167920c794b3Sgavinm cpuid_get_ncore_per_chip(cp); 168020c794b3Sgavinm 168120c794b3Sgavinm return (cpuid_get_clogid(cp) % strands_per_core); 168220c794b3Sgavinm } 1683a3114836SGerry Liu 1684a3114836SGerry Liu static void 1685a3114836SGerry Liu cmi_ntv_hwdisable_mce_xc(void) 1686a3114836SGerry Liu { 1687a3114836SGerry Liu ulong_t cr4; 1688a3114836SGerry Liu 1689a3114836SGerry Liu cr4 = getcr4(); 1690a3114836SGerry Liu cr4 = cr4 & (~CR4_MCE); 1691a3114836SGerry Liu setcr4(cr4); 1692a3114836SGerry Liu } 1693a3114836SGerry Liu 1694a3114836SGerry Liu void 1695a3114836SGerry Liu cmi_ntv_hwdisable_mce(cmi_hdl_t hdl) 1696a3114836SGerry Liu { 1697a3114836SGerry Liu cpuset_t set; 1698a3114836SGerry Liu cmi_hdl_impl_t *thdl = IMPLHDL(hdl); 1699a3114836SGerry Liu cpu_t *cp = HDLPRIV(thdl); 1700a3114836SGerry Liu 1701a3114836SGerry Liu if (CPU->cpu_id == cp->cpu_id) { 1702a3114836SGerry Liu cmi_ntv_hwdisable_mce_xc(); 1703a3114836SGerry Liu } else { 1704a3114836SGerry Liu CPUSET_ONLY(set, cp->cpu_id); 1705a3114836SGerry Liu xc_call(NULL, NULL, NULL, CPUSET2BV(set), 1706a3114836SGerry Liu (xc_func_t)cmi_ntv_hwdisable_mce_xc); 1707a3114836SGerry Liu } 1708a3114836SGerry Liu } 1709a3114836SGerry Liu 171020c794b3Sgavinm #endif /* __xpv */ 171120c794b3Sgavinm 171220c794b3Sgavinm void 171320c794b3Sgavinm cmi_hdlconf_rdmsr_nohw(cmi_hdl_t ophdl) 171420c794b3Sgavinm { 171520c794b3Sgavinm cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 171620c794b3Sgavinm 171720c794b3Sgavinm hdl->cmih_msrsrc &= ~CMI_MSR_FLAG_RD_HWOK; 171820c794b3Sgavinm } 171920c794b3Sgavinm 172020c794b3Sgavinm void 172120c794b3Sgavinm cmi_hdlconf_wrmsr_nohw(cmi_hdl_t ophdl) 172220c794b3Sgavinm { 172320c794b3Sgavinm cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 172420c794b3Sgavinm 172520c794b3Sgavinm hdl->cmih_msrsrc &= ~CMI_MSR_FLAG_WR_HWOK; 172620c794b3Sgavinm } 172720c794b3Sgavinm 172820c794b3Sgavinm cmi_errno_t 172920c794b3Sgavinm cmi_hdl_rdmsr(cmi_hdl_t ophdl, uint_t msr, uint64_t *valp) 173020c794b3Sgavinm { 173120c794b3Sgavinm cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 173220c794b3Sgavinm 173320c794b3Sgavinm /* 173420c794b3Sgavinm * Regardless of the handle class, we first check for am 173520c794b3Sgavinm * interposed value. In the xVM case you probably want to 173620c794b3Sgavinm * place interposed values within the hypervisor itself, but 173720c794b3Sgavinm * we still allow interposing them in dom0 for test and bringup 173820c794b3Sgavinm * purposes. 173920c794b3Sgavinm */ 174020c794b3Sgavinm if ((hdl->cmih_msrsrc & CMI_MSR_FLAG_RD_INTERPOSEOK) && 174120c794b3Sgavinm msri_lookup(hdl, msr, valp)) 174220c794b3Sgavinm return (CMI_SUCCESS); 174320c794b3Sgavinm 1744e4b86885SCheng Sean Ye if (HDLOPS(hdl)->cmio_rdmsr == NULL) 1745e4b86885SCheng Sean Ye return (CMIERR_NOTSUP); 174620c794b3Sgavinm 1747e4b86885SCheng Sean Ye return (HDLOPS(hdl)->cmio_rdmsr(hdl, msr, valp)); 174820c794b3Sgavinm } 174920c794b3Sgavinm 175020c794b3Sgavinm cmi_errno_t 175120c794b3Sgavinm cmi_hdl_wrmsr(cmi_hdl_t ophdl, uint_t msr, uint64_t val) 175220c794b3Sgavinm { 175320c794b3Sgavinm cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 175420c794b3Sgavinm 175520c794b3Sgavinm /* Invalidate any interposed value */ 175620c794b3Sgavinm msri_rment(hdl, msr); 175720c794b3Sgavinm 1758e4b86885SCheng Sean Ye if (HDLOPS(hdl)->cmio_wrmsr == NULL) 1759e4b86885SCheng Sean Ye return (CMI_SUCCESS); /* pretend all is ok */ 176020c794b3Sgavinm 1761e4b86885SCheng Sean Ye return (HDLOPS(hdl)->cmio_wrmsr(hdl, msr, val)); 176220c794b3Sgavinm } 176320c794b3Sgavinm 176420c794b3Sgavinm void 176520c794b3Sgavinm cmi_hdl_enable_mce(cmi_hdl_t ophdl) 176620c794b3Sgavinm { 176720c794b3Sgavinm cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 1768e4b86885SCheng Sean Ye ulong_t cr4; 176920c794b3Sgavinm 1770e4b86885SCheng Sean Ye if (HDLOPS(hdl)->cmio_getcr4 == NULL || 1771e4b86885SCheng Sean Ye HDLOPS(hdl)->cmio_setcr4 == NULL) 1772e4b86885SCheng Sean Ye return; 1773e4b86885SCheng Sean Ye 1774e4b86885SCheng Sean Ye cr4 = HDLOPS(hdl)->cmio_getcr4(hdl); 1775e4b86885SCheng Sean Ye 1776e4b86885SCheng Sean Ye HDLOPS(hdl)->cmio_setcr4(hdl, cr4 | CR4_MCE); 177720c794b3Sgavinm } 177820c794b3Sgavinm 177920c794b3Sgavinm void 178020c794b3Sgavinm cmi_hdl_msrinterpose(cmi_hdl_t ophdl, cmi_mca_regs_t *regs, uint_t nregs) 178120c794b3Sgavinm { 178220c794b3Sgavinm cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 178320c794b3Sgavinm int i; 178420c794b3Sgavinm 1785e4b86885SCheng Sean Ye if (HDLOPS(hdl)->cmio_msrinterpose == NULL) 1786e4b86885SCheng Sean Ye return; 1787e4b86885SCheng Sean Ye 1788e4b86885SCheng Sean Ye cmi_hdl_inj_begin(ophdl); 1789e4b86885SCheng Sean Ye 1790e4b86885SCheng Sean Ye for (i = 0; i < nregs; i++, regs++) 1791e4b86885SCheng Sean Ye HDLOPS(hdl)->cmio_msrinterpose(hdl, regs->cmr_msrnum, 1792e4b86885SCheng Sean Ye regs->cmr_msrval); 1793e4b86885SCheng Sean Ye 1794e4b86885SCheng Sean Ye cmi_hdl_inj_end(ophdl); 179520c794b3Sgavinm } 179620c794b3Sgavinm 1797e4b86885SCheng Sean Ye /*ARGSUSED*/ 1798e4b86885SCheng Sean Ye void 1799e4b86885SCheng Sean Ye cmi_hdl_msrforward(cmi_hdl_t ophdl, cmi_mca_regs_t *regs, uint_t nregs) 1800e4b86885SCheng Sean Ye { 1801e4b86885SCheng Sean Ye #ifdef __xpv 1802e4b86885SCheng Sean Ye cmi_hdl_impl_t *hdl = IMPLHDL(ophdl); 1803e4b86885SCheng Sean Ye int i; 1804e4b86885SCheng Sean Ye 1805e4b86885SCheng Sean Ye for (i = 0; i < nregs; i++, regs++) 1806e4b86885SCheng Sean Ye msri_addent(hdl, regs->cmr_msrnum, regs->cmr_msrval); 1807e4b86885SCheng Sean Ye #endif 1808e4b86885SCheng Sean Ye } 1809e4b86885SCheng Sean Ye 1810e4b86885SCheng Sean Ye 181120c794b3Sgavinm void 181220c794b3Sgavinm cmi_pcird_nohw(void) 181320c794b3Sgavinm { 181420c794b3Sgavinm cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_RD_HWOK; 181520c794b3Sgavinm } 181620c794b3Sgavinm 181720c794b3Sgavinm void 181820c794b3Sgavinm cmi_pciwr_nohw(void) 181920c794b3Sgavinm { 182020c794b3Sgavinm cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_WR_HWOK; 182120c794b3Sgavinm } 182220c794b3Sgavinm 182320c794b3Sgavinm static uint32_t 182420c794b3Sgavinm cmi_pci_get_cmn(int bus, int dev, int func, int reg, int asz, 182520c794b3Sgavinm int *interpose, ddi_acc_handle_t hdl) 182620c794b3Sgavinm { 182720c794b3Sgavinm uint32_t val; 182820c794b3Sgavinm 182920c794b3Sgavinm if (cmi_pcicfg_flags & CMI_PCICFG_FLAG_RD_INTERPOSEOK && 183020c794b3Sgavinm pcii_lookup(bus, dev, func, reg, asz, &val)) { 183120c794b3Sgavinm if (interpose) 183220c794b3Sgavinm *interpose = 1; 183320c794b3Sgavinm return (val); 183420c794b3Sgavinm } 183520c794b3Sgavinm if (interpose) 183620c794b3Sgavinm *interpose = 0; 183720c794b3Sgavinm 183820c794b3Sgavinm if (!(cmi_pcicfg_flags & CMI_PCICFG_FLAG_RD_HWOK)) 183920c794b3Sgavinm return (0); 184020c794b3Sgavinm 184120c794b3Sgavinm switch (asz) { 184220c794b3Sgavinm case 1: 184320c794b3Sgavinm if (hdl) 184420c794b3Sgavinm val = pci_config_get8(hdl, (off_t)reg); 184520c794b3Sgavinm else 18465667185bSSrihari Venkatesan val = pci_cfgacc_get8(NULL, PCI_GETBDF(bus, dev, func), 18475667185bSSrihari Venkatesan reg); 184820c794b3Sgavinm break; 184920c794b3Sgavinm case 2: 185020c794b3Sgavinm if (hdl) 185120c794b3Sgavinm val = pci_config_get16(hdl, (off_t)reg); 185220c794b3Sgavinm else 18535667185bSSrihari Venkatesan val = pci_cfgacc_get16(NULL, PCI_GETBDF(bus, dev, func), 18545667185bSSrihari Venkatesan reg); 185520c794b3Sgavinm break; 185620c794b3Sgavinm case 4: 185720c794b3Sgavinm if (hdl) 185820c794b3Sgavinm val = pci_config_get32(hdl, (off_t)reg); 185920c794b3Sgavinm else 18605667185bSSrihari Venkatesan val = pci_cfgacc_get32(NULL, PCI_GETBDF(bus, dev, func), 18615667185bSSrihari Venkatesan reg); 186220c794b3Sgavinm break; 186320c794b3Sgavinm default: 186420c794b3Sgavinm val = 0; 186520c794b3Sgavinm } 186620c794b3Sgavinm return (val); 186720c794b3Sgavinm } 186820c794b3Sgavinm 186920c794b3Sgavinm uint8_t 187020c794b3Sgavinm cmi_pci_getb(int bus, int dev, int func, int reg, int *interpose, 187120c794b3Sgavinm ddi_acc_handle_t hdl) 187220c794b3Sgavinm { 187320c794b3Sgavinm return ((uint8_t)cmi_pci_get_cmn(bus, dev, func, reg, 1, interpose, 187420c794b3Sgavinm hdl)); 187520c794b3Sgavinm } 187620c794b3Sgavinm 187720c794b3Sgavinm uint16_t 187820c794b3Sgavinm cmi_pci_getw(int bus, int dev, int func, int reg, int *interpose, 187920c794b3Sgavinm ddi_acc_handle_t hdl) 188020c794b3Sgavinm { 188120c794b3Sgavinm return ((uint16_t)cmi_pci_get_cmn(bus, dev, func, reg, 2, interpose, 188220c794b3Sgavinm hdl)); 188320c794b3Sgavinm } 188420c794b3Sgavinm 188520c794b3Sgavinm uint32_t 188620c794b3Sgavinm cmi_pci_getl(int bus, int dev, int func, int reg, int *interpose, 188720c794b3Sgavinm ddi_acc_handle_t hdl) 188820c794b3Sgavinm { 188920c794b3Sgavinm return (cmi_pci_get_cmn(bus, dev, func, reg, 4, interpose, hdl)); 189020c794b3Sgavinm } 189120c794b3Sgavinm 189220c794b3Sgavinm void 189320c794b3Sgavinm cmi_pci_interposeb(int bus, int dev, int func, int reg, uint8_t val) 189420c794b3Sgavinm { 189520c794b3Sgavinm pcii_addent(bus, dev, func, reg, val, 1); 189620c794b3Sgavinm } 189720c794b3Sgavinm 189820c794b3Sgavinm void 189920c794b3Sgavinm cmi_pci_interposew(int bus, int dev, int func, int reg, uint16_t val) 190020c794b3Sgavinm { 190120c794b3Sgavinm pcii_addent(bus, dev, func, reg, val, 2); 190220c794b3Sgavinm } 190320c794b3Sgavinm 190420c794b3Sgavinm void 190520c794b3Sgavinm cmi_pci_interposel(int bus, int dev, int func, int reg, uint32_t val) 190620c794b3Sgavinm { 190720c794b3Sgavinm pcii_addent(bus, dev, func, reg, val, 4); 190820c794b3Sgavinm } 190920c794b3Sgavinm 191020c794b3Sgavinm static void 191120c794b3Sgavinm cmi_pci_put_cmn(int bus, int dev, int func, int reg, int asz, 191220c794b3Sgavinm ddi_acc_handle_t hdl, uint32_t val) 191320c794b3Sgavinm { 191420c794b3Sgavinm /* 191520c794b3Sgavinm * If there is an interposed value for this register invalidate it. 191620c794b3Sgavinm */ 191720c794b3Sgavinm pcii_rment(bus, dev, func, reg, asz); 191820c794b3Sgavinm 191920c794b3Sgavinm if (!(cmi_pcicfg_flags & CMI_PCICFG_FLAG_WR_HWOK)) 192020c794b3Sgavinm return; 192120c794b3Sgavinm 192220c794b3Sgavinm switch (asz) { 192320c794b3Sgavinm case 1: 192420c794b3Sgavinm if (hdl) 192520c794b3Sgavinm pci_config_put8(hdl, (off_t)reg, (uint8_t)val); 192620c794b3Sgavinm else 19275667185bSSrihari Venkatesan pci_cfgacc_put8(NULL, PCI_GETBDF(bus, dev, func), reg, 19285667185bSSrihari Venkatesan (uint8_t)val); 192920c794b3Sgavinm break; 193020c794b3Sgavinm 193120c794b3Sgavinm case 2: 193220c794b3Sgavinm if (hdl) 193320c794b3Sgavinm pci_config_put16(hdl, (off_t)reg, (uint16_t)val); 193420c794b3Sgavinm else 19355667185bSSrihari Venkatesan pci_cfgacc_put16(NULL, PCI_GETBDF(bus, dev, func), reg, 19365667185bSSrihari Venkatesan (uint16_t)val); 193720c794b3Sgavinm break; 193820c794b3Sgavinm 193920c794b3Sgavinm case 4: 194020c794b3Sgavinm if (hdl) 194120c794b3Sgavinm pci_config_put32(hdl, (off_t)reg, val); 194220c794b3Sgavinm else 19435667185bSSrihari Venkatesan pci_cfgacc_put32(NULL, PCI_GETBDF(bus, dev, func), reg, 19445667185bSSrihari Venkatesan val); 194520c794b3Sgavinm break; 194620c794b3Sgavinm 194720c794b3Sgavinm default: 194820c794b3Sgavinm break; 194920c794b3Sgavinm } 195020c794b3Sgavinm } 195120c794b3Sgavinm 1952e4b86885SCheng Sean Ye void 195320c794b3Sgavinm cmi_pci_putb(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl, 195420c794b3Sgavinm uint8_t val) 195520c794b3Sgavinm { 195620c794b3Sgavinm cmi_pci_put_cmn(bus, dev, func, reg, 1, hdl, val); 195720c794b3Sgavinm } 195820c794b3Sgavinm 1959e4b86885SCheng Sean Ye void 196020c794b3Sgavinm cmi_pci_putw(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl, 196120c794b3Sgavinm uint16_t val) 196220c794b3Sgavinm { 196320c794b3Sgavinm cmi_pci_put_cmn(bus, dev, func, reg, 2, hdl, val); 196420c794b3Sgavinm } 196520c794b3Sgavinm 1966e4b86885SCheng Sean Ye void 196720c794b3Sgavinm cmi_pci_putl(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl, 196820c794b3Sgavinm uint32_t val) 196920c794b3Sgavinm { 197020c794b3Sgavinm cmi_pci_put_cmn(bus, dev, func, reg, 4, hdl, val); 197120c794b3Sgavinm } 1972e4b86885SCheng Sean Ye 1973e4b86885SCheng Sean Ye static const struct cmi_hdl_ops cmi_hdl_ops = { 1974e4b86885SCheng Sean Ye #ifdef __xpv 1975e4b86885SCheng Sean Ye /* 1976e4b86885SCheng Sean Ye * CMI_HDL_SOLARIS_xVM_MCA - ops when we are an xVM dom0 1977e4b86885SCheng Sean Ye */ 1978e4b86885SCheng Sean Ye xpv_vendor, /* cmio_vendor */ 1979e4b86885SCheng Sean Ye xpv_vendorstr, /* cmio_vendorstr */ 1980e4b86885SCheng Sean Ye xpv_family, /* cmio_family */ 1981e4b86885SCheng Sean Ye xpv_model, /* cmio_model */ 1982e4b86885SCheng Sean Ye xpv_stepping, /* cmio_stepping */ 1983e4b86885SCheng Sean Ye xpv_chipid, /* cmio_chipid */ 19848031591dSSrihari Venkatesan xpv_procnodeid, /* cmio_procnodeid */ 1985e4b86885SCheng Sean Ye xpv_coreid, /* cmio_coreid */ 1986e4b86885SCheng Sean Ye xpv_strandid, /* cmio_strandid */ 19878031591dSSrihari Venkatesan xpv_procnodes_per_pkg, /* cmio_procnodes_per_pkg */ 1988074bb90dSTom Pothier xpv_strand_apicid, /* cmio_strand_apicid */ 1989e4b86885SCheng Sean Ye xpv_chiprev, /* cmio_chiprev */ 1990e4b86885SCheng Sean Ye xpv_chiprevstr, /* cmio_chiprevstr */ 1991e4b86885SCheng Sean Ye xpv_getsockettype, /* cmio_getsockettype */ 199289e921d5SKuriakose Kuruvilla xpv_getsocketstr, /* cmio_getsocketstr */ 1993e4b86885SCheng Sean Ye xpv_logical_id, /* cmio_logical_id */ 1994e4b86885SCheng Sean Ye NULL, /* cmio_getcr4 */ 1995e4b86885SCheng Sean Ye NULL, /* cmio_setcr4 */ 1996e4b86885SCheng Sean Ye xpv_rdmsr, /* cmio_rdmsr */ 1997e4b86885SCheng Sean Ye xpv_wrmsr, /* cmio_wrmsr */ 1998e4b86885SCheng Sean Ye xpv_msrinterpose, /* cmio_msrinterpose */ 1999e4b86885SCheng Sean Ye xpv_int, /* cmio_int */ 2000074bb90dSTom Pothier xpv_online, /* cmio_online */ 2001074bb90dSTom Pothier xpv_smbiosid, /* cmio_smbiosid */ 2002074bb90dSTom Pothier xpv_smb_chipid, /* cmio_smb_chipid */ 2003074bb90dSTom Pothier xpv_smb_bboard /* cmio_smb_bboard */ 2004e4b86885SCheng Sean Ye 2005e4b86885SCheng Sean Ye #else /* __xpv */ 2006e4b86885SCheng Sean Ye 2007e4b86885SCheng Sean Ye /* 2008e4b86885SCheng Sean Ye * CMI_HDL_NATIVE - ops when apparently running on bare-metal 2009e4b86885SCheng Sean Ye */ 2010e4b86885SCheng Sean Ye ntv_vendor, /* cmio_vendor */ 2011e4b86885SCheng Sean Ye ntv_vendorstr, /* cmio_vendorstr */ 2012e4b86885SCheng Sean Ye ntv_family, /* cmio_family */ 2013e4b86885SCheng Sean Ye ntv_model, /* cmio_model */ 2014e4b86885SCheng Sean Ye ntv_stepping, /* cmio_stepping */ 2015e4b86885SCheng Sean Ye ntv_chipid, /* cmio_chipid */ 20168031591dSSrihari Venkatesan ntv_procnodeid, /* cmio_procnodeid */ 2017e4b86885SCheng Sean Ye ntv_coreid, /* cmio_coreid */ 2018e4b86885SCheng Sean Ye ntv_strandid, /* cmio_strandid */ 20198031591dSSrihari Venkatesan ntv_procnodes_per_pkg, /* cmio_procnodes_per_pkg */ 20208031591dSSrihari Venkatesan ntv_strand_apicid, /* cmio_strand_apicid */ 2021e4b86885SCheng Sean Ye ntv_chiprev, /* cmio_chiprev */ 2022e4b86885SCheng Sean Ye ntv_chiprevstr, /* cmio_chiprevstr */ 2023e4b86885SCheng Sean Ye ntv_getsockettype, /* cmio_getsockettype */ 202489e921d5SKuriakose Kuruvilla ntv_getsocketstr, /* cmio_getsocketstr */ 2025e4b86885SCheng Sean Ye ntv_logical_id, /* cmio_logical_id */ 2026e4b86885SCheng Sean Ye ntv_getcr4, /* cmio_getcr4 */ 2027e4b86885SCheng Sean Ye ntv_setcr4, /* cmio_setcr4 */ 2028e4b86885SCheng Sean Ye ntv_rdmsr, /* cmio_rdmsr */ 2029e4b86885SCheng Sean Ye ntv_wrmsr, /* cmio_wrmsr */ 2030e4b86885SCheng Sean Ye ntv_msrinterpose, /* cmio_msrinterpose */ 2031e4b86885SCheng Sean Ye ntv_int, /* cmio_int */ 2032074bb90dSTom Pothier ntv_online, /* cmio_online */ 2033074bb90dSTom Pothier ntv_smbiosid, /* cmio_smbiosid */ 2034074bb90dSTom Pothier ntv_smb_chipid, /* cmio_smb_chipid */ 2035074bb90dSTom Pothier ntv_smb_bboard /* cmio_smb_bboard */ 2036e4b86885SCheng Sean Ye #endif 2037e4b86885SCheng Sean Ye }; 2038