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
call_func_ntv(int cpuid,xc_func_t func,xc_arg_t arg1,xc_arg_t arg2)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
cmi_hdl_inj_begin(cmi_hdl_t ophdl)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
cmi_hdl_inj_end(cmi_hdl_t ophdl)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
cmi_inj_tainted(void)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
msri_addent(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)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
msri_lookup(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t * valp)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
msri_rment(cmi_hdl_impl_t * hdl,uint_t msr)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
pcii_addent(int bus,int dev,int func,int reg,uint32_t val,int asz)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
pcii_lookup(int bus,int dev,int func,int reg,int asz,uint32_t * valp)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
pcii_rment(int bus,int dev,int func,int reg,int asz)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
ntv_vendor(cmi_hdl_impl_t * hdl)57920c794b3Sgavinm ntv_vendor(cmi_hdl_impl_t *hdl)
58020c794b3Sgavinm {
581e4b86885SCheng Sean Ye return (cpuid_getvendor(HDLPRIV(hdl)));
58220c794b3Sgavinm }
58320c794b3Sgavinm
58420c794b3Sgavinm static const char *
ntv_vendorstr(cmi_hdl_impl_t * hdl)58520c794b3Sgavinm ntv_vendorstr(cmi_hdl_impl_t *hdl)
58620c794b3Sgavinm {
587e4b86885SCheng Sean Ye return (cpuid_getvendorstr(HDLPRIV(hdl)));
58820c794b3Sgavinm }
58920c794b3Sgavinm
59020c794b3Sgavinm static uint_t
ntv_family(cmi_hdl_impl_t * hdl)59120c794b3Sgavinm ntv_family(cmi_hdl_impl_t *hdl)
59220c794b3Sgavinm {
593e4b86885SCheng Sean Ye return (cpuid_getfamily(HDLPRIV(hdl)));
59420c794b3Sgavinm }
59520c794b3Sgavinm
59620c794b3Sgavinm static uint_t
ntv_model(cmi_hdl_impl_t * hdl)59720c794b3Sgavinm ntv_model(cmi_hdl_impl_t *hdl)
59820c794b3Sgavinm {
599e4b86885SCheng Sean Ye return (cpuid_getmodel(HDLPRIV(hdl)));
60020c794b3Sgavinm }
60120c794b3Sgavinm
60220c794b3Sgavinm static uint_t
ntv_stepping(cmi_hdl_impl_t * hdl)60320c794b3Sgavinm ntv_stepping(cmi_hdl_impl_t *hdl)
60420c794b3Sgavinm {
605e4b86885SCheng Sean Ye return (cpuid_getstep(HDLPRIV(hdl)));
60620c794b3Sgavinm }
60720c794b3Sgavinm
60820c794b3Sgavinm static uint_t
ntv_chipid(cmi_hdl_impl_t * hdl)60920c794b3Sgavinm ntv_chipid(cmi_hdl_impl_t *hdl)
61020c794b3Sgavinm {
61120c794b3Sgavinm return (hdl->cmih_chipid);
61220c794b3Sgavinm
61320c794b3Sgavinm }
61420c794b3Sgavinm
61520c794b3Sgavinm static uint_t
ntv_procnodeid(cmi_hdl_impl_t * hdl)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
ntv_procnodes_per_pkg(cmi_hdl_impl_t * hdl)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
ntv_coreid(cmi_hdl_impl_t * hdl)62820c794b3Sgavinm ntv_coreid(cmi_hdl_impl_t *hdl)
62920c794b3Sgavinm {
63020c794b3Sgavinm return (hdl->cmih_coreid);
63120c794b3Sgavinm }
63220c794b3Sgavinm
63320c794b3Sgavinm static uint_t
ntv_strandid(cmi_hdl_impl_t * hdl)63420c794b3Sgavinm ntv_strandid(cmi_hdl_impl_t *hdl)
63520c794b3Sgavinm {
63620c794b3Sgavinm return (hdl->cmih_strandid);
63720c794b3Sgavinm }
63820c794b3Sgavinm
639074bb90dSTom Pothier static uint_t
ntv_strand_apicid(cmi_hdl_impl_t * hdl)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
ntv_smbiosid(cmi_hdl_impl_t * hdl)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
ntv_smb_chipid(cmi_hdl_impl_t * hdl)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 *
ntv_smb_bboard(cmi_hdl_impl_t * hdl)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
ntv_chiprev(cmi_hdl_impl_t * hdl)66420c794b3Sgavinm ntv_chiprev(cmi_hdl_impl_t *hdl)
66520c794b3Sgavinm {
666e4b86885SCheng Sean Ye return (cpuid_getchiprev(HDLPRIV(hdl)));
66720c794b3Sgavinm }
66820c794b3Sgavinm
66920c794b3Sgavinm static const char *
ntv_chiprevstr(cmi_hdl_impl_t * hdl)67020c794b3Sgavinm ntv_chiprevstr(cmi_hdl_impl_t *hdl)
67120c794b3Sgavinm {
672e4b86885SCheng Sean Ye return (cpuid_getchiprevstr(HDLPRIV(hdl)));
67320c794b3Sgavinm }
67420c794b3Sgavinm
67520c794b3Sgavinm static uint32_t
ntv_getsockettype(cmi_hdl_impl_t * hdl)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 *
ntv_getsocketstr(cmi_hdl_impl_t * hdl)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
ntv_logical_id(cmi_hdl_impl_t * hdl)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
ntv_getcr4_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)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
ntv_getcr4(cmi_hdl_impl_t * hdl)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
ntv_setcr4_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)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
ntv_setcr4(cmi_hdl_impl_t * hdl,ulong_t val)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
ntv_rdmsr_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)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
ntv_rdmsr(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t * valp)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
ntv_wrmsr_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)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
ntv_wrmsr(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)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
ntv_msrinterpose(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)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
ntv_int_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)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
ntv_int(cmi_hdl_impl_t * hdl,int int_no)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
ntv_online(cmi_hdl_impl_t * hdl,int new_status,int * old_status)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
xpv_vendor(cmi_hdl_impl_t * hdl)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 *
xpv_vendorstr(cmi_hdl_impl_t * hdl)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
xpv_family(cmi_hdl_impl_t * hdl)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
xpv_model(cmi_hdl_impl_t * hdl)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
xpv_stepping(cmi_hdl_impl_t * hdl)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
xpv_chipid(cmi_hdl_impl_t * hdl)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
xpv_procnodeid(cmi_hdl_impl_t * hdl)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
xpv_procnodes_per_pkg(cmi_hdl_impl_t * hdl)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
xpv_coreid(cmi_hdl_impl_t * hdl)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
xpv_strandid(cmi_hdl_impl_t * hdl)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
xpv_strand_apicid(cmi_hdl_impl_t * hdl)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
xpv_smbiosid(cmi_hdl_impl_t * hdl)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
xpv_smb_chipid(cmi_hdl_impl_t * hdl)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 *
xpv_smb_bboard(cmi_hdl_impl_t * hdl)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
xpv_chiprev(cmi_hdl_impl_t * hdl)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 *
xpv_chiprevstr(cmi_hdl_impl_t * hdl)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
xpv_getsockettype(cmi_hdl_impl_t * hdl)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 *
xpv_getsocketstr(cmi_hdl_impl_t * hdl)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
xpv_logical_id(cmi_hdl_impl_t * hdl)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
xpv_rdmsr(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t * valp)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
xpv_wrmsr_cmn(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val,boolean_t intpose)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
xpv_wrmsr(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)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
xpv_msrinterpose(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)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
xpv_int(cmi_hdl_impl_t * hdl,int int_no)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
xpv_online(cmi_hdl_impl_t * hdl,int new_status,int * old_status)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 *
cpu_search(enum cmi_hdl_class class,uint_t chipid,uint_t coreid,uint_t strandid)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
cpu_is_cmt(void * priv)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 *
cmi_hdl_ent_lookup(uint_t chipid,uint_t coreid,uint_t strandid)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
cmi_hdl_create(enum cmi_hdl_class class,uint_t chipid,uint_t coreid,uint_t strandid)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
cmi_read_smbios(cmi_hdl_t ophdl)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
cmi_hdl_hold(cmi_hdl_t ophdl)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
cmi_hdl_canref(cmi_hdl_ent_t * ent)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
cmi_hdl_rele(cmi_hdl_t ophdl)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
cmi_hdl_destroy(cmi_hdl_t ophdl)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
cmi_hdl_setspecific(cmi_hdl_t ophdl,void * arg)145320c794b3Sgavinm cmi_hdl_setspecific(cmi_hdl_t ophdl, void *arg)
145420c794b3Sgavinm {
145520c794b3Sgavinm IMPLHDL(ophdl)->cmih_spec = arg;
145620c794b3Sgavinm }
145720c794b3Sgavinm
145820c794b3Sgavinm void *
cmi_hdl_getspecific(cmi_hdl_t ophdl)145920c794b3Sgavinm cmi_hdl_getspecific(cmi_hdl_t ophdl)
146020c794b3Sgavinm {
146120c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_spec);
146220c794b3Sgavinm }
146320c794b3Sgavinm
146420c794b3Sgavinm void
cmi_hdl_setmc(cmi_hdl_t ophdl,const struct cmi_mc_ops * mcops,void * mcdata)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 *
cmi_hdl_getmcops(cmi_hdl_t ophdl)147520c794b3Sgavinm cmi_hdl_getmcops(cmi_hdl_t ophdl)
147620c794b3Sgavinm {
147720c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_mcops);
147820c794b3Sgavinm }
147920c794b3Sgavinm
148020c794b3Sgavinm void *
cmi_hdl_getmcdata(cmi_hdl_t ophdl)148120c794b3Sgavinm cmi_hdl_getmcdata(cmi_hdl_t ophdl)
148220c794b3Sgavinm {
148320c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_mcdata);
148420c794b3Sgavinm }
148520c794b3Sgavinm
148620c794b3Sgavinm cmi_hdl_t
cmi_hdl_lookup(enum cmi_hdl_class class,uint_t chipid,uint_t coreid,uint_t strandid)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
cmi_hdl_any(void)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
cmi_hdl_walk(int (* cbfunc)(cmi_hdl_t,void *,void *,void *),void * arg1,void * arg2,void * arg3)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
cmi_hdl_setcmi(cmi_hdl_t ophdl,void * cmi,void * cmidata)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 *
cmi_hdl_getcmi(cmi_hdl_t ophdl)157320c794b3Sgavinm cmi_hdl_getcmi(cmi_hdl_t ophdl)
157420c794b3Sgavinm {
157520c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_cmi);
157620c794b3Sgavinm }
157720c794b3Sgavinm
157820c794b3Sgavinm void *
cmi_hdl_getcmidata(cmi_hdl_t ophdl)157920c794b3Sgavinm cmi_hdl_getcmidata(cmi_hdl_t ophdl)
158020c794b3Sgavinm {
158120c794b3Sgavinm return (IMPLHDL(ophdl)->cmih_cmidata);
158220c794b3Sgavinm }
158320c794b3Sgavinm
158420c794b3Sgavinm enum cmi_hdl_class
cmi_hdl_class(cmi_hdl_t ophdl)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
CMI_HDL_OPFUNC(vendor,uint_t)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
cmi_hdl_int(cmi_hdl_t ophdl,int num)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
cmi_hdl_online(cmi_hdl_t ophdl,int new_status,int * old_status)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
cmi_ntv_hwchipid(cpu_t * cp)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
cmi_ntv_hwprocnodeid(cpu_t * cp)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
cmi_ntv_hwcoreid(cpu_t * cp)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
cmi_ntv_hwstrandid(cpu_t * cp)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
cmi_ntv_hwdisable_mce_xc(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
cmi_ntv_hwdisable_mce(cmi_hdl_t hdl)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
cmi_hdlconf_rdmsr_nohw(cmi_hdl_t ophdl)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
cmi_hdlconf_wrmsr_nohw(cmi_hdl_t ophdl)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
cmi_hdl_rdmsr(cmi_hdl_t ophdl,uint_t msr,uint64_t * valp)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
cmi_hdl_wrmsr(cmi_hdl_t ophdl,uint_t msr,uint64_t val)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
cmi_hdl_enable_mce(cmi_hdl_t ophdl)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
cmi_hdl_msrinterpose(cmi_hdl_t ophdl,cmi_mca_regs_t * regs,uint_t nregs)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
cmi_hdl_msrforward(cmi_hdl_t ophdl,cmi_mca_regs_t * regs,uint_t nregs)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
cmi_pcird_nohw(void)181220c794b3Sgavinm cmi_pcird_nohw(void)
181320c794b3Sgavinm {
181420c794b3Sgavinm cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_RD_HWOK;
181520c794b3Sgavinm }
181620c794b3Sgavinm
181720c794b3Sgavinm void
cmi_pciwr_nohw(void)181820c794b3Sgavinm cmi_pciwr_nohw(void)
181920c794b3Sgavinm {
182020c794b3Sgavinm cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_WR_HWOK;
182120c794b3Sgavinm }
182220c794b3Sgavinm
182320c794b3Sgavinm static uint32_t
cmi_pci_get_cmn(int bus,int dev,int func,int reg,int asz,int * interpose,ddi_acc_handle_t hdl)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
cmi_pci_getb(int bus,int dev,int func,int reg,int * interpose,ddi_acc_handle_t hdl)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
cmi_pci_getw(int bus,int dev,int func,int reg,int * interpose,ddi_acc_handle_t hdl)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
cmi_pci_getl(int bus,int dev,int func,int reg,int * interpose,ddi_acc_handle_t hdl)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
cmi_pci_interposeb(int bus,int dev,int func,int reg,uint8_t val)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
cmi_pci_interposew(int bus,int dev,int func,int reg,uint16_t val)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
cmi_pci_interposel(int bus,int dev,int func,int reg,uint32_t val)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
cmi_pci_put_cmn(int bus,int dev,int func,int reg,int asz,ddi_acc_handle_t hdl,uint32_t val)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
cmi_pci_putb(int bus,int dev,int func,int reg,ddi_acc_handle_t hdl,uint8_t val)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
cmi_pci_putw(int bus,int dev,int func,int reg,ddi_acc_handle_t hdl,uint16_t val)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
cmi_pci_putl(int bus,int dev,int func,int reg,ddi_acc_handle_t hdl,uint32_t val)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