xref: /onnv-gate/usr/src/uts/i86pc/os/cmi_hw.c (revision 12261:52117d41c06e)
15254Sgavinm /*
25254Sgavinm  * CDDL HEADER START
35254Sgavinm  *
45254Sgavinm  * The contents of this file are subject to the terms of the
55254Sgavinm  * Common Development and Distribution License (the "License").
65254Sgavinm  * You may not use this file except in compliance with the License.
75254Sgavinm  *
85254Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95254Sgavinm  * or http://www.opensolaris.org/os/licensing.
105254Sgavinm  * See the License for the specific language governing permissions
115254Sgavinm  * and limitations under the License.
125254Sgavinm  *
135254Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
145254Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155254Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
165254Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
175254Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
185254Sgavinm  *
195254Sgavinm  * CDDL HEADER END
205254Sgavinm  */
215254Sgavinm 
225254Sgavinm /*
23*12261SVuong.Nguyen@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245254Sgavinm  */
2512004Sjiang.liu@intel.com /*
2612004Sjiang.liu@intel.com  * Copyright (c) 2010, Intel Corporation.
2712004Sjiang.liu@intel.com  * All rights reserved.
2812004Sjiang.liu@intel.com  */
295254Sgavinm 
305254Sgavinm /*
315254Sgavinm  * CPU Module Interface - hardware abstraction.
325254Sgavinm  */
335254Sgavinm 
3410175SStuart.Maybee@Sun.COM #ifdef __xpv
3510175SStuart.Maybee@Sun.COM #include <sys/xpv_user.h>
3610175SStuart.Maybee@Sun.COM #endif
3710175SStuart.Maybee@Sun.COM 
385254Sgavinm #include <sys/types.h>
395254Sgavinm #include <sys/cpu_module.h>
405254Sgavinm #include <sys/kmem.h>
415254Sgavinm #include <sys/x86_archext.h>
425254Sgavinm #include <sys/cpuvar.h>
435254Sgavinm #include <sys/ksynch.h>
445254Sgavinm #include <sys/x_call.h>
455254Sgavinm #include <sys/pghw.h>
4611947Ssrihari.venkatesan@oracle.com #include <sys/pci_cfgacc.h>
475254Sgavinm #include <sys/pci_cfgspace.h>
485254Sgavinm #include <sys/archsystm.h>
495254Sgavinm #include <sys/ontrap.h>
505254Sgavinm #include <sys/controlregs.h>
515254Sgavinm #include <sys/sunddi.h>
527349SAdrian.Frost@Sun.COM #include <sys/trap.h>
537532SSean.Ye@Sun.COM #include <sys/mca_x86.h>
547532SSean.Ye@Sun.COM #include <sys/processor.h>
5510942STom.Pothier@Sun.COM #include <sys/cmn_err.h>
5610942STom.Pothier@Sun.COM #include <sys/nvpair.h>
5710942STom.Pothier@Sun.COM #include <sys/fm/util.h>
5810942STom.Pothier@Sun.COM #include <sys/fm/protocol.h>
5910942STom.Pothier@Sun.COM #include <sys/fm/smb/fmsmb.h>
6010942STom.Pothier@Sun.COM #include <sys/cpu_module_impl.h>
6110942STom.Pothier@Sun.COM 
6210942STom.Pothier@Sun.COM /*
6310942STom.Pothier@Sun.COM  * Variable which determines if the SMBIOS supports x86 generic topology; or
6410942STom.Pothier@Sun.COM  * if legacy topolgy enumeration will occur.
6510942STom.Pothier@Sun.COM  */
6610942STom.Pothier@Sun.COM extern int x86gentopo_legacy;
677532SSean.Ye@Sun.COM 
685254Sgavinm /*
695254Sgavinm  * Outside of this file consumers use the opaque cmi_hdl_t.  This
705254Sgavinm  * definition is duplicated in the generic_cpu mdb module, so keep
715254Sgavinm  * them in-sync when making changes.
725254Sgavinm  */
735254Sgavinm typedef struct cmi_hdl_impl {
745254Sgavinm 	enum cmi_hdl_class cmih_class;		/* Handle nature */
757532SSean.Ye@Sun.COM 	const struct cmi_hdl_ops *cmih_ops;	/* Operations vector */
765254Sgavinm 	uint_t cmih_chipid;			/* Chipid of cpu resource */
7710947SSrihari.Venkatesan@Sun.COM 	uint_t cmih_procnodeid;			/* Nodeid of cpu resource */
785254Sgavinm 	uint_t cmih_coreid;			/* Core within die */
795254Sgavinm 	uint_t cmih_strandid;			/* Thread within core */
8010947SSrihari.Venkatesan@Sun.COM 	uint_t cmih_procnodes_per_pkg;		/* Nodes in a processor */
817532SSean.Ye@Sun.COM 	boolean_t cmih_mstrand;			/* cores are multithreaded */
825254Sgavinm 	volatile uint32_t *cmih_refcntp;	/* Reference count pointer */
835254Sgavinm 	uint64_t cmih_msrsrc;			/* MSR data source flags */
845254Sgavinm 	void *cmih_hdlpriv;			/* cmi_hw.c private data */
855254Sgavinm 	void *cmih_spec;			/* cmi_hdl_{set,get}_specific */
865254Sgavinm 	void *cmih_cmi;				/* cpu mod control structure */
875254Sgavinm 	void *cmih_cmidata;			/* cpu mod private data */
885254Sgavinm 	const struct cmi_mc_ops *cmih_mcops;	/* Memory-controller ops */
895254Sgavinm 	void *cmih_mcdata;			/* Memory-controller data */
907532SSean.Ye@Sun.COM 	uint64_t cmih_flags;			/* See CMIH_F_* below */
9110942STom.Pothier@Sun.COM 	uint16_t cmih_smbiosid;			/* SMBIOS Type 4 struct ID */
9210942STom.Pothier@Sun.COM 	uint_t cmih_smb_chipid;			/* SMBIOS factored chipid */
9310942STom.Pothier@Sun.COM 	nvlist_t *cmih_smb_bboard;		/* SMBIOS bboard nvlist */
945254Sgavinm } cmi_hdl_impl_t;
955254Sgavinm 
965254Sgavinm #define	IMPLHDL(ophdl)	((cmi_hdl_impl_t *)ophdl)
977532SSean.Ye@Sun.COM #define	HDLOPS(hdl)	((hdl)->cmih_ops)
987532SSean.Ye@Sun.COM 
997532SSean.Ye@Sun.COM #define	CMIH_F_INJACTV		0x1ULL
10012004Sjiang.liu@intel.com #define	CMIH_F_DEAD		0x2ULL
1017532SSean.Ye@Sun.COM 
1027532SSean.Ye@Sun.COM /*
1037532SSean.Ye@Sun.COM  * Ops structure for handle operations.
1047532SSean.Ye@Sun.COM  */
1057532SSean.Ye@Sun.COM struct cmi_hdl_ops {
1067532SSean.Ye@Sun.COM 	/*
1077532SSean.Ye@Sun.COM 	 * These ops are required in an implementation.
1087532SSean.Ye@Sun.COM 	 */
1097532SSean.Ye@Sun.COM 	uint_t (*cmio_vendor)(cmi_hdl_impl_t *);
1107532SSean.Ye@Sun.COM 	const char *(*cmio_vendorstr)(cmi_hdl_impl_t *);
1117532SSean.Ye@Sun.COM 	uint_t (*cmio_family)(cmi_hdl_impl_t *);
1127532SSean.Ye@Sun.COM 	uint_t (*cmio_model)(cmi_hdl_impl_t *);
1137532SSean.Ye@Sun.COM 	uint_t (*cmio_stepping)(cmi_hdl_impl_t *);
1147532SSean.Ye@Sun.COM 	uint_t (*cmio_chipid)(cmi_hdl_impl_t *);
11510947SSrihari.Venkatesan@Sun.COM 	uint_t (*cmio_procnodeid)(cmi_hdl_impl_t *);
1167532SSean.Ye@Sun.COM 	uint_t (*cmio_coreid)(cmi_hdl_impl_t *);
1177532SSean.Ye@Sun.COM 	uint_t (*cmio_strandid)(cmi_hdl_impl_t *);
11810947SSrihari.Venkatesan@Sun.COM 	uint_t (*cmio_procnodes_per_pkg)(cmi_hdl_impl_t *);
11910942STom.Pothier@Sun.COM 	uint_t (*cmio_strand_apicid)(cmi_hdl_impl_t *);
1207532SSean.Ye@Sun.COM 	uint32_t (*cmio_chiprev)(cmi_hdl_impl_t *);
1217532SSean.Ye@Sun.COM 	const char *(*cmio_chiprevstr)(cmi_hdl_impl_t *);
1227532SSean.Ye@Sun.COM 	uint32_t (*cmio_getsockettype)(cmi_hdl_impl_t *);
1239482SKuriakose.Kuruvilla@Sun.COM 	const char *(*cmio_getsocketstr)(cmi_hdl_impl_t *);
1249482SKuriakose.Kuruvilla@Sun.COM 
1257532SSean.Ye@Sun.COM 	id_t (*cmio_logical_id)(cmi_hdl_impl_t *);
1267532SSean.Ye@Sun.COM 	/*
1277532SSean.Ye@Sun.COM 	 * These ops are optional in an implementation.
1287532SSean.Ye@Sun.COM 	 */
1297532SSean.Ye@Sun.COM 	ulong_t (*cmio_getcr4)(cmi_hdl_impl_t *);
1307532SSean.Ye@Sun.COM 	void (*cmio_setcr4)(cmi_hdl_impl_t *, ulong_t);
1317532SSean.Ye@Sun.COM 	cmi_errno_t (*cmio_rdmsr)(cmi_hdl_impl_t *, uint_t, uint64_t *);
1327532SSean.Ye@Sun.COM 	cmi_errno_t (*cmio_wrmsr)(cmi_hdl_impl_t *, uint_t, uint64_t);
1337532SSean.Ye@Sun.COM 	cmi_errno_t (*cmio_msrinterpose)(cmi_hdl_impl_t *, uint_t, uint64_t);
1347532SSean.Ye@Sun.COM 	void (*cmio_int)(cmi_hdl_impl_t *, int);
1357532SSean.Ye@Sun.COM 	int (*cmio_online)(cmi_hdl_impl_t *, int, int *);
13610942STom.Pothier@Sun.COM 	uint16_t (*cmio_smbiosid) (cmi_hdl_impl_t *);
13710942STom.Pothier@Sun.COM 	uint_t (*cmio_smb_chipid)(cmi_hdl_impl_t *);
13810942STom.Pothier@Sun.COM 	nvlist_t *(*cmio_smb_bboard)(cmi_hdl_impl_t *);
1397532SSean.Ye@Sun.COM };
1407532SSean.Ye@Sun.COM 
1417532SSean.Ye@Sun.COM static const struct cmi_hdl_ops cmi_hdl_ops;
1425254Sgavinm 
1435254Sgavinm /*
1445254Sgavinm  * Handles are looked up from contexts such as polling, injection etc
1455254Sgavinm  * where the context is reasonably well defined (although a poller could
1465254Sgavinm  * interrupt any old thread holding any old lock).  They are also looked
1475254Sgavinm  * up by machine check handlers, which may strike at inconvenient times
1485254Sgavinm  * such as during handle initialization or destruction or during handle
1495254Sgavinm  * lookup (which the #MC handler itself will also have to perform).
1505254Sgavinm  *
1515254Sgavinm  * So keeping handles in a linked list makes locking difficult when we
1529090SVuong.Nguyen@Sun.COM  * consider #MC handlers.  Our solution is to have a look-up table indexed
1535254Sgavinm  * by that which uniquely identifies a handle - chip/core/strand id -
1549090SVuong.Nguyen@Sun.COM  * with each entry a structure including a pointer to a handle
1555254Sgavinm  * structure for the resource, and a reference count for the handle.
1565254Sgavinm  * Reference counts are modified atomically.  The public cmi_hdl_hold
1575254Sgavinm  * always succeeds because this can only be used after handle creation
1587532SSean.Ye@Sun.COM  * and before the call to destruct, so the hold count is already at least one.
1595254Sgavinm  * In other functions that lookup a handle (cmi_hdl_lookup, cmi_hdl_any)
1605254Sgavinm  * we must be certain that the count has not already decrmented to zero
1615254Sgavinm  * before applying our hold.
1625254Sgavinm  *
1639090SVuong.Nguyen@Sun.COM  * The table is an array of maximum number of chips defined in
1649090SVuong.Nguyen@Sun.COM  * CMI_CHIPID_ARR_SZ indexed by the chip id. If the chip is not present, the
1659090SVuong.Nguyen@Sun.COM  * entry is NULL. Each entry is a pointer to another array which contains a
1669090SVuong.Nguyen@Sun.COM  * list of all strands of the chip. This first level table is allocated when
1679090SVuong.Nguyen@Sun.COM  * first we want to populate an entry. The size of the latter (per chip) table
1689090SVuong.Nguyen@Sun.COM  * is CMI_MAX_STRANDS_PER_CHIP and it is populated when one of its cpus starts.
1699090SVuong.Nguyen@Sun.COM  *
1709090SVuong.Nguyen@Sun.COM  * Ideally we should only allocate to the actual number of chips, cores per
1719090SVuong.Nguyen@Sun.COM  * chip and strand per core. The number of chips is not available until all
1729090SVuong.Nguyen@Sun.COM  * of them are passed. The number of cores and strands are partially available.
1739090SVuong.Nguyen@Sun.COM  * For now we stick with the above approach.
1745254Sgavinm  */
1759090SVuong.Nguyen@Sun.COM #define	CMI_MAX_CHIPID_NBITS		6	/* max chipid of 63 */
1769090SVuong.Nguyen@Sun.COM #define	CMI_MAX_CORES_PER_CHIP_NBITS	4	/* 16 cores per chip max */
1779090SVuong.Nguyen@Sun.COM #define	CMI_MAX_STRANDS_PER_CORE_NBITS	3	/* 8 strands per core max */
1786000Sgavinm 
1799090SVuong.Nguyen@Sun.COM #define	CMI_MAX_CHIPID			((1 << (CMI_MAX_CHIPID_NBITS)) - 1)
180*12261SVuong.Nguyen@Sun.COM #define	CMI_MAX_CORES_PER_CHIP(cbits)	(1 << (cbits))
181*12261SVuong.Nguyen@Sun.COM #define	CMI_MAX_COREID(cbits)		((1 << (cbits)) - 1)
182*12261SVuong.Nguyen@Sun.COM #define	CMI_MAX_STRANDS_PER_CORE(sbits)	(1 << (sbits))
183*12261SVuong.Nguyen@Sun.COM #define	CMI_MAX_STRANDID(sbits)		((1 << (sbits)) - 1)
184*12261SVuong.Nguyen@Sun.COM #define	CMI_MAX_STRANDS_PER_CHIP(cbits, sbits)	\
185*12261SVuong.Nguyen@Sun.COM 	(CMI_MAX_CORES_PER_CHIP(cbits) * CMI_MAX_STRANDS_PER_CORE(sbits))
1866000Sgavinm 
1879090SVuong.Nguyen@Sun.COM #define	CMI_CHIPID_ARR_SZ		(1 << CMI_MAX_CHIPID_NBITS)
1885254Sgavinm 
1899090SVuong.Nguyen@Sun.COM typedef struct cmi_hdl_ent {
1906000Sgavinm 	volatile uint32_t cmae_refcnt;
1916000Sgavinm 	cmi_hdl_impl_t *cmae_hdlp;
1929090SVuong.Nguyen@Sun.COM } cmi_hdl_ent_t;
1935254Sgavinm 
1949090SVuong.Nguyen@Sun.COM static cmi_hdl_ent_t *cmi_chip_tab[CMI_CHIPID_ARR_SZ];
1955254Sgavinm 
1965254Sgavinm /*
197*12261SVuong.Nguyen@Sun.COM  * Default values for the number of core and strand bits.
198*12261SVuong.Nguyen@Sun.COM  */
199*12261SVuong.Nguyen@Sun.COM uint_t cmi_core_nbits = CMI_MAX_CORES_PER_CHIP_NBITS;
200*12261SVuong.Nguyen@Sun.COM uint_t cmi_strand_nbits = CMI_MAX_STRANDS_PER_CORE_NBITS;
201*12261SVuong.Nguyen@Sun.COM static int cmi_ext_topo_check = 0;
202*12261SVuong.Nguyen@Sun.COM 
203*12261SVuong.Nguyen@Sun.COM /*
2045254Sgavinm  * Controls where we will source PCI config space data.
2055254Sgavinm  */
2065254Sgavinm #define	CMI_PCICFG_FLAG_RD_HWOK		0x0001
2075254Sgavinm #define	CMI_PCICFG_FLAG_RD_INTERPOSEOK	0X0002
2085254Sgavinm #define	CMI_PCICFG_FLAG_WR_HWOK		0x0004
2095254Sgavinm #define	CMI_PCICFG_FLAG_WR_INTERPOSEOK	0X0008
2105254Sgavinm 
2115254Sgavinm static uint64_t cmi_pcicfg_flags =
2125254Sgavinm     CMI_PCICFG_FLAG_RD_HWOK | CMI_PCICFG_FLAG_RD_INTERPOSEOK |
2135254Sgavinm     CMI_PCICFG_FLAG_WR_HWOK | CMI_PCICFG_FLAG_WR_INTERPOSEOK;
2145254Sgavinm 
2155254Sgavinm /*
2165254Sgavinm  * The flags for individual cpus are kept in their per-cpu handle cmih_msrsrc
2175254Sgavinm  */
2185254Sgavinm #define	CMI_MSR_FLAG_RD_HWOK		0x0001
2195254Sgavinm #define	CMI_MSR_FLAG_RD_INTERPOSEOK	0x0002
2205254Sgavinm #define	CMI_MSR_FLAG_WR_HWOK		0x0004
2215254Sgavinm #define	CMI_MSR_FLAG_WR_INTERPOSEOK	0x0008
2225254Sgavinm 
2235254Sgavinm int cmi_call_func_ntv_tries = 3;
2245254Sgavinm 
2255254Sgavinm static cmi_errno_t
call_func_ntv(int cpuid,xc_func_t func,xc_arg_t arg1,xc_arg_t arg2)2265254Sgavinm call_func_ntv(int cpuid, xc_func_t func, xc_arg_t arg1, xc_arg_t arg2)
2275254Sgavinm {
2285254Sgavinm 	cmi_errno_t rc = -1;
2295254Sgavinm 	int i;
2305254Sgavinm 
2315254Sgavinm 	kpreempt_disable();
2325254Sgavinm 
2335254Sgavinm 	if (CPU->cpu_id == cpuid) {
2345254Sgavinm 		(*func)(arg1, arg2, (xc_arg_t)&rc);
2355254Sgavinm 	} else {
2365254Sgavinm 		/*
2375254Sgavinm 		 * This should not happen for a #MC trap or a poll, so
2385254Sgavinm 		 * this is likely an error injection or similar.
2395254Sgavinm 		 * We will try to cross call with xc_trycall - we
2405254Sgavinm 		 * can't guarantee success with xc_call because
2415254Sgavinm 		 * the interrupt code in the case of a #MC may
2425254Sgavinm 		 * already hold the xc mutex.
2435254Sgavinm 		 */
2445254Sgavinm 		for (i = 0; i < cmi_call_func_ntv_tries; i++) {
2455254Sgavinm 			cpuset_t cpus;
2465254Sgavinm 
2475254Sgavinm 			CPUSET_ONLY(cpus, cpuid);
2489489SJoe.Bonasera@sun.com 			xc_priority(arg1, arg2, (xc_arg_t)&rc,
2499489SJoe.Bonasera@sun.com 			    CPUSET2BV(cpus), func);
2505254Sgavinm 			if (rc != -1)
2515254Sgavinm 				break;
2525254Sgavinm 
2535254Sgavinm 			DELAY(1);
2545254Sgavinm 		}
2555254Sgavinm 	}
2565254Sgavinm 
2575254Sgavinm 	kpreempt_enable();
2585254Sgavinm 
2595254Sgavinm 	return (rc != -1 ? rc : CMIERR_DEADLOCK);
2605254Sgavinm }
2615254Sgavinm 
2627532SSean.Ye@Sun.COM static uint64_t injcnt;
2637532SSean.Ye@Sun.COM 
2647532SSean.Ye@Sun.COM void
cmi_hdl_inj_begin(cmi_hdl_t ophdl)2657532SSean.Ye@Sun.COM cmi_hdl_inj_begin(cmi_hdl_t ophdl)
2667532SSean.Ye@Sun.COM {
2677532SSean.Ye@Sun.COM 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
2687532SSean.Ye@Sun.COM 
2697532SSean.Ye@Sun.COM 	if (hdl != NULL)
2707532SSean.Ye@Sun.COM 		hdl->cmih_flags |= CMIH_F_INJACTV;
2717532SSean.Ye@Sun.COM 	if (injcnt++ == 0) {
2727532SSean.Ye@Sun.COM 		cmn_err(CE_NOTE, "Hardware error injection/simulation "
2737532SSean.Ye@Sun.COM 		    "activity noted");
2747532SSean.Ye@Sun.COM 	}
2757532SSean.Ye@Sun.COM }
2767532SSean.Ye@Sun.COM 
2777532SSean.Ye@Sun.COM void
cmi_hdl_inj_end(cmi_hdl_t ophdl)2787532SSean.Ye@Sun.COM cmi_hdl_inj_end(cmi_hdl_t ophdl)
2797532SSean.Ye@Sun.COM {
2807532SSean.Ye@Sun.COM 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
2817532SSean.Ye@Sun.COM 
2827532SSean.Ye@Sun.COM 	ASSERT(hdl == NULL || hdl->cmih_flags & CMIH_F_INJACTV);
2837532SSean.Ye@Sun.COM 	if (hdl != NULL)
2847532SSean.Ye@Sun.COM 		hdl->cmih_flags &= ~CMIH_F_INJACTV;
2857532SSean.Ye@Sun.COM }
2867532SSean.Ye@Sun.COM 
2877532SSean.Ye@Sun.COM boolean_t
cmi_inj_tainted(void)2887532SSean.Ye@Sun.COM cmi_inj_tainted(void)
2897532SSean.Ye@Sun.COM {
2907532SSean.Ye@Sun.COM 	return (injcnt != 0 ? B_TRUE : B_FALSE);
2917532SSean.Ye@Sun.COM }
2927532SSean.Ye@Sun.COM 
2935254Sgavinm /*
2945254Sgavinm  *	 =======================================================
2955254Sgavinm  *	|	MSR Interposition				|
2965254Sgavinm  *	|	-----------------				|
2975254Sgavinm  *	|							|
2985254Sgavinm  *	 -------------------------------------------------------
2995254Sgavinm  */
3005254Sgavinm 
3015254Sgavinm #define	CMI_MSRI_HASHSZ		16
3025254Sgavinm #define	CMI_MSRI_HASHIDX(hdl, msr) \
3035254Sgavinm 	(((uintptr_t)(hdl) >> 3 + (msr)) % (CMI_MSRI_HASHSZ - 1))
3045254Sgavinm 
3055254Sgavinm struct cmi_msri_bkt {
3065254Sgavinm 	kmutex_t msrib_lock;
3075254Sgavinm 	struct cmi_msri_hashent *msrib_head;
3085254Sgavinm };
3095254Sgavinm 
3105254Sgavinm struct cmi_msri_hashent {
3115254Sgavinm 	struct cmi_msri_hashent *msrie_next;
3125254Sgavinm 	struct cmi_msri_hashent *msrie_prev;
3135254Sgavinm 	cmi_hdl_impl_t *msrie_hdl;
3145254Sgavinm 	uint_t msrie_msrnum;
3155254Sgavinm 	uint64_t msrie_msrval;
3165254Sgavinm };
3175254Sgavinm 
3185254Sgavinm #define	CMI_MSRI_MATCH(ent, hdl, req_msr) \
3195254Sgavinm 	((ent)->msrie_hdl == (hdl) && (ent)->msrie_msrnum == (req_msr))
3205254Sgavinm 
3215254Sgavinm static struct cmi_msri_bkt msrihash[CMI_MSRI_HASHSZ];
3225254Sgavinm 
3235254Sgavinm static void
msri_addent(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)3247532SSean.Ye@Sun.COM msri_addent(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
3255254Sgavinm {
3267532SSean.Ye@Sun.COM 	int idx = CMI_MSRI_HASHIDX(hdl, msr);
3275254Sgavinm 	struct cmi_msri_bkt *hbp = &msrihash[idx];
3285254Sgavinm 	struct cmi_msri_hashent *hep;
3295254Sgavinm 
3305254Sgavinm 	mutex_enter(&hbp->msrib_lock);
3315254Sgavinm 
3325254Sgavinm 	for (hep = hbp->msrib_head; hep != NULL; hep = hep->msrie_next) {
3337532SSean.Ye@Sun.COM 		if (CMI_MSRI_MATCH(hep, hdl, msr))
3345254Sgavinm 			break;
3355254Sgavinm 	}
3365254Sgavinm 
3375254Sgavinm 	if (hep != NULL) {
3387532SSean.Ye@Sun.COM 		hep->msrie_msrval = val;
3395254Sgavinm 	} else {
3405254Sgavinm 		hep = kmem_alloc(sizeof (*hep), KM_SLEEP);
3415254Sgavinm 		hep->msrie_hdl = hdl;
3427532SSean.Ye@Sun.COM 		hep->msrie_msrnum = msr;
3437532SSean.Ye@Sun.COM 		hep->msrie_msrval = val;
3445254Sgavinm 
3455254Sgavinm 		if (hbp->msrib_head != NULL)
3465254Sgavinm 			hbp->msrib_head->msrie_prev = hep;
3475254Sgavinm 		hep->msrie_next = hbp->msrib_head;
3485254Sgavinm 		hep->msrie_prev = NULL;
3495254Sgavinm 		hbp->msrib_head = hep;
3505254Sgavinm 	}
3515254Sgavinm 
3525254Sgavinm 	mutex_exit(&hbp->msrib_lock);
3535254Sgavinm }
3545254Sgavinm 
3555254Sgavinm /*
3565254Sgavinm  * Look for a match for the given hanlde and msr.  Return 1 with valp
3575254Sgavinm  * filled if a match is found, otherwise return 0 with valp untouched.
3585254Sgavinm  */
3595254Sgavinm static int
msri_lookup(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t * valp)3605254Sgavinm msri_lookup(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t *valp)
3615254Sgavinm {
3625254Sgavinm 	int idx = CMI_MSRI_HASHIDX(hdl, msr);
3635254Sgavinm 	struct cmi_msri_bkt *hbp = &msrihash[idx];
3645254Sgavinm 	struct cmi_msri_hashent *hep;
3655254Sgavinm 
3665254Sgavinm 	/*
3675254Sgavinm 	 * This function is called during #MC trap handling, so we should
3685254Sgavinm 	 * consider the possibility that the hash mutex is held by the
3695254Sgavinm 	 * interrupted thread.  This should not happen because interposition
3705254Sgavinm 	 * is an artificial injection mechanism and the #MC is requested
3715254Sgavinm 	 * after adding entries, but just in case of a real #MC at an
3725254Sgavinm 	 * unlucky moment we'll use mutex_tryenter here.
3735254Sgavinm 	 */
3745254Sgavinm 	if (!mutex_tryenter(&hbp->msrib_lock))
3755254Sgavinm 		return (0);
3765254Sgavinm 
3775254Sgavinm 	for (hep = hbp->msrib_head; hep != NULL; hep = hep->msrie_next) {
3785254Sgavinm 		if (CMI_MSRI_MATCH(hep, hdl, msr)) {
3795254Sgavinm 			*valp = hep->msrie_msrval;
3805254Sgavinm 			break;
3815254Sgavinm 		}
3825254Sgavinm 	}
3835254Sgavinm 
3845254Sgavinm 	mutex_exit(&hbp->msrib_lock);
3855254Sgavinm 
3865254Sgavinm 	return (hep != NULL);
3875254Sgavinm }
3885254Sgavinm 
3895254Sgavinm /*
3905254Sgavinm  * Remove any interposed value that matches.
3915254Sgavinm  */
3925254Sgavinm static void
msri_rment(cmi_hdl_impl_t * hdl,uint_t msr)3935254Sgavinm msri_rment(cmi_hdl_impl_t *hdl, uint_t msr)
3945254Sgavinm {
3955254Sgavinm 
3965254Sgavinm 	int idx = CMI_MSRI_HASHIDX(hdl, msr);
3975254Sgavinm 	struct cmi_msri_bkt *hbp = &msrihash[idx];
3985254Sgavinm 	struct cmi_msri_hashent *hep;
3995254Sgavinm 
4005254Sgavinm 	if (!mutex_tryenter(&hbp->msrib_lock))
4015254Sgavinm 		return;
4025254Sgavinm 
4035254Sgavinm 	for (hep = hbp->msrib_head; hep != NULL; hep = hep->msrie_next) {
4045254Sgavinm 		if (CMI_MSRI_MATCH(hep, hdl, msr)) {
4055254Sgavinm 			if (hep->msrie_prev != NULL)
4065254Sgavinm 				hep->msrie_prev->msrie_next = hep->msrie_next;
4075254Sgavinm 
4085254Sgavinm 			if (hep->msrie_next != NULL)
4095254Sgavinm 				hep->msrie_next->msrie_prev = hep->msrie_prev;
4105254Sgavinm 
4115254Sgavinm 			if (hbp->msrib_head == hep)
4125254Sgavinm 				hbp->msrib_head = hep->msrie_next;
4135254Sgavinm 
4145254Sgavinm 			kmem_free(hep, sizeof (*hep));
4155254Sgavinm 			break;
4165254Sgavinm 		}
4175254Sgavinm 	}
4185254Sgavinm 
4195254Sgavinm 	mutex_exit(&hbp->msrib_lock);
4205254Sgavinm }
4215254Sgavinm 
4225254Sgavinm /*
4235254Sgavinm  *	 =======================================================
4245254Sgavinm  *	|	PCI Config Space Interposition			|
4255254Sgavinm  *	|	------------------------------			|
4265254Sgavinm  *	|							|
4275254Sgavinm  *	 -------------------------------------------------------
4285254Sgavinm  */
4295254Sgavinm 
4305254Sgavinm /*
4315254Sgavinm  * Hash for interposed PCI config space values.  We lookup on bus/dev/fun/offset
4325254Sgavinm  * and then record whether the value stashed was made with a byte, word or
4335254Sgavinm  * doubleword access;  we will only return a hit for an access of the
4345254Sgavinm  * same size.  If you access say a 32-bit register using byte accesses
4355254Sgavinm  * and then attempt to read the full 32-bit value back you will not obtain
4365254Sgavinm  * any sort of merged result - you get a lookup miss.
4375254Sgavinm  */
4385254Sgavinm 
4395254Sgavinm #define	CMI_PCII_HASHSZ		16
4405254Sgavinm #define	CMI_PCII_HASHIDX(b, d, f, o) \
4415254Sgavinm 	(((b) + (d) + (f) + (o)) % (CMI_PCII_HASHSZ - 1))
4425254Sgavinm 
4435254Sgavinm struct cmi_pcii_bkt {
4445254Sgavinm 	kmutex_t pciib_lock;
4455254Sgavinm 	struct cmi_pcii_hashent *pciib_head;
4465254Sgavinm };
4475254Sgavinm 
4485254Sgavinm struct cmi_pcii_hashent {
4495254Sgavinm 	struct cmi_pcii_hashent *pcii_next;
4505254Sgavinm 	struct cmi_pcii_hashent *pcii_prev;
4515254Sgavinm 	int pcii_bus;
4525254Sgavinm 	int pcii_dev;
4535254Sgavinm 	int pcii_func;
4545254Sgavinm 	int pcii_reg;
4555254Sgavinm 	int pcii_asize;
4565254Sgavinm 	uint32_t pcii_val;
4575254Sgavinm };
4585254Sgavinm 
4595254Sgavinm #define	CMI_PCII_MATCH(ent, b, d, f, r, asz) \
4605254Sgavinm 	((ent)->pcii_bus == (b) && (ent)->pcii_dev == (d) && \
4615254Sgavinm 	(ent)->pcii_func == (f) && (ent)->pcii_reg == (r) && \
4625254Sgavinm 	(ent)->pcii_asize == (asz))
4635254Sgavinm 
4645254Sgavinm static struct cmi_pcii_bkt pciihash[CMI_PCII_HASHSZ];
4655254Sgavinm 
4665254Sgavinm 
4675254Sgavinm /*
4685254Sgavinm  * Add a new entry to the PCI interpose hash, overwriting any existing
4695254Sgavinm  * entry that is found.
4705254Sgavinm  */
4715254Sgavinm static void
pcii_addent(int bus,int dev,int func,int reg,uint32_t val,int asz)4725254Sgavinm pcii_addent(int bus, int dev, int func, int reg, uint32_t val, int asz)
4735254Sgavinm {
4745254Sgavinm 	int idx = CMI_PCII_HASHIDX(bus, dev, func, reg);
4755254Sgavinm 	struct cmi_pcii_bkt *hbp = &pciihash[idx];
4765254Sgavinm 	struct cmi_pcii_hashent *hep;
4775254Sgavinm 
4787532SSean.Ye@Sun.COM 	cmi_hdl_inj_begin(NULL);
4797532SSean.Ye@Sun.COM 
4805254Sgavinm 	mutex_enter(&hbp->pciib_lock);
4815254Sgavinm 
4825254Sgavinm 	for (hep = hbp->pciib_head; hep != NULL; hep = hep->pcii_next) {
4835254Sgavinm 		if (CMI_PCII_MATCH(hep, bus, dev, func, reg, asz))
4845254Sgavinm 			break;
4855254Sgavinm 	}
4865254Sgavinm 
4875254Sgavinm 	if (hep != NULL) {
4885254Sgavinm 		hep->pcii_val = val;
4895254Sgavinm 	} else {
4905254Sgavinm 		hep = kmem_alloc(sizeof (*hep), KM_SLEEP);
4915254Sgavinm 		hep->pcii_bus = bus;
4925254Sgavinm 		hep->pcii_dev = dev;
4935254Sgavinm 		hep->pcii_func = func;
4945254Sgavinm 		hep->pcii_reg = reg;
4955254Sgavinm 		hep->pcii_asize = asz;
4965254Sgavinm 		hep->pcii_val = val;
4975254Sgavinm 
4985254Sgavinm 		if (hbp->pciib_head != NULL)
4995254Sgavinm 			hbp->pciib_head->pcii_prev = hep;
5005254Sgavinm 		hep->pcii_next = hbp->pciib_head;
5015254Sgavinm 		hep->pcii_prev = NULL;
5025254Sgavinm 		hbp->pciib_head = hep;
5035254Sgavinm 	}
5045254Sgavinm 
5055254Sgavinm 	mutex_exit(&hbp->pciib_lock);
5067532SSean.Ye@Sun.COM 
5077532SSean.Ye@Sun.COM 	cmi_hdl_inj_end(NULL);
5085254Sgavinm }
5095254Sgavinm 
5105254Sgavinm /*
5115254Sgavinm  * Look for a match for the given bus/dev/func/reg; return 1 with valp
5125254Sgavinm  * filled if a match is found, otherwise return 0 with valp untouched.
5135254Sgavinm  */
5145254Sgavinm static int
pcii_lookup(int bus,int dev,int func,int reg,int asz,uint32_t * valp)5155254Sgavinm pcii_lookup(int bus, int dev, int func, int reg, int asz, uint32_t *valp)
5165254Sgavinm {
5175254Sgavinm 	int idx = CMI_PCII_HASHIDX(bus, dev, func, reg);
5185254Sgavinm 	struct cmi_pcii_bkt *hbp = &pciihash[idx];
5195254Sgavinm 	struct cmi_pcii_hashent *hep;
5205254Sgavinm 
5215254Sgavinm 	if (!mutex_tryenter(&hbp->pciib_lock))
5225254Sgavinm 		return (0);
5235254Sgavinm 
5245254Sgavinm 	for (hep = hbp->pciib_head; hep != NULL; hep = hep->pcii_next) {
5255254Sgavinm 		if (CMI_PCII_MATCH(hep, bus, dev, func, reg, asz)) {
5265254Sgavinm 			*valp = hep->pcii_val;
5275254Sgavinm 			break;
5285254Sgavinm 		}
5295254Sgavinm 	}
5305254Sgavinm 
5315254Sgavinm 	mutex_exit(&hbp->pciib_lock);
5325254Sgavinm 
5335254Sgavinm 	return (hep != NULL);
5345254Sgavinm }
5355254Sgavinm 
5365254Sgavinm static void
pcii_rment(int bus,int dev,int func,int reg,int asz)5375254Sgavinm pcii_rment(int bus, int dev, int func, int reg, int asz)
5385254Sgavinm {
5395254Sgavinm 	int idx = CMI_PCII_HASHIDX(bus, dev, func, reg);
5405254Sgavinm 	struct cmi_pcii_bkt *hbp = &pciihash[idx];
5415254Sgavinm 	struct cmi_pcii_hashent *hep;
5425254Sgavinm 
5435254Sgavinm 	mutex_enter(&hbp->pciib_lock);
5445254Sgavinm 
5455254Sgavinm 	for (hep = hbp->pciib_head; hep != NULL; hep = hep->pcii_next) {
5465254Sgavinm 		if (CMI_PCII_MATCH(hep, bus, dev, func, reg, asz)) {
5475254Sgavinm 			if (hep->pcii_prev != NULL)
5485254Sgavinm 				hep->pcii_prev->pcii_next = hep->pcii_next;
5495254Sgavinm 
5505254Sgavinm 			if (hep->pcii_next != NULL)
5515254Sgavinm 				hep->pcii_next->pcii_prev = hep->pcii_prev;
5525254Sgavinm 
5535254Sgavinm 			if (hbp->pciib_head == hep)
5545254Sgavinm 				hbp->pciib_head = hep->pcii_next;
5555254Sgavinm 
5565254Sgavinm 			kmem_free(hep, sizeof (*hep));
5575254Sgavinm 			break;
5585254Sgavinm 		}
5595254Sgavinm 	}
5605254Sgavinm 
5615254Sgavinm 	mutex_exit(&hbp->pciib_lock);
5625254Sgavinm }
5635254Sgavinm 
5647532SSean.Ye@Sun.COM #ifndef __xpv
5657532SSean.Ye@Sun.COM 
5665254Sgavinm /*
5675254Sgavinm  *	 =======================================================
5685254Sgavinm  *	|	Native methods					|
5695254Sgavinm  *	|	--------------					|
5705254Sgavinm  *	|							|
5715254Sgavinm  *	| These are used when we are running native on bare-	|
5725254Sgavinm  *	| metal, or simply don't know any better.		|
5735254Sgavinm  *	---------------------------------------------------------
5745254Sgavinm  */
5755254Sgavinm 
5767532SSean.Ye@Sun.COM #define	HDLPRIV(hdl)	((cpu_t *)(hdl)->cmih_hdlpriv)
5777532SSean.Ye@Sun.COM 
5785254Sgavinm static uint_t
ntv_vendor(cmi_hdl_impl_t * hdl)5795254Sgavinm ntv_vendor(cmi_hdl_impl_t *hdl)
5805254Sgavinm {
5817532SSean.Ye@Sun.COM 	return (cpuid_getvendor(HDLPRIV(hdl)));
5825254Sgavinm }
5835254Sgavinm 
5845254Sgavinm static const char *
ntv_vendorstr(cmi_hdl_impl_t * hdl)5855254Sgavinm ntv_vendorstr(cmi_hdl_impl_t *hdl)
5865254Sgavinm {
5877532SSean.Ye@Sun.COM 	return (cpuid_getvendorstr(HDLPRIV(hdl)));
5885254Sgavinm }
5895254Sgavinm 
5905254Sgavinm static uint_t
ntv_family(cmi_hdl_impl_t * hdl)5915254Sgavinm ntv_family(cmi_hdl_impl_t *hdl)
5925254Sgavinm {
5937532SSean.Ye@Sun.COM 	return (cpuid_getfamily(HDLPRIV(hdl)));
5945254Sgavinm }
5955254Sgavinm 
5965254Sgavinm static uint_t
ntv_model(cmi_hdl_impl_t * hdl)5975254Sgavinm ntv_model(cmi_hdl_impl_t *hdl)
5985254Sgavinm {
5997532SSean.Ye@Sun.COM 	return (cpuid_getmodel(HDLPRIV(hdl)));
6005254Sgavinm }
6015254Sgavinm 
6025254Sgavinm static uint_t
ntv_stepping(cmi_hdl_impl_t * hdl)6035254Sgavinm ntv_stepping(cmi_hdl_impl_t *hdl)
6045254Sgavinm {
6057532SSean.Ye@Sun.COM 	return (cpuid_getstep(HDLPRIV(hdl)));
6065254Sgavinm }
6075254Sgavinm 
6085254Sgavinm static uint_t
ntv_chipid(cmi_hdl_impl_t * hdl)6095254Sgavinm ntv_chipid(cmi_hdl_impl_t *hdl)
6105254Sgavinm {
6115254Sgavinm 	return (hdl->cmih_chipid);
6125254Sgavinm 
6135254Sgavinm }
6145254Sgavinm 
6155254Sgavinm static uint_t
ntv_procnodeid(cmi_hdl_impl_t * hdl)61610947SSrihari.Venkatesan@Sun.COM ntv_procnodeid(cmi_hdl_impl_t *hdl)
61710947SSrihari.Venkatesan@Sun.COM {
61810947SSrihari.Venkatesan@Sun.COM 	return (hdl->cmih_procnodeid);
61910947SSrihari.Venkatesan@Sun.COM }
62010947SSrihari.Venkatesan@Sun.COM 
62110947SSrihari.Venkatesan@Sun.COM static uint_t
ntv_procnodes_per_pkg(cmi_hdl_impl_t * hdl)62210947SSrihari.Venkatesan@Sun.COM ntv_procnodes_per_pkg(cmi_hdl_impl_t *hdl)
62310947SSrihari.Venkatesan@Sun.COM {
62410947SSrihari.Venkatesan@Sun.COM 	return (hdl->cmih_procnodes_per_pkg);
62510947SSrihari.Venkatesan@Sun.COM }
62610947SSrihari.Venkatesan@Sun.COM 
62710947SSrihari.Venkatesan@Sun.COM static uint_t
ntv_coreid(cmi_hdl_impl_t * hdl)6285254Sgavinm ntv_coreid(cmi_hdl_impl_t *hdl)
6295254Sgavinm {
6305254Sgavinm 	return (hdl->cmih_coreid);
6315254Sgavinm }
6325254Sgavinm 
6335254Sgavinm static uint_t
ntv_strandid(cmi_hdl_impl_t * hdl)6345254Sgavinm ntv_strandid(cmi_hdl_impl_t *hdl)
6355254Sgavinm {
6365254Sgavinm 	return (hdl->cmih_strandid);
6375254Sgavinm }
6385254Sgavinm 
63910942STom.Pothier@Sun.COM static uint_t
ntv_strand_apicid(cmi_hdl_impl_t * hdl)64010942STom.Pothier@Sun.COM ntv_strand_apicid(cmi_hdl_impl_t *hdl)
64110942STom.Pothier@Sun.COM {
64210942STom.Pothier@Sun.COM 	return (cpuid_get_apicid(HDLPRIV(hdl)));
64310942STom.Pothier@Sun.COM }
64410942STom.Pothier@Sun.COM 
64510942STom.Pothier@Sun.COM static uint16_t
ntv_smbiosid(cmi_hdl_impl_t * hdl)64610942STom.Pothier@Sun.COM ntv_smbiosid(cmi_hdl_impl_t *hdl)
64710942STom.Pothier@Sun.COM {
64810942STom.Pothier@Sun.COM 	return (hdl->cmih_smbiosid);
64910942STom.Pothier@Sun.COM }
65010942STom.Pothier@Sun.COM 
65110942STom.Pothier@Sun.COM static uint_t
ntv_smb_chipid(cmi_hdl_impl_t * hdl)65210942STom.Pothier@Sun.COM ntv_smb_chipid(cmi_hdl_impl_t *hdl)
65310942STom.Pothier@Sun.COM {
65410942STom.Pothier@Sun.COM 	return (hdl->cmih_smb_chipid);
65510942STom.Pothier@Sun.COM }
65610942STom.Pothier@Sun.COM 
65710942STom.Pothier@Sun.COM static nvlist_t *
ntv_smb_bboard(cmi_hdl_impl_t * hdl)65810942STom.Pothier@Sun.COM ntv_smb_bboard(cmi_hdl_impl_t *hdl)
65910942STom.Pothier@Sun.COM {
66010942STom.Pothier@Sun.COM 	return (hdl->cmih_smb_bboard);
66110942STom.Pothier@Sun.COM }
66210942STom.Pothier@Sun.COM 
6635254Sgavinm static uint32_t
ntv_chiprev(cmi_hdl_impl_t * hdl)6645254Sgavinm ntv_chiprev(cmi_hdl_impl_t *hdl)
6655254Sgavinm {
6667532SSean.Ye@Sun.COM 	return (cpuid_getchiprev(HDLPRIV(hdl)));
6675254Sgavinm }
6685254Sgavinm 
6695254Sgavinm static const char *
ntv_chiprevstr(cmi_hdl_impl_t * hdl)6705254Sgavinm ntv_chiprevstr(cmi_hdl_impl_t *hdl)
6715254Sgavinm {
6727532SSean.Ye@Sun.COM 	return (cpuid_getchiprevstr(HDLPRIV(hdl)));
6735254Sgavinm }
6745254Sgavinm 
6755254Sgavinm static uint32_t
ntv_getsockettype(cmi_hdl_impl_t * hdl)6765254Sgavinm ntv_getsockettype(cmi_hdl_impl_t *hdl)
6775254Sgavinm {
6787532SSean.Ye@Sun.COM 	return (cpuid_getsockettype(HDLPRIV(hdl)));
6797532SSean.Ye@Sun.COM }
6807532SSean.Ye@Sun.COM 
6819482SKuriakose.Kuruvilla@Sun.COM static const char *
ntv_getsocketstr(cmi_hdl_impl_t * hdl)6829482SKuriakose.Kuruvilla@Sun.COM ntv_getsocketstr(cmi_hdl_impl_t *hdl)
6839482SKuriakose.Kuruvilla@Sun.COM {
6849482SKuriakose.Kuruvilla@Sun.COM 	return (cpuid_getsocketstr(HDLPRIV(hdl)));
6859482SKuriakose.Kuruvilla@Sun.COM }
6869482SKuriakose.Kuruvilla@Sun.COM 
6877532SSean.Ye@Sun.COM static id_t
ntv_logical_id(cmi_hdl_impl_t * hdl)6887532SSean.Ye@Sun.COM ntv_logical_id(cmi_hdl_impl_t *hdl)
6897532SSean.Ye@Sun.COM {
6907532SSean.Ye@Sun.COM 	return (HDLPRIV(hdl)->cpu_id);
6915254Sgavinm }
6925254Sgavinm 
6935254Sgavinm /*ARGSUSED*/
6945254Sgavinm static int
ntv_getcr4_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)6955254Sgavinm ntv_getcr4_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
6965254Sgavinm {
6975254Sgavinm 	ulong_t *dest = (ulong_t *)arg1;
6985254Sgavinm 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
6995254Sgavinm 
7005254Sgavinm 	*dest = getcr4();
7015254Sgavinm 	*rcp = CMI_SUCCESS;
7025254Sgavinm 
7035254Sgavinm 	return (0);
7045254Sgavinm }
7055254Sgavinm 
7065254Sgavinm static ulong_t
ntv_getcr4(cmi_hdl_impl_t * hdl)7075254Sgavinm ntv_getcr4(cmi_hdl_impl_t *hdl)
7085254Sgavinm {
7097532SSean.Ye@Sun.COM 	cpu_t *cp = HDLPRIV(hdl);
7105254Sgavinm 	ulong_t val;
7115254Sgavinm 
7125254Sgavinm 	(void) call_func_ntv(cp->cpu_id, ntv_getcr4_xc, (xc_arg_t)&val, NULL);
7135254Sgavinm 
7145254Sgavinm 	return (val);
7155254Sgavinm }
7165254Sgavinm 
7175254Sgavinm /*ARGSUSED*/
7185254Sgavinm static int
ntv_setcr4_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)7195254Sgavinm ntv_setcr4_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
7205254Sgavinm {
7215254Sgavinm 	ulong_t val = (ulong_t)arg1;
7225254Sgavinm 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
7235254Sgavinm 
7245254Sgavinm 	setcr4(val);
7255254Sgavinm 	*rcp = CMI_SUCCESS;
7265254Sgavinm 
7275254Sgavinm 	return (0);
7285254Sgavinm }
7295254Sgavinm 
7305254Sgavinm static void
ntv_setcr4(cmi_hdl_impl_t * hdl,ulong_t val)7315254Sgavinm ntv_setcr4(cmi_hdl_impl_t *hdl, ulong_t val)
7325254Sgavinm {
7337532SSean.Ye@Sun.COM 	cpu_t *cp = HDLPRIV(hdl);
7345254Sgavinm 
7355254Sgavinm 	(void) call_func_ntv(cp->cpu_id, ntv_setcr4_xc, (xc_arg_t)val, NULL);
7365254Sgavinm }
7375254Sgavinm 
7385639Sgavinm volatile uint32_t cmi_trapped_rdmsr;
7395639Sgavinm 
7405254Sgavinm /*ARGSUSED*/
7415254Sgavinm static int
ntv_rdmsr_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)7425254Sgavinm ntv_rdmsr_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
7435254Sgavinm {
7445254Sgavinm 	uint_t msr = (uint_t)arg1;
7455254Sgavinm 	uint64_t *valp = (uint64_t *)arg2;
7465254Sgavinm 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
7475254Sgavinm 
7485254Sgavinm 	on_trap_data_t otd;
7495254Sgavinm 
7505254Sgavinm 	if (on_trap(&otd, OT_DATA_ACCESS) == 0) {
7515254Sgavinm 		if (checked_rdmsr(msr, valp) == 0)
7525254Sgavinm 			*rcp = CMI_SUCCESS;
7535254Sgavinm 		else
7545254Sgavinm 			*rcp = CMIERR_NOTSUP;
7555254Sgavinm 	} else {
7565254Sgavinm 		*rcp = CMIERR_MSRGPF;
7575639Sgavinm 		atomic_inc_32(&cmi_trapped_rdmsr);
7585254Sgavinm 	}
7595254Sgavinm 	no_trap();
7605254Sgavinm 
7615254Sgavinm 	return (0);
7625254Sgavinm }
7635254Sgavinm 
7645254Sgavinm static cmi_errno_t
ntv_rdmsr(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t * valp)7655254Sgavinm ntv_rdmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t *valp)
7665254Sgavinm {
7677532SSean.Ye@Sun.COM 	cpu_t *cp = HDLPRIV(hdl);
7687532SSean.Ye@Sun.COM 
7697532SSean.Ye@Sun.COM 	if (!(hdl->cmih_msrsrc & CMI_MSR_FLAG_RD_HWOK))
7707532SSean.Ye@Sun.COM 		return (CMIERR_INTERPOSE);
7715254Sgavinm 
7725254Sgavinm 	return (call_func_ntv(cp->cpu_id, ntv_rdmsr_xc,
7735254Sgavinm 	    (xc_arg_t)msr, (xc_arg_t)valp));
7745254Sgavinm }
7755254Sgavinm 
7765639Sgavinm volatile uint32_t cmi_trapped_wrmsr;
7775639Sgavinm 
7785254Sgavinm /*ARGSUSED*/
7795254Sgavinm static int
ntv_wrmsr_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)7805254Sgavinm ntv_wrmsr_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
7815254Sgavinm {
7825254Sgavinm 	uint_t msr = (uint_t)arg1;
7835254Sgavinm 	uint64_t val = *((uint64_t *)arg2);
7845254Sgavinm 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
7855254Sgavinm 	on_trap_data_t otd;
7865254Sgavinm 
7875254Sgavinm 	if (on_trap(&otd, OT_DATA_ACCESS) == 0) {
7885254Sgavinm 		if (checked_wrmsr(msr, val) == 0)
7895254Sgavinm 			*rcp = CMI_SUCCESS;
7905254Sgavinm 		else
7915254Sgavinm 			*rcp = CMIERR_NOTSUP;
7925254Sgavinm 	} else {
7935254Sgavinm 		*rcp = CMIERR_MSRGPF;
7945639Sgavinm 		atomic_inc_32(&cmi_trapped_wrmsr);
7955254Sgavinm 	}
7965254Sgavinm 	no_trap();
7975254Sgavinm 
7985254Sgavinm 	return (0);
7995254Sgavinm 
8005254Sgavinm }
8015254Sgavinm 
8025254Sgavinm static cmi_errno_t
ntv_wrmsr(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)8035254Sgavinm ntv_wrmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
8045254Sgavinm {
8057532SSean.Ye@Sun.COM 	cpu_t *cp = HDLPRIV(hdl);
8067532SSean.Ye@Sun.COM 
8077532SSean.Ye@Sun.COM 	if (!(hdl->cmih_msrsrc & CMI_MSR_FLAG_WR_HWOK))
8087532SSean.Ye@Sun.COM 		return (CMI_SUCCESS);
8095254Sgavinm 
8105254Sgavinm 	return (call_func_ntv(cp->cpu_id, ntv_wrmsr_xc,
8115254Sgavinm 	    (xc_arg_t)msr, (xc_arg_t)&val));
8125254Sgavinm }
8135254Sgavinm 
8147532SSean.Ye@Sun.COM static cmi_errno_t
ntv_msrinterpose(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)8157532SSean.Ye@Sun.COM ntv_msrinterpose(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
8167532SSean.Ye@Sun.COM {
8177532SSean.Ye@Sun.COM 	msri_addent(hdl, msr, val);
8187532SSean.Ye@Sun.COM 	return (CMI_SUCCESS);
8197532SSean.Ye@Sun.COM }
8207532SSean.Ye@Sun.COM 
8215254Sgavinm /*ARGSUSED*/
8225254Sgavinm static int
ntv_int_xc(xc_arg_t arg1,xc_arg_t arg2,xc_arg_t arg3)8237349SAdrian.Frost@Sun.COM ntv_int_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
8245254Sgavinm {
8255254Sgavinm 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
8267349SAdrian.Frost@Sun.COM 	int int_no = (int)arg1;
8275254Sgavinm 
8287349SAdrian.Frost@Sun.COM 	if (int_no == T_MCE)
8297349SAdrian.Frost@Sun.COM 		int18();
8307349SAdrian.Frost@Sun.COM 	else
8317349SAdrian.Frost@Sun.COM 		int_cmci();
8325254Sgavinm 	*rcp = CMI_SUCCESS;
8335254Sgavinm 
8345254Sgavinm 	return (0);
8355254Sgavinm }
8365254Sgavinm 
8375254Sgavinm static void
ntv_int(cmi_hdl_impl_t * hdl,int int_no)8387349SAdrian.Frost@Sun.COM ntv_int(cmi_hdl_impl_t *hdl, int int_no)
8395254Sgavinm {
8407532SSean.Ye@Sun.COM 	cpu_t *cp = HDLPRIV(hdl);
8415254Sgavinm 
8427349SAdrian.Frost@Sun.COM 	(void) call_func_ntv(cp->cpu_id, ntv_int_xc, (xc_arg_t)int_no, NULL);
8435254Sgavinm }
8445254Sgavinm 
8457532SSean.Ye@Sun.COM static int
ntv_online(cmi_hdl_impl_t * hdl,int new_status,int * old_status)8467532SSean.Ye@Sun.COM ntv_online(cmi_hdl_impl_t *hdl, int new_status, int *old_status)
8477532SSean.Ye@Sun.COM {
84812004Sjiang.liu@intel.com 	int rc;
8497532SSean.Ye@Sun.COM 	processorid_t cpuid = HDLPRIV(hdl)->cpu_id;
8507532SSean.Ye@Sun.COM 
85112004Sjiang.liu@intel.com 	while (mutex_tryenter(&cpu_lock) == 0) {
85212004Sjiang.liu@intel.com 		if (hdl->cmih_flags & CMIH_F_DEAD)
85312004Sjiang.liu@intel.com 			return (EBUSY);
85412004Sjiang.liu@intel.com 		delay(1);
85512004Sjiang.liu@intel.com 	}
85612004Sjiang.liu@intel.com 	rc = p_online_internal_locked(cpuid, new_status, old_status);
85712004Sjiang.liu@intel.com 	mutex_exit(&cpu_lock);
85812004Sjiang.liu@intel.com 
85912004Sjiang.liu@intel.com 	return (rc);
8607532SSean.Ye@Sun.COM }
8617532SSean.Ye@Sun.COM 
8627532SSean.Ye@Sun.COM #else	/* __xpv */
8637532SSean.Ye@Sun.COM 
8645254Sgavinm /*
8657532SSean.Ye@Sun.COM  *	 =======================================================
8667532SSean.Ye@Sun.COM  *	|	xVM dom0 methods				|
8677532SSean.Ye@Sun.COM  *	|	----------------				|
8687532SSean.Ye@Sun.COM  *	|							|
8697532SSean.Ye@Sun.COM  *	| These are used when we are running as dom0 in		|
8707532SSean.Ye@Sun.COM  *	| a Solaris xVM context.				|
8717532SSean.Ye@Sun.COM  *	---------------------------------------------------------
8725254Sgavinm  */
8737532SSean.Ye@Sun.COM 
8747532SSean.Ye@Sun.COM #define	HDLPRIV(hdl)	((xen_mc_lcpu_cookie_t)(hdl)->cmih_hdlpriv)
8757532SSean.Ye@Sun.COM 
8767532SSean.Ye@Sun.COM extern uint_t _cpuid_vendorstr_to_vendorcode(char *);
8777532SSean.Ye@Sun.COM 
8787532SSean.Ye@Sun.COM 
8797532SSean.Ye@Sun.COM static uint_t
xpv_vendor(cmi_hdl_impl_t * hdl)8807532SSean.Ye@Sun.COM xpv_vendor(cmi_hdl_impl_t *hdl)
8817532SSean.Ye@Sun.COM {
8827532SSean.Ye@Sun.COM 	return (_cpuid_vendorstr_to_vendorcode((char *)xen_physcpu_vendorstr(
8837532SSean.Ye@Sun.COM 	    HDLPRIV(hdl))));
8847532SSean.Ye@Sun.COM }
8857532SSean.Ye@Sun.COM 
8867532SSean.Ye@Sun.COM static const char *
xpv_vendorstr(cmi_hdl_impl_t * hdl)8877532SSean.Ye@Sun.COM xpv_vendorstr(cmi_hdl_impl_t *hdl)
8887532SSean.Ye@Sun.COM {
8897532SSean.Ye@Sun.COM 	return (xen_physcpu_vendorstr(HDLPRIV(hdl)));
8907532SSean.Ye@Sun.COM }
8917532SSean.Ye@Sun.COM 
8927532SSean.Ye@Sun.COM static uint_t
xpv_family(cmi_hdl_impl_t * hdl)8937532SSean.Ye@Sun.COM xpv_family(cmi_hdl_impl_t *hdl)
8947532SSean.Ye@Sun.COM {
8957532SSean.Ye@Sun.COM 	return (xen_physcpu_family(HDLPRIV(hdl)));
8967532SSean.Ye@Sun.COM }
8977532SSean.Ye@Sun.COM 
8987532SSean.Ye@Sun.COM static uint_t
xpv_model(cmi_hdl_impl_t * hdl)8997532SSean.Ye@Sun.COM xpv_model(cmi_hdl_impl_t *hdl)
9007532SSean.Ye@Sun.COM {
9017532SSean.Ye@Sun.COM 	return (xen_physcpu_model(HDLPRIV(hdl)));
9027532SSean.Ye@Sun.COM }
9037532SSean.Ye@Sun.COM 
9047532SSean.Ye@Sun.COM static uint_t
xpv_stepping(cmi_hdl_impl_t * hdl)9057532SSean.Ye@Sun.COM xpv_stepping(cmi_hdl_impl_t *hdl)
9067532SSean.Ye@Sun.COM {
9077532SSean.Ye@Sun.COM 	return (xen_physcpu_stepping(HDLPRIV(hdl)));
9087532SSean.Ye@Sun.COM }
9097532SSean.Ye@Sun.COM 
9107532SSean.Ye@Sun.COM static uint_t
xpv_chipid(cmi_hdl_impl_t * hdl)9117532SSean.Ye@Sun.COM xpv_chipid(cmi_hdl_impl_t *hdl)
9127532SSean.Ye@Sun.COM {
9137532SSean.Ye@Sun.COM 	return (hdl->cmih_chipid);
9147532SSean.Ye@Sun.COM }
9157532SSean.Ye@Sun.COM 
9167532SSean.Ye@Sun.COM static uint_t
xpv_procnodeid(cmi_hdl_impl_t * hdl)91710947SSrihari.Venkatesan@Sun.COM xpv_procnodeid(cmi_hdl_impl_t *hdl)
91810947SSrihari.Venkatesan@Sun.COM {
91910947SSrihari.Venkatesan@Sun.COM 	return (hdl->cmih_procnodeid);
92010947SSrihari.Venkatesan@Sun.COM }
92110947SSrihari.Venkatesan@Sun.COM 
92210947SSrihari.Venkatesan@Sun.COM static uint_t
xpv_procnodes_per_pkg(cmi_hdl_impl_t * hdl)92310947SSrihari.Venkatesan@Sun.COM xpv_procnodes_per_pkg(cmi_hdl_impl_t *hdl)
92410947SSrihari.Venkatesan@Sun.COM {
92510947SSrihari.Venkatesan@Sun.COM 	return (hdl->cmih_procnodes_per_pkg);
92610947SSrihari.Venkatesan@Sun.COM }
92710947SSrihari.Venkatesan@Sun.COM 
92810947SSrihari.Venkatesan@Sun.COM static uint_t
xpv_coreid(cmi_hdl_impl_t * hdl)9297532SSean.Ye@Sun.COM xpv_coreid(cmi_hdl_impl_t *hdl)
9307532SSean.Ye@Sun.COM {
9317532SSean.Ye@Sun.COM 	return (hdl->cmih_coreid);
9327532SSean.Ye@Sun.COM }
9337532SSean.Ye@Sun.COM 
9347532SSean.Ye@Sun.COM static uint_t
xpv_strandid(cmi_hdl_impl_t * hdl)9357532SSean.Ye@Sun.COM xpv_strandid(cmi_hdl_impl_t *hdl)
9367532SSean.Ye@Sun.COM {
9377532SSean.Ye@Sun.COM 	return (hdl->cmih_strandid);
9387532SSean.Ye@Sun.COM }
9397532SSean.Ye@Sun.COM 
94010942STom.Pothier@Sun.COM static uint_t
xpv_strand_apicid(cmi_hdl_impl_t * hdl)94110942STom.Pothier@Sun.COM xpv_strand_apicid(cmi_hdl_impl_t *hdl)
94210942STom.Pothier@Sun.COM {
94310942STom.Pothier@Sun.COM 	return (xen_physcpu_initial_apicid(HDLPRIV(hdl)));
94410942STom.Pothier@Sun.COM }
94510942STom.Pothier@Sun.COM 
94610942STom.Pothier@Sun.COM static uint16_t
xpv_smbiosid(cmi_hdl_impl_t * hdl)94710942STom.Pothier@Sun.COM xpv_smbiosid(cmi_hdl_impl_t *hdl)
94810942STom.Pothier@Sun.COM {
94910942STom.Pothier@Sun.COM 	return (hdl->cmih_smbiosid);
95010942STom.Pothier@Sun.COM }
95110942STom.Pothier@Sun.COM 
95210942STom.Pothier@Sun.COM static uint_t
xpv_smb_chipid(cmi_hdl_impl_t * hdl)95310942STom.Pothier@Sun.COM xpv_smb_chipid(cmi_hdl_impl_t *hdl)
95410942STom.Pothier@Sun.COM {
95510942STom.Pothier@Sun.COM 	return (hdl->cmih_smb_chipid);
95610942STom.Pothier@Sun.COM }
95710942STom.Pothier@Sun.COM 
95810942STom.Pothier@Sun.COM static nvlist_t *
xpv_smb_bboard(cmi_hdl_impl_t * hdl)95910942STom.Pothier@Sun.COM xpv_smb_bboard(cmi_hdl_impl_t *hdl)
96010942STom.Pothier@Sun.COM {
96110942STom.Pothier@Sun.COM 	return (hdl->cmih_smb_bboard);
96210942STom.Pothier@Sun.COM }
96310942STom.Pothier@Sun.COM 
9647532SSean.Ye@Sun.COM extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t);
9657532SSean.Ye@Sun.COM 
9667532SSean.Ye@Sun.COM static uint32_t
xpv_chiprev(cmi_hdl_impl_t * hdl)9677532SSean.Ye@Sun.COM xpv_chiprev(cmi_hdl_impl_t *hdl)
9687532SSean.Ye@Sun.COM {
9697532SSean.Ye@Sun.COM 	return (_cpuid_chiprev(xpv_vendor(hdl), xpv_family(hdl),
9707532SSean.Ye@Sun.COM 	    xpv_model(hdl), xpv_stepping(hdl)));
9717532SSean.Ye@Sun.COM }
9727532SSean.Ye@Sun.COM 
9737532SSean.Ye@Sun.COM extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t);
9747532SSean.Ye@Sun.COM 
9757532SSean.Ye@Sun.COM static const char *
xpv_chiprevstr(cmi_hdl_impl_t * hdl)9767532SSean.Ye@Sun.COM xpv_chiprevstr(cmi_hdl_impl_t *hdl)
9777532SSean.Ye@Sun.COM {
9787532SSean.Ye@Sun.COM 	return (_cpuid_chiprevstr(xpv_vendor(hdl), xpv_family(hdl),
9797532SSean.Ye@Sun.COM 	    xpv_model(hdl), xpv_stepping(hdl)));
9807532SSean.Ye@Sun.COM }
9817532SSean.Ye@Sun.COM 
9827532SSean.Ye@Sun.COM extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t);
9837532SSean.Ye@Sun.COM 
9847532SSean.Ye@Sun.COM static uint32_t
xpv_getsockettype(cmi_hdl_impl_t * hdl)9857532SSean.Ye@Sun.COM xpv_getsockettype(cmi_hdl_impl_t *hdl)
9867532SSean.Ye@Sun.COM {
9877532SSean.Ye@Sun.COM 	return (_cpuid_skt(xpv_vendor(hdl), xpv_family(hdl),
9887532SSean.Ye@Sun.COM 	    xpv_model(hdl), xpv_stepping(hdl)));
9897532SSean.Ye@Sun.COM }
9907532SSean.Ye@Sun.COM 
9919482SKuriakose.Kuruvilla@Sun.COM extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t);
9929482SKuriakose.Kuruvilla@Sun.COM 
9939482SKuriakose.Kuruvilla@Sun.COM static const char *
xpv_getsocketstr(cmi_hdl_impl_t * hdl)9949482SKuriakose.Kuruvilla@Sun.COM xpv_getsocketstr(cmi_hdl_impl_t *hdl)
9959482SKuriakose.Kuruvilla@Sun.COM {
9969482SKuriakose.Kuruvilla@Sun.COM 	return (_cpuid_sktstr(xpv_vendor(hdl), xpv_family(hdl),
9979482SKuriakose.Kuruvilla@Sun.COM 	    xpv_model(hdl), xpv_stepping(hdl)));
9989482SKuriakose.Kuruvilla@Sun.COM }
9999482SKuriakose.Kuruvilla@Sun.COM 
10007532SSean.Ye@Sun.COM static id_t
xpv_logical_id(cmi_hdl_impl_t * hdl)10017532SSean.Ye@Sun.COM xpv_logical_id(cmi_hdl_impl_t *hdl)
10027532SSean.Ye@Sun.COM {
10037532SSean.Ye@Sun.COM 	return (xen_physcpu_logical_id(HDLPRIV(hdl)));
10047532SSean.Ye@Sun.COM }
10057532SSean.Ye@Sun.COM 
10067532SSean.Ye@Sun.COM static cmi_errno_t
xpv_rdmsr(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t * valp)10077532SSean.Ye@Sun.COM xpv_rdmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t *valp)
10087532SSean.Ye@Sun.COM {
10097532SSean.Ye@Sun.COM 	switch (msr) {
10107532SSean.Ye@Sun.COM 	case IA32_MSR_MCG_CAP:
10117532SSean.Ye@Sun.COM 		*valp = xen_physcpu_mcg_cap(HDLPRIV(hdl));
10127532SSean.Ye@Sun.COM 		break;
10137532SSean.Ye@Sun.COM 
10147532SSean.Ye@Sun.COM 	default:
10157532SSean.Ye@Sun.COM 		return (CMIERR_NOTSUP);
10167532SSean.Ye@Sun.COM 	}
10177532SSean.Ye@Sun.COM 
10187532SSean.Ye@Sun.COM 	return (CMI_SUCCESS);
10197532SSean.Ye@Sun.COM }
10207532SSean.Ye@Sun.COM 
10217532SSean.Ye@Sun.COM /*
10227532SSean.Ye@Sun.COM  * Request the hypervisor to write an MSR for us.  The hypervisor
10237532SSean.Ye@Sun.COM  * will only accept MCA-related MSRs, as this is for MCA error
10247532SSean.Ye@Sun.COM  * simulation purposes alone.  We will pre-screen MSRs for injection
10257532SSean.Ye@Sun.COM  * so we don't bother the HV with bogus requests.  We will permit
10267532SSean.Ye@Sun.COM  * injection to any MCA bank register, and to MCG_STATUS.
10277532SSean.Ye@Sun.COM  */
10287532SSean.Ye@Sun.COM 
10297532SSean.Ye@Sun.COM #define	IS_MCA_INJ_MSR(msr) \
10307532SSean.Ye@Sun.COM 	(((msr) >= IA32_MSR_MC(0, CTL) && (msr) <= IA32_MSR_MC(10, MISC)) || \
10317532SSean.Ye@Sun.COM 	(msr) == IA32_MSR_MCG_STATUS)
10325254Sgavinm 
10337532SSean.Ye@Sun.COM static cmi_errno_t
xpv_wrmsr_cmn(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val,boolean_t intpose)10347532SSean.Ye@Sun.COM xpv_wrmsr_cmn(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val, boolean_t intpose)
10357532SSean.Ye@Sun.COM {
103611120SMark.Johnson@Sun.COM 	xen_mc_t xmc;
103711120SMark.Johnson@Sun.COM 	struct xen_mc_msrinject *mci = &xmc.u.mc_msrinject;
10387532SSean.Ye@Sun.COM 
10397532SSean.Ye@Sun.COM 	if (!(hdl->cmih_flags & CMIH_F_INJACTV))
10407532SSean.Ye@Sun.COM 		return (CMIERR_NOTSUP);		/* for injection use only! */
10417532SSean.Ye@Sun.COM 
10427532SSean.Ye@Sun.COM 	if (!IS_MCA_INJ_MSR(msr))
10437532SSean.Ye@Sun.COM 		return (CMIERR_API);
10447532SSean.Ye@Sun.COM 
10457532SSean.Ye@Sun.COM 	if (panicstr)
10467532SSean.Ye@Sun.COM 		return (CMIERR_DEADLOCK);
10477532SSean.Ye@Sun.COM 
104811120SMark.Johnson@Sun.COM 	mci->mcinj_cpunr = xen_physcpu_logical_id(HDLPRIV(hdl));
104911120SMark.Johnson@Sun.COM 	mci->mcinj_flags = intpose ? MC_MSRINJ_F_INTERPOSE : 0;
105011120SMark.Johnson@Sun.COM 	mci->mcinj_count = 1;	/* learn to batch sometime */
105111120SMark.Johnson@Sun.COM 	mci->mcinj_msr[0].reg = msr;
105211120SMark.Johnson@Sun.COM 	mci->mcinj_msr[0].value = val;
10537532SSean.Ye@Sun.COM 
105411120SMark.Johnson@Sun.COM 	return (HYPERVISOR_mca(XEN_MC_msrinject, &xmc) ==
105510175SStuart.Maybee@Sun.COM 	    0 ?  CMI_SUCCESS : CMIERR_NOTSUP);
10567532SSean.Ye@Sun.COM }
10577532SSean.Ye@Sun.COM 
10587532SSean.Ye@Sun.COM static cmi_errno_t
xpv_wrmsr(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)10597532SSean.Ye@Sun.COM xpv_wrmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
10607532SSean.Ye@Sun.COM {
10617532SSean.Ye@Sun.COM 	return (xpv_wrmsr_cmn(hdl, msr, val, B_FALSE));
10627532SSean.Ye@Sun.COM }
10637532SSean.Ye@Sun.COM 
10647532SSean.Ye@Sun.COM 
10657532SSean.Ye@Sun.COM static cmi_errno_t
xpv_msrinterpose(cmi_hdl_impl_t * hdl,uint_t msr,uint64_t val)10667532SSean.Ye@Sun.COM xpv_msrinterpose(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
10677532SSean.Ye@Sun.COM {
10687532SSean.Ye@Sun.COM 	return (xpv_wrmsr_cmn(hdl, msr, val, B_TRUE));
10697532SSean.Ye@Sun.COM }
10707532SSean.Ye@Sun.COM 
10717532SSean.Ye@Sun.COM static void
xpv_int(cmi_hdl_impl_t * hdl,int int_no)10727532SSean.Ye@Sun.COM xpv_int(cmi_hdl_impl_t *hdl, int int_no)
10737532SSean.Ye@Sun.COM {
107411120SMark.Johnson@Sun.COM 	xen_mc_t xmc;
107511120SMark.Johnson@Sun.COM 	struct xen_mc_mceinject *mce = &xmc.u.mc_mceinject;
10767532SSean.Ye@Sun.COM 
10777532SSean.Ye@Sun.COM 	if (!(hdl->cmih_flags & CMIH_F_INJACTV))
10787532SSean.Ye@Sun.COM 		return;
10797532SSean.Ye@Sun.COM 
10807532SSean.Ye@Sun.COM 	if (int_no != T_MCE) {
10817532SSean.Ye@Sun.COM 		cmn_err(CE_WARN, "xpv_int: int_no %d unimplemented\n",
10827532SSean.Ye@Sun.COM 		    int_no);
10837532SSean.Ye@Sun.COM 	}
10847532SSean.Ye@Sun.COM 
108511120SMark.Johnson@Sun.COM 	mce->mceinj_cpunr = xen_physcpu_logical_id(HDLPRIV(hdl));
10867532SSean.Ye@Sun.COM 
108711120SMark.Johnson@Sun.COM 	(void) HYPERVISOR_mca(XEN_MC_mceinject, &xmc);
10887532SSean.Ye@Sun.COM }
10897532SSean.Ye@Sun.COM 
10907532SSean.Ye@Sun.COM static int
xpv_online(cmi_hdl_impl_t * hdl,int new_status,int * old_status)10917532SSean.Ye@Sun.COM xpv_online(cmi_hdl_impl_t *hdl, int new_status, int *old_status)
10927532SSean.Ye@Sun.COM {
109310175SStuart.Maybee@Sun.COM 	xen_sysctl_t xs;
109410175SStuart.Maybee@Sun.COM 	int op, rc, status;
10957532SSean.Ye@Sun.COM 
10967532SSean.Ye@Sun.COM 	new_status &= ~P_FORCED;
10977532SSean.Ye@Sun.COM 
109810175SStuart.Maybee@Sun.COM 	switch (new_status) {
109910175SStuart.Maybee@Sun.COM 	case P_STATUS:
110010175SStuart.Maybee@Sun.COM 		op = XEN_SYSCTL_CPU_HOTPLUG_STATUS;
110110175SStuart.Maybee@Sun.COM 		break;
110210175SStuart.Maybee@Sun.COM 	case P_FAULTED:
110310175SStuart.Maybee@Sun.COM 	case P_OFFLINE:
110410175SStuart.Maybee@Sun.COM 		op = XEN_SYSCTL_CPU_HOTPLUG_OFFLINE;
110510175SStuart.Maybee@Sun.COM 		break;
110610175SStuart.Maybee@Sun.COM 	case P_ONLINE:
110710175SStuart.Maybee@Sun.COM 		op = XEN_SYSCTL_CPU_HOTPLUG_ONLINE;
110810175SStuart.Maybee@Sun.COM 		break;
110910175SStuart.Maybee@Sun.COM 	default:
111010175SStuart.Maybee@Sun.COM 		return (-1);
111110175SStuart.Maybee@Sun.COM 	}
11127532SSean.Ye@Sun.COM 
111310175SStuart.Maybee@Sun.COM 	xs.cmd = XEN_SYSCTL_cpu_hotplug;
111410175SStuart.Maybee@Sun.COM 	xs.interface_version = XEN_SYSCTL_INTERFACE_VERSION;
111510175SStuart.Maybee@Sun.COM 	xs.u.cpu_hotplug.cpu = xen_physcpu_logical_id(HDLPRIV(hdl));
111610175SStuart.Maybee@Sun.COM 	xs.u.cpu_hotplug.op = op;
111710175SStuart.Maybee@Sun.COM 
111810175SStuart.Maybee@Sun.COM 	if ((rc = HYPERVISOR_sysctl(&xs)) >= 0) {
111910175SStuart.Maybee@Sun.COM 		status = rc;
112010175SStuart.Maybee@Sun.COM 		rc = 0;
112110175SStuart.Maybee@Sun.COM 		switch (status) {
112210175SStuart.Maybee@Sun.COM 		case XEN_CPU_HOTPLUG_STATUS_NEW:
112310175SStuart.Maybee@Sun.COM 			*old_status = P_OFFLINE;
112410175SStuart.Maybee@Sun.COM 			break;
112510175SStuart.Maybee@Sun.COM 		case XEN_CPU_HOTPLUG_STATUS_OFFLINE:
112610175SStuart.Maybee@Sun.COM 			*old_status = P_FAULTED;
112710175SStuart.Maybee@Sun.COM 			break;
112810175SStuart.Maybee@Sun.COM 		case XEN_CPU_HOTPLUG_STATUS_ONLINE:
112910175SStuart.Maybee@Sun.COM 			*old_status = P_ONLINE;
113010175SStuart.Maybee@Sun.COM 			break;
113110175SStuart.Maybee@Sun.COM 		default:
113210175SStuart.Maybee@Sun.COM 			return (-1);
113310175SStuart.Maybee@Sun.COM 		}
11347532SSean.Ye@Sun.COM 	}
11357532SSean.Ye@Sun.COM 
11367532SSean.Ye@Sun.COM 	return (-rc);
11377532SSean.Ye@Sun.COM }
11387532SSean.Ye@Sun.COM 
11397532SSean.Ye@Sun.COM #endif
11407532SSean.Ye@Sun.COM 
11417532SSean.Ye@Sun.COM /*ARGSUSED*/
11425254Sgavinm static void *
cpu_search(enum cmi_hdl_class class,uint_t chipid,uint_t coreid,uint_t strandid)11435254Sgavinm cpu_search(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
11445254Sgavinm     uint_t strandid)
11455254Sgavinm {
11467532SSean.Ye@Sun.COM #ifdef __xpv
11477532SSean.Ye@Sun.COM 	xen_mc_lcpu_cookie_t cpi;
11487532SSean.Ye@Sun.COM 
11497532SSean.Ye@Sun.COM 	for (cpi = xen_physcpu_next(NULL); cpi != NULL;
11507532SSean.Ye@Sun.COM 	    cpi = xen_physcpu_next(cpi)) {
11517532SSean.Ye@Sun.COM 		if (xen_physcpu_chipid(cpi) == chipid &&
11527532SSean.Ye@Sun.COM 		    xen_physcpu_coreid(cpi) == coreid &&
11537532SSean.Ye@Sun.COM 		    xen_physcpu_strandid(cpi) == strandid)
11547532SSean.Ye@Sun.COM 			return ((void *)cpi);
11557532SSean.Ye@Sun.COM 	}
11567532SSean.Ye@Sun.COM 	return (NULL);
11577532SSean.Ye@Sun.COM 
11587532SSean.Ye@Sun.COM #else	/* __xpv */
11597532SSean.Ye@Sun.COM 
11607532SSean.Ye@Sun.COM 	cpu_t *cp, *startcp;
11615254Sgavinm 
11627532SSean.Ye@Sun.COM 	kpreempt_disable();
11637532SSean.Ye@Sun.COM 	cp = startcp = CPU;
11647532SSean.Ye@Sun.COM 	do {
11657532SSean.Ye@Sun.COM 		if (cmi_ntv_hwchipid(cp) == chipid &&
11667532SSean.Ye@Sun.COM 		    cmi_ntv_hwcoreid(cp) == coreid &&
11677532SSean.Ye@Sun.COM 		    cmi_ntv_hwstrandid(cp) == strandid) {
11687532SSean.Ye@Sun.COM 			kpreempt_enable();
11697532SSean.Ye@Sun.COM 			return ((void *)cp);
11707532SSean.Ye@Sun.COM 		}
11715254Sgavinm 
11727532SSean.Ye@Sun.COM 		cp = cp->cpu_next;
11737532SSean.Ye@Sun.COM 	} while (cp != startcp);
11747532SSean.Ye@Sun.COM 	kpreempt_enable();
11757532SSean.Ye@Sun.COM 	return (NULL);
11767532SSean.Ye@Sun.COM #endif	/* __ xpv */
11777532SSean.Ye@Sun.COM }
11785254Sgavinm 
11797532SSean.Ye@Sun.COM static boolean_t
cpu_is_cmt(void * priv)11807532SSean.Ye@Sun.COM cpu_is_cmt(void *priv)
11817532SSean.Ye@Sun.COM {
11827532SSean.Ye@Sun.COM #ifdef __xpv
11837532SSean.Ye@Sun.COM 	return (xen_physcpu_is_cmt((xen_mc_lcpu_cookie_t)priv));
11847532SSean.Ye@Sun.COM #else /* __xpv */
11857532SSean.Ye@Sun.COM 	cpu_t *cp = (cpu_t *)priv;
11867532SSean.Ye@Sun.COM 
11877532SSean.Ye@Sun.COM 	int strands_per_core = cpuid_get_ncpu_per_chip(cp) /
11887532SSean.Ye@Sun.COM 	    cpuid_get_ncore_per_chip(cp);
11897532SSean.Ye@Sun.COM 
11907532SSean.Ye@Sun.COM 	return (strands_per_core > 1);
11917532SSean.Ye@Sun.COM #endif /* __xpv */
11925254Sgavinm }
11935254Sgavinm 
11949090SVuong.Nguyen@Sun.COM /*
11959090SVuong.Nguyen@Sun.COM  * Find the handle entry of a given cpu identified by a <chip,core,strand>
11969090SVuong.Nguyen@Sun.COM  * tuple.
11979090SVuong.Nguyen@Sun.COM  */
11989090SVuong.Nguyen@Sun.COM static cmi_hdl_ent_t *
cmi_hdl_ent_lookup(uint_t chipid,uint_t coreid,uint_t strandid)11999090SVuong.Nguyen@Sun.COM cmi_hdl_ent_lookup(uint_t chipid, uint_t coreid, uint_t strandid)
12009090SVuong.Nguyen@Sun.COM {
1201*12261SVuong.Nguyen@Sun.COM 	int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits,
1202*12261SVuong.Nguyen@Sun.COM 	    cmi_strand_nbits);
1203*12261SVuong.Nguyen@Sun.COM 
12049090SVuong.Nguyen@Sun.COM 	/*
12059090SVuong.Nguyen@Sun.COM 	 * Allocate per-chip table which contains a list of handle of
12069090SVuong.Nguyen@Sun.COM 	 * all strands of the chip.
12079090SVuong.Nguyen@Sun.COM 	 */
12089090SVuong.Nguyen@Sun.COM 	if (cmi_chip_tab[chipid] == NULL) {
12099090SVuong.Nguyen@Sun.COM 		size_t sz;
12109090SVuong.Nguyen@Sun.COM 		cmi_hdl_ent_t *pg;
12119090SVuong.Nguyen@Sun.COM 
1212*12261SVuong.Nguyen@Sun.COM 		sz = max_strands * sizeof (cmi_hdl_ent_t);
12139090SVuong.Nguyen@Sun.COM 		pg = kmem_zalloc(sz, KM_SLEEP);
12149090SVuong.Nguyen@Sun.COM 
12159090SVuong.Nguyen@Sun.COM 		/* test and set the per-chip table if it is not allocated */
12169090SVuong.Nguyen@Sun.COM 		if (atomic_cas_ptr(&cmi_chip_tab[chipid], NULL, pg) != NULL)
1217*12261SVuong.Nguyen@Sun.COM 			kmem_free(pg, sz); /* someone beats us */
12189090SVuong.Nguyen@Sun.COM 	}
12199090SVuong.Nguyen@Sun.COM 
1220*12261SVuong.Nguyen@Sun.COM 	return (cmi_chip_tab[chipid] +
1221*12261SVuong.Nguyen@Sun.COM 	    ((((coreid) & CMI_MAX_COREID(cmi_core_nbits)) << cmi_strand_nbits) |
1222*12261SVuong.Nguyen@Sun.COM 	    ((strandid) & CMI_MAX_STRANDID(cmi_strand_nbits))));
12239090SVuong.Nguyen@Sun.COM }
12249090SVuong.Nguyen@Sun.COM 
1225*12261SVuong.Nguyen@Sun.COM extern void cpuid_get_ext_topo(uint_t, uint_t *, uint_t *);
1226*12261SVuong.Nguyen@Sun.COM 
12275254Sgavinm cmi_hdl_t
cmi_hdl_create(enum cmi_hdl_class class,uint_t chipid,uint_t coreid,uint_t strandid)12285254Sgavinm cmi_hdl_create(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
12297532SSean.Ye@Sun.COM     uint_t strandid)
12305254Sgavinm {
12315254Sgavinm 	cmi_hdl_impl_t *hdl;
12327532SSean.Ye@Sun.COM 	void *priv;
12339090SVuong.Nguyen@Sun.COM 	cmi_hdl_ent_t *ent;
1234*12261SVuong.Nguyen@Sun.COM 	uint_t vendor;
12355254Sgavinm 
12367532SSean.Ye@Sun.COM #ifdef __xpv
12377532SSean.Ye@Sun.COM 	ASSERT(class == CMI_HDL_SOLARIS_xVM_MCA);
12387532SSean.Ye@Sun.COM #else
12397532SSean.Ye@Sun.COM 	ASSERT(class == CMI_HDL_NATIVE);
12407532SSean.Ye@Sun.COM #endif
12417532SSean.Ye@Sun.COM 
1242*12261SVuong.Nguyen@Sun.COM 	if ((priv = cpu_search(class, chipid, coreid, strandid)) == NULL)
12435254Sgavinm 		return (NULL);
12445254Sgavinm 
1245*12261SVuong.Nguyen@Sun.COM 	/*
1246*12261SVuong.Nguyen@Sun.COM 	 * Assume all chips in the system are the same type.
1247*12261SVuong.Nguyen@Sun.COM 	 * For Intel, attempt to check if extended topology is available
1248*12261SVuong.Nguyen@Sun.COM 	 * CPUID.EAX=0xB. If so, get the number of core and strand bits.
1249*12261SVuong.Nguyen@Sun.COM 	 */
1250*12261SVuong.Nguyen@Sun.COM #ifdef __xpv
1251*12261SVuong.Nguyen@Sun.COM 	vendor = _cpuid_vendorstr_to_vendorcode(
1252*12261SVuong.Nguyen@Sun.COM 	    (char *)xen_physcpu_vendorstr((xen_mc_lcpu_cookie_t)priv));
1253*12261SVuong.Nguyen@Sun.COM #else
1254*12261SVuong.Nguyen@Sun.COM 	vendor = cpuid_getvendor((cpu_t *)priv);
1255*12261SVuong.Nguyen@Sun.COM #endif
1256*12261SVuong.Nguyen@Sun.COM 	if (vendor == X86_VENDOR_Intel && cmi_ext_topo_check == 0) {
1257*12261SVuong.Nguyen@Sun.COM 		cpuid_get_ext_topo(vendor, &cmi_core_nbits, &cmi_strand_nbits);
1258*12261SVuong.Nguyen@Sun.COM 		cmi_ext_topo_check = 1;
1259*12261SVuong.Nguyen@Sun.COM 	}
1260*12261SVuong.Nguyen@Sun.COM 
1261*12261SVuong.Nguyen@Sun.COM 	if (chipid > CMI_MAX_CHIPID ||
1262*12261SVuong.Nguyen@Sun.COM 	    coreid > CMI_MAX_COREID(cmi_core_nbits) ||
1263*12261SVuong.Nguyen@Sun.COM 	    strandid > CMI_MAX_STRANDID(cmi_strand_nbits))
12645254Sgavinm 		return (NULL);
12655254Sgavinm 
12665254Sgavinm 	hdl = kmem_zalloc(sizeof (*hdl), KM_SLEEP);
12675254Sgavinm 
12685254Sgavinm 	hdl->cmih_class = class;
12697532SSean.Ye@Sun.COM 	HDLOPS(hdl) = &cmi_hdl_ops;
12705254Sgavinm 	hdl->cmih_chipid = chipid;
12715254Sgavinm 	hdl->cmih_coreid = coreid;
12725254Sgavinm 	hdl->cmih_strandid = strandid;
12737532SSean.Ye@Sun.COM 	hdl->cmih_mstrand = cpu_is_cmt(priv);
12745254Sgavinm 	hdl->cmih_hdlpriv = priv;
12757532SSean.Ye@Sun.COM #ifdef __xpv
12767532SSean.Ye@Sun.COM 	hdl->cmih_msrsrc = CMI_MSR_FLAG_RD_INTERPOSEOK |
12777532SSean.Ye@Sun.COM 	    CMI_MSR_FLAG_WR_INTERPOSEOK;
127810947SSrihari.Venkatesan@Sun.COM 
127910947SSrihari.Venkatesan@Sun.COM 	/*
128010947SSrihari.Venkatesan@Sun.COM 	 * XXX: need hypervisor support for procnodeid, for now assume
128110947SSrihari.Venkatesan@Sun.COM 	 * single-node processors (procnodeid = chipid)
128210947SSrihari.Venkatesan@Sun.COM 	 */
128310947SSrihari.Venkatesan@Sun.COM 	hdl->cmih_procnodeid = xen_physcpu_chipid((xen_mc_lcpu_cookie_t)priv);
128410947SSrihari.Venkatesan@Sun.COM 	hdl->cmih_procnodes_per_pkg = 1;
128510947SSrihari.Venkatesan@Sun.COM #else   /* __xpv */
12865254Sgavinm 	hdl->cmih_msrsrc = CMI_MSR_FLAG_RD_HWOK | CMI_MSR_FLAG_RD_INTERPOSEOK |
12875254Sgavinm 	    CMI_MSR_FLAG_WR_HWOK | CMI_MSR_FLAG_WR_INTERPOSEOK;
128810947SSrihari.Venkatesan@Sun.COM 	hdl->cmih_procnodeid = cpuid_get_procnodeid((cpu_t *)priv);
128910947SSrihari.Venkatesan@Sun.COM 	hdl->cmih_procnodes_per_pkg =
129010947SSrihari.Venkatesan@Sun.COM 	    cpuid_get_procnodes_per_pkg((cpu_t *)priv);
129110947SSrihari.Venkatesan@Sun.COM #endif  /* __xpv */
12925254Sgavinm 
12939090SVuong.Nguyen@Sun.COM 	ent = cmi_hdl_ent_lookup(chipid, coreid, strandid);
12949090SVuong.Nguyen@Sun.COM 	if (ent->cmae_refcnt != 0 || ent->cmae_hdlp != NULL) {
12955870Sgavinm 		/*
12965870Sgavinm 		 * Somehow this (chipid, coreid, strandid) id tuple has
12975870Sgavinm 		 * already been assigned!  This indicates that the
12985870Sgavinm 		 * callers logic in determining these values is busted,
12995870Sgavinm 		 * or perhaps undermined by bad BIOS setup.  Complain,
13005870Sgavinm 		 * and refuse to initialize this tuple again as bad things
13015870Sgavinm 		 * will happen.
13025870Sgavinm 		 */
13035870Sgavinm 		cmn_err(CE_NOTE, "cmi_hdl_create: chipid %d coreid %d "
13045870Sgavinm 		    "strandid %d handle already allocated!",
13055870Sgavinm 		    chipid, coreid, strandid);
13065870Sgavinm 		kmem_free(hdl, sizeof (*hdl));
13075870Sgavinm 		return (NULL);
13085870Sgavinm 	}
13095254Sgavinm 
13105254Sgavinm 	/*
13115254Sgavinm 	 * Once we store a nonzero reference count others can find this
13125254Sgavinm 	 * handle via cmi_hdl_lookup etc.  This initial hold on the handle
13135254Sgavinm 	 * is to be dropped only if some other part of cmi initialization
13145254Sgavinm 	 * fails or, if it succeeds, at later cpu deconfigure.  Note the
13155254Sgavinm 	 * the module private data we hold in cmih_cmi and cmih_cmidata
13165254Sgavinm 	 * is still NULL at this point (the caller will fill it with
13175254Sgavinm 	 * cmi_hdl_setcmi if it initializes) so consumers of handles
13185254Sgavinm 	 * should always be ready for that possibility.
13195254Sgavinm 	 */
13209090SVuong.Nguyen@Sun.COM 	ent->cmae_hdlp = hdl;
13219090SVuong.Nguyen@Sun.COM 	hdl->cmih_refcntp = &ent->cmae_refcnt;
13229090SVuong.Nguyen@Sun.COM 	ent->cmae_refcnt = 1;
13235254Sgavinm 
13245254Sgavinm 	return ((cmi_hdl_t)hdl);
13255254Sgavinm }
13265254Sgavinm 
13275254Sgavinm void
cmi_read_smbios(cmi_hdl_t ophdl)132810942STom.Pothier@Sun.COM cmi_read_smbios(cmi_hdl_t ophdl)
132910942STom.Pothier@Sun.COM {
133010942STom.Pothier@Sun.COM 
133111675SSrihari.Venkatesan@Sun.COM 	uint_t strand_apicid = UINT_MAX;
133211675SSrihari.Venkatesan@Sun.COM 	uint_t chip_inst = UINT_MAX;
133311675SSrihari.Venkatesan@Sun.COM 	uint16_t smb_id = USHRT_MAX;
133410942STom.Pothier@Sun.COM 	int rc = 0;
133510942STom.Pothier@Sun.COM 
133610942STom.Pothier@Sun.COM 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
133710942STom.Pothier@Sun.COM 
133810942STom.Pothier@Sun.COM 	/* set x86gentopo compatibility */
133910942STom.Pothier@Sun.COM 	fm_smb_fmacompat();
134010942STom.Pothier@Sun.COM 
134110942STom.Pothier@Sun.COM #ifndef __xpv
134210942STom.Pothier@Sun.COM 	strand_apicid = ntv_strand_apicid(hdl);
134310942STom.Pothier@Sun.COM #else
134410942STom.Pothier@Sun.COM 	strand_apicid = xpv_strand_apicid(hdl);
134510942STom.Pothier@Sun.COM #endif
134610942STom.Pothier@Sun.COM 
134710942STom.Pothier@Sun.COM 	if (!x86gentopo_legacy) {
134810942STom.Pothier@Sun.COM 		/*
134910942STom.Pothier@Sun.COM 		 * If fm_smb_chipinst() or fm_smb_bboard() fails,
135010942STom.Pothier@Sun.COM 		 * topo reverts to legacy mode
135110942STom.Pothier@Sun.COM 		 */
135210942STom.Pothier@Sun.COM 		rc = fm_smb_chipinst(strand_apicid, &chip_inst, &smb_id);
135310942STom.Pothier@Sun.COM 		if (rc == 0) {
135410942STom.Pothier@Sun.COM 			hdl->cmih_smb_chipid = chip_inst;
135510942STom.Pothier@Sun.COM 			hdl->cmih_smbiosid = smb_id;
135610942STom.Pothier@Sun.COM 		} else {
135710942STom.Pothier@Sun.COM #ifdef DEBUG
135810987STom.Pothier@Sun.COM 			cmn_err(CE_NOTE, "!cmi reads smbios chip info failed");
135910942STom.Pothier@Sun.COM #endif /* DEBUG */
136010942STom.Pothier@Sun.COM 			return;
136110942STom.Pothier@Sun.COM 		}
136210942STom.Pothier@Sun.COM 
136310942STom.Pothier@Sun.COM 		hdl->cmih_smb_bboard  = fm_smb_bboard(strand_apicid);
136410942STom.Pothier@Sun.COM #ifdef DEBUG
136510942STom.Pothier@Sun.COM 		if (hdl->cmih_smb_bboard == NULL)
136610942STom.Pothier@Sun.COM 			cmn_err(CE_NOTE,
136710987STom.Pothier@Sun.COM 			    "!cmi reads smbios base boards info failed");
136810942STom.Pothier@Sun.COM #endif /* DEBUG */
136910942STom.Pothier@Sun.COM 	}
137010942STom.Pothier@Sun.COM }
137110942STom.Pothier@Sun.COM 
137210942STom.Pothier@Sun.COM void
cmi_hdl_hold(cmi_hdl_t ophdl)13735254Sgavinm cmi_hdl_hold(cmi_hdl_t ophdl)
13745254Sgavinm {
13755254Sgavinm 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
13765254Sgavinm 
13775254Sgavinm 	ASSERT(*hdl->cmih_refcntp != 0); /* must not be the initial hold */
13785254Sgavinm 
13795254Sgavinm 	atomic_inc_32(hdl->cmih_refcntp);
13805254Sgavinm }
13815254Sgavinm 
13825254Sgavinm static int
cmi_hdl_canref(cmi_hdl_ent_t * ent)13839090SVuong.Nguyen@Sun.COM cmi_hdl_canref(cmi_hdl_ent_t *ent)
13845254Sgavinm {
13855254Sgavinm 	volatile uint32_t *refcntp;
13865254Sgavinm 	uint32_t refcnt;
13875254Sgavinm 
13889090SVuong.Nguyen@Sun.COM 	refcntp = &ent->cmae_refcnt;
13895254Sgavinm 	refcnt = *refcntp;
13905254Sgavinm 
13915254Sgavinm 	if (refcnt == 0) {
13925254Sgavinm 		/*
13935254Sgavinm 		 * Associated object never existed, is being destroyed,
13945254Sgavinm 		 * or has been destroyed.
13955254Sgavinm 		 */
13965254Sgavinm 		return (0);
13975254Sgavinm 	}
13985254Sgavinm 
13995254Sgavinm 	/*
14005254Sgavinm 	 * We cannot use atomic increment here because once the reference
14015254Sgavinm 	 * count reaches zero it must never be bumped up again.
14025254Sgavinm 	 */
14035254Sgavinm 	while (refcnt != 0) {
14045254Sgavinm 		if (atomic_cas_32(refcntp, refcnt, refcnt + 1) == refcnt)
14055254Sgavinm 			return (1);
14065254Sgavinm 		refcnt = *refcntp;
14075254Sgavinm 	}
14085254Sgavinm 
14095254Sgavinm 	/*
14105254Sgavinm 	 * Somebody dropped the reference count to 0 after our initial
14115254Sgavinm 	 * check.
14125254Sgavinm 	 */
14135254Sgavinm 	return (0);
14145254Sgavinm }
14155254Sgavinm 
14165254Sgavinm 
14175254Sgavinm void
cmi_hdl_rele(cmi_hdl_t ophdl)14185254Sgavinm cmi_hdl_rele(cmi_hdl_t ophdl)
14195254Sgavinm {
14205254Sgavinm 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
14215254Sgavinm 
14225254Sgavinm 	ASSERT(*hdl->cmih_refcntp > 0);
142312004Sjiang.liu@intel.com 	(void) atomic_dec_32_nv(hdl->cmih_refcntp);
142412004Sjiang.liu@intel.com }
14255254Sgavinm 
142612004Sjiang.liu@intel.com void
cmi_hdl_destroy(cmi_hdl_t ophdl)142712004Sjiang.liu@intel.com cmi_hdl_destroy(cmi_hdl_t ophdl)
142812004Sjiang.liu@intel.com {
142912004Sjiang.liu@intel.com 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
143012004Sjiang.liu@intel.com 	cmi_hdl_ent_t *ent;
143112004Sjiang.liu@intel.com 
143212004Sjiang.liu@intel.com 	/* Release the reference count held by cmi_hdl_create(). */
143312004Sjiang.liu@intel.com 	ASSERT(*hdl->cmih_refcntp > 0);
143412004Sjiang.liu@intel.com 	(void) atomic_dec_32_nv(hdl->cmih_refcntp);
143512004Sjiang.liu@intel.com 	hdl->cmih_flags |= CMIH_F_DEAD;
14365254Sgavinm 
14379090SVuong.Nguyen@Sun.COM 	ent = cmi_hdl_ent_lookup(hdl->cmih_chipid, hdl->cmih_coreid,
14385254Sgavinm 	    hdl->cmih_strandid);
143912004Sjiang.liu@intel.com 	/*
144012004Sjiang.liu@intel.com 	 * Use busy polling instead of condition variable here because
144112004Sjiang.liu@intel.com 	 * cmi_hdl_rele() may be called from #MC handler.
144212004Sjiang.liu@intel.com 	 */
144312004Sjiang.liu@intel.com 	while (cmi_hdl_canref(ent)) {
144412004Sjiang.liu@intel.com 		cmi_hdl_rele(ophdl);
144512004Sjiang.liu@intel.com 		delay(1);
144612004Sjiang.liu@intel.com 	}
14479090SVuong.Nguyen@Sun.COM 	ent->cmae_hdlp = NULL;
14485254Sgavinm 
14495254Sgavinm 	kmem_free(hdl, sizeof (*hdl));
14505254Sgavinm }
14515254Sgavinm 
14525254Sgavinm void
cmi_hdl_setspecific(cmi_hdl_t ophdl,void * arg)14535254Sgavinm cmi_hdl_setspecific(cmi_hdl_t ophdl, void *arg)
14545254Sgavinm {
14555254Sgavinm 	IMPLHDL(ophdl)->cmih_spec = arg;
14565254Sgavinm }
14575254Sgavinm 
14585254Sgavinm void *
cmi_hdl_getspecific(cmi_hdl_t ophdl)14595254Sgavinm cmi_hdl_getspecific(cmi_hdl_t ophdl)
14605254Sgavinm {
14615254Sgavinm 	return (IMPLHDL(ophdl)->cmih_spec);
14625254Sgavinm }
14635254Sgavinm 
14645254Sgavinm void
cmi_hdl_setmc(cmi_hdl_t ophdl,const struct cmi_mc_ops * mcops,void * mcdata)14655254Sgavinm cmi_hdl_setmc(cmi_hdl_t ophdl, const struct cmi_mc_ops *mcops, void *mcdata)
14665254Sgavinm {
14675254Sgavinm 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
14685254Sgavinm 
14695254Sgavinm 	ASSERT(hdl->cmih_mcops == NULL && hdl->cmih_mcdata == NULL);
14705254Sgavinm 	hdl->cmih_mcops = mcops;
14715254Sgavinm 	hdl->cmih_mcdata = mcdata;
14725254Sgavinm }
14735254Sgavinm 
14745254Sgavinm const struct cmi_mc_ops *
cmi_hdl_getmcops(cmi_hdl_t ophdl)14755254Sgavinm cmi_hdl_getmcops(cmi_hdl_t ophdl)
14765254Sgavinm {
14775254Sgavinm 	return (IMPLHDL(ophdl)->cmih_mcops);
14785254Sgavinm }
14795254Sgavinm 
14805254Sgavinm void *
cmi_hdl_getmcdata(cmi_hdl_t ophdl)14815254Sgavinm cmi_hdl_getmcdata(cmi_hdl_t ophdl)
14825254Sgavinm {
14835254Sgavinm 	return (IMPLHDL(ophdl)->cmih_mcdata);
14845254Sgavinm }
14855254Sgavinm 
14865254Sgavinm cmi_hdl_t
cmi_hdl_lookup(enum cmi_hdl_class class,uint_t chipid,uint_t coreid,uint_t strandid)14875254Sgavinm cmi_hdl_lookup(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
14885254Sgavinm     uint_t strandid)
14895254Sgavinm {
14909090SVuong.Nguyen@Sun.COM 	cmi_hdl_ent_t *ent;
14916685Sstephh 
14929090SVuong.Nguyen@Sun.COM 	if (chipid > CMI_MAX_CHIPID ||
1493*12261SVuong.Nguyen@Sun.COM 	    coreid > CMI_MAX_COREID(cmi_core_nbits) ||
1494*12261SVuong.Nguyen@Sun.COM 	    strandid > CMI_MAX_STRANDID(cmi_strand_nbits))
14956685Sstephh 		return (NULL);
14966685Sstephh 
14979090SVuong.Nguyen@Sun.COM 	ent = cmi_hdl_ent_lookup(chipid, coreid, strandid);
14985254Sgavinm 
14997532SSean.Ye@Sun.COM 	if (class == CMI_HDL_NEUTRAL)
15007532SSean.Ye@Sun.COM #ifdef __xpv
15017532SSean.Ye@Sun.COM 		class = CMI_HDL_SOLARIS_xVM_MCA;
15027532SSean.Ye@Sun.COM #else
15037532SSean.Ye@Sun.COM 		class = CMI_HDL_NATIVE;
15047532SSean.Ye@Sun.COM #endif
15057532SSean.Ye@Sun.COM 
15069090SVuong.Nguyen@Sun.COM 	if (!cmi_hdl_canref(ent))
15075254Sgavinm 		return (NULL);
15085254Sgavinm 
15099090SVuong.Nguyen@Sun.COM 	if (ent->cmae_hdlp->cmih_class != class) {
15109090SVuong.Nguyen@Sun.COM 		cmi_hdl_rele((cmi_hdl_t)ent->cmae_hdlp);
15115254Sgavinm 		return (NULL);
15125254Sgavinm 	}
15135254Sgavinm 
15149090SVuong.Nguyen@Sun.COM 	return ((cmi_hdl_t)ent->cmae_hdlp);
15155254Sgavinm }
15165254Sgavinm 
15175254Sgavinm cmi_hdl_t
cmi_hdl_any(void)15185254Sgavinm cmi_hdl_any(void)
15195254Sgavinm {
15209090SVuong.Nguyen@Sun.COM 	int i, j;
15219090SVuong.Nguyen@Sun.COM 	cmi_hdl_ent_t *ent;
1522*12261SVuong.Nguyen@Sun.COM 	int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits,
1523*12261SVuong.Nguyen@Sun.COM 	    cmi_strand_nbits);
15245254Sgavinm 
15259090SVuong.Nguyen@Sun.COM 	for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) {
15269090SVuong.Nguyen@Sun.COM 		if (cmi_chip_tab[i] == NULL)
15279090SVuong.Nguyen@Sun.COM 			continue;
1528*12261SVuong.Nguyen@Sun.COM 		for (j = 0, ent = cmi_chip_tab[i]; j < max_strands;
15299090SVuong.Nguyen@Sun.COM 		    j++, ent++) {
15309090SVuong.Nguyen@Sun.COM 			if (cmi_hdl_canref(ent))
15319090SVuong.Nguyen@Sun.COM 				return ((cmi_hdl_t)ent->cmae_hdlp);
15329090SVuong.Nguyen@Sun.COM 		}
15335254Sgavinm 	}
15345254Sgavinm 
15355254Sgavinm 	return (NULL);
15365254Sgavinm }
15375254Sgavinm 
15385254Sgavinm void
cmi_hdl_walk(int (* cbfunc)(cmi_hdl_t,void *,void *,void *),void * arg1,void * arg2,void * arg3)15395254Sgavinm cmi_hdl_walk(int (*cbfunc)(cmi_hdl_t, void *, void *, void *),
15405254Sgavinm     void *arg1, void *arg2, void *arg3)
15415254Sgavinm {
15429090SVuong.Nguyen@Sun.COM 	int i, j;
15439090SVuong.Nguyen@Sun.COM 	cmi_hdl_ent_t *ent;
1544*12261SVuong.Nguyen@Sun.COM 	int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits,
1545*12261SVuong.Nguyen@Sun.COM 	    cmi_strand_nbits);
15465254Sgavinm 
15479090SVuong.Nguyen@Sun.COM 	for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) {
15489090SVuong.Nguyen@Sun.COM 		if (cmi_chip_tab[i] == NULL)
15499090SVuong.Nguyen@Sun.COM 			continue;
1550*12261SVuong.Nguyen@Sun.COM 		for (j = 0, ent = cmi_chip_tab[i]; j < max_strands;
15519090SVuong.Nguyen@Sun.COM 		    j++, ent++) {
15529090SVuong.Nguyen@Sun.COM 			if (cmi_hdl_canref(ent)) {
15539090SVuong.Nguyen@Sun.COM 				cmi_hdl_impl_t *hdl = ent->cmae_hdlp;
15549090SVuong.Nguyen@Sun.COM 				if ((*cbfunc)((cmi_hdl_t)hdl, arg1, arg2, arg3)
15559090SVuong.Nguyen@Sun.COM 				    == CMI_HDL_WALK_DONE) {
15569090SVuong.Nguyen@Sun.COM 					cmi_hdl_rele((cmi_hdl_t)hdl);
15579090SVuong.Nguyen@Sun.COM 					return;
15589090SVuong.Nguyen@Sun.COM 				}
15595254Sgavinm 				cmi_hdl_rele((cmi_hdl_t)hdl);
15605254Sgavinm 			}
15615254Sgavinm 		}
15625254Sgavinm 	}
15635254Sgavinm }
15645254Sgavinm 
15655254Sgavinm void
cmi_hdl_setcmi(cmi_hdl_t ophdl,void * cmi,void * cmidata)15665254Sgavinm cmi_hdl_setcmi(cmi_hdl_t ophdl, void *cmi, void *cmidata)
15675254Sgavinm {
15685254Sgavinm 	IMPLHDL(ophdl)->cmih_cmidata = cmidata;
15695254Sgavinm 	IMPLHDL(ophdl)->cmih_cmi = cmi;
15705254Sgavinm }
15715254Sgavinm 
15725254Sgavinm void *
cmi_hdl_getcmi(cmi_hdl_t ophdl)15735254Sgavinm cmi_hdl_getcmi(cmi_hdl_t ophdl)
15745254Sgavinm {
15755254Sgavinm 	return (IMPLHDL(ophdl)->cmih_cmi);
15765254Sgavinm }
15775254Sgavinm 
15785254Sgavinm void *
cmi_hdl_getcmidata(cmi_hdl_t ophdl)15795254Sgavinm cmi_hdl_getcmidata(cmi_hdl_t ophdl)
15805254Sgavinm {
15815254Sgavinm 	return (IMPLHDL(ophdl)->cmih_cmidata);
15825254Sgavinm }
15835254Sgavinm 
15845254Sgavinm enum cmi_hdl_class
cmi_hdl_class(cmi_hdl_t ophdl)15855254Sgavinm cmi_hdl_class(cmi_hdl_t ophdl)
15865254Sgavinm {
15875254Sgavinm 	return (IMPLHDL(ophdl)->cmih_class);
15885254Sgavinm }
15895254Sgavinm 
15905254Sgavinm #define	CMI_HDL_OPFUNC(what, type)				\
15915254Sgavinm 	type							\
15925254Sgavinm 	cmi_hdl_##what(cmi_hdl_t ophdl)				\
15935254Sgavinm 	{							\
15947532SSean.Ye@Sun.COM 		return (HDLOPS(IMPLHDL(ophdl))->		\
15955254Sgavinm 		    cmio_##what(IMPLHDL(ophdl)));		\
15965254Sgavinm 	}
15975254Sgavinm 
CMI_HDL_OPFUNC(vendor,uint_t)15985254Sgavinm CMI_HDL_OPFUNC(vendor, uint_t)
15995254Sgavinm CMI_HDL_OPFUNC(vendorstr, const char *)
16005254Sgavinm CMI_HDL_OPFUNC(family, uint_t)
16015254Sgavinm CMI_HDL_OPFUNC(model, uint_t)
16025254Sgavinm CMI_HDL_OPFUNC(stepping, uint_t)
16035254Sgavinm CMI_HDL_OPFUNC(chipid, uint_t)
160410947SSrihari.Venkatesan@Sun.COM CMI_HDL_OPFUNC(procnodeid, uint_t)
16055254Sgavinm CMI_HDL_OPFUNC(coreid, uint_t)
16065254Sgavinm CMI_HDL_OPFUNC(strandid, uint_t)
160710947SSrihari.Venkatesan@Sun.COM CMI_HDL_OPFUNC(procnodes_per_pkg, uint_t)
160810942STom.Pothier@Sun.COM CMI_HDL_OPFUNC(strand_apicid, uint_t)
16095254Sgavinm CMI_HDL_OPFUNC(chiprev, uint32_t)
16105254Sgavinm CMI_HDL_OPFUNC(chiprevstr, const char *)
16115254Sgavinm CMI_HDL_OPFUNC(getsockettype, uint32_t)
16129482SKuriakose.Kuruvilla@Sun.COM CMI_HDL_OPFUNC(getsocketstr, const char *)
16137532SSean.Ye@Sun.COM CMI_HDL_OPFUNC(logical_id, id_t)
161410942STom.Pothier@Sun.COM CMI_HDL_OPFUNC(smbiosid, uint16_t)
161510942STom.Pothier@Sun.COM CMI_HDL_OPFUNC(smb_chipid, uint_t)
161610942STom.Pothier@Sun.COM CMI_HDL_OPFUNC(smb_bboard, nvlist_t *)
16177532SSean.Ye@Sun.COM 
16187532SSean.Ye@Sun.COM boolean_t
16197532SSean.Ye@Sun.COM cmi_hdl_is_cmt(cmi_hdl_t ophdl)
16207532SSean.Ye@Sun.COM {
16217532SSean.Ye@Sun.COM 	return (IMPLHDL(ophdl)->cmih_mstrand);
16227532SSean.Ye@Sun.COM }
16235254Sgavinm 
16245254Sgavinm void
cmi_hdl_int(cmi_hdl_t ophdl,int num)16257349SAdrian.Frost@Sun.COM cmi_hdl_int(cmi_hdl_t ophdl, int num)
16265254Sgavinm {
16277532SSean.Ye@Sun.COM 	if (HDLOPS(IMPLHDL(ophdl))->cmio_int == NULL)
16287532SSean.Ye@Sun.COM 		return;
16297532SSean.Ye@Sun.COM 
16307532SSean.Ye@Sun.COM 	cmi_hdl_inj_begin(ophdl);
16317532SSean.Ye@Sun.COM 	HDLOPS(IMPLHDL(ophdl))->cmio_int(IMPLHDL(ophdl), num);
16327532SSean.Ye@Sun.COM 	cmi_hdl_inj_end(NULL);
16337532SSean.Ye@Sun.COM }
16347532SSean.Ye@Sun.COM 
16357532SSean.Ye@Sun.COM int
cmi_hdl_online(cmi_hdl_t ophdl,int new_status,int * old_status)16367532SSean.Ye@Sun.COM cmi_hdl_online(cmi_hdl_t ophdl, int new_status, int *old_status)
16377532SSean.Ye@Sun.COM {
16387532SSean.Ye@Sun.COM 	return (HDLOPS(IMPLHDL(ophdl))->cmio_online(IMPLHDL(ophdl),
16397532SSean.Ye@Sun.COM 	    new_status, old_status));
16405254Sgavinm }
16415254Sgavinm 
16425254Sgavinm #ifndef	__xpv
16435254Sgavinm /*
16445254Sgavinm  * Return hardware chip instance; cpuid_get_chipid provides this directly.
16455254Sgavinm  */
16465254Sgavinm uint_t
cmi_ntv_hwchipid(cpu_t * cp)16475254Sgavinm cmi_ntv_hwchipid(cpu_t *cp)
16485254Sgavinm {
16495254Sgavinm 	return (cpuid_get_chipid(cp));
16505254Sgavinm }
16515254Sgavinm 
16525254Sgavinm /*
165310947SSrihari.Venkatesan@Sun.COM  * Return hardware node instance; cpuid_get_procnodeid provides this directly.
165410947SSrihari.Venkatesan@Sun.COM  */
165510947SSrihari.Venkatesan@Sun.COM uint_t
cmi_ntv_hwprocnodeid(cpu_t * cp)165610947SSrihari.Venkatesan@Sun.COM cmi_ntv_hwprocnodeid(cpu_t *cp)
165710947SSrihari.Venkatesan@Sun.COM {
165810947SSrihari.Venkatesan@Sun.COM 	return (cpuid_get_procnodeid(cp));
165910947SSrihari.Venkatesan@Sun.COM }
166010947SSrihari.Venkatesan@Sun.COM 
166110947SSrihari.Venkatesan@Sun.COM /*
16625870Sgavinm  * Return core instance within a single chip.
16635254Sgavinm  */
16645254Sgavinm uint_t
cmi_ntv_hwcoreid(cpu_t * cp)16655254Sgavinm cmi_ntv_hwcoreid(cpu_t *cp)
16665254Sgavinm {
16675870Sgavinm 	return (cpuid_get_pkgcoreid(cp));
16685254Sgavinm }
16695254Sgavinm 
16705254Sgavinm /*
16715254Sgavinm  * Return strand number within a single core.  cpuid_get_clogid numbers
16725254Sgavinm  * all execution units (strands, or cores in unstranded models) sequentially
16735254Sgavinm  * within a single chip.
16745254Sgavinm  */
16755254Sgavinm uint_t
cmi_ntv_hwstrandid(cpu_t * cp)16765254Sgavinm cmi_ntv_hwstrandid(cpu_t *cp)
16775254Sgavinm {
16785254Sgavinm 	int strands_per_core = cpuid_get_ncpu_per_chip(cp) /
16795254Sgavinm 	    cpuid_get_ncore_per_chip(cp);
16805254Sgavinm 
16815254Sgavinm 	return (cpuid_get_clogid(cp) % strands_per_core);
16825254Sgavinm }
168312004Sjiang.liu@intel.com 
168412004Sjiang.liu@intel.com static void
cmi_ntv_hwdisable_mce_xc(void)168512004Sjiang.liu@intel.com cmi_ntv_hwdisable_mce_xc(void)
168612004Sjiang.liu@intel.com {
168712004Sjiang.liu@intel.com 	ulong_t cr4;
168812004Sjiang.liu@intel.com 
168912004Sjiang.liu@intel.com 	cr4 = getcr4();
169012004Sjiang.liu@intel.com 	cr4 = cr4 & (~CR4_MCE);
169112004Sjiang.liu@intel.com 	setcr4(cr4);
169212004Sjiang.liu@intel.com }
169312004Sjiang.liu@intel.com 
169412004Sjiang.liu@intel.com void
cmi_ntv_hwdisable_mce(cmi_hdl_t hdl)169512004Sjiang.liu@intel.com cmi_ntv_hwdisable_mce(cmi_hdl_t hdl)
169612004Sjiang.liu@intel.com {
169712004Sjiang.liu@intel.com 	cpuset_t	set;
169812004Sjiang.liu@intel.com 	cmi_hdl_impl_t *thdl = IMPLHDL(hdl);
169912004Sjiang.liu@intel.com 	cpu_t *cp = HDLPRIV(thdl);
170012004Sjiang.liu@intel.com 
170112004Sjiang.liu@intel.com 	if (CPU->cpu_id == cp->cpu_id) {
170212004Sjiang.liu@intel.com 		cmi_ntv_hwdisable_mce_xc();
170312004Sjiang.liu@intel.com 	} else {
170412004Sjiang.liu@intel.com 		CPUSET_ONLY(set, cp->cpu_id);
170512004Sjiang.liu@intel.com 		xc_call(NULL, NULL, NULL, CPUSET2BV(set),
170612004Sjiang.liu@intel.com 		    (xc_func_t)cmi_ntv_hwdisable_mce_xc);
170712004Sjiang.liu@intel.com 	}
170812004Sjiang.liu@intel.com }
170912004Sjiang.liu@intel.com 
17105254Sgavinm #endif	/* __xpv */
17115254Sgavinm 
17125254Sgavinm void
cmi_hdlconf_rdmsr_nohw(cmi_hdl_t ophdl)17135254Sgavinm cmi_hdlconf_rdmsr_nohw(cmi_hdl_t ophdl)
17145254Sgavinm {
17155254Sgavinm 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
17165254Sgavinm 
17175254Sgavinm 	hdl->cmih_msrsrc &= ~CMI_MSR_FLAG_RD_HWOK;
17185254Sgavinm }
17195254Sgavinm 
17205254Sgavinm void
cmi_hdlconf_wrmsr_nohw(cmi_hdl_t ophdl)17215254Sgavinm cmi_hdlconf_wrmsr_nohw(cmi_hdl_t ophdl)
17225254Sgavinm {
17235254Sgavinm 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
17245254Sgavinm 
17255254Sgavinm 	hdl->cmih_msrsrc &= ~CMI_MSR_FLAG_WR_HWOK;
17265254Sgavinm }
17275254Sgavinm 
17285254Sgavinm cmi_errno_t
cmi_hdl_rdmsr(cmi_hdl_t ophdl,uint_t msr,uint64_t * valp)17295254Sgavinm cmi_hdl_rdmsr(cmi_hdl_t ophdl, uint_t msr, uint64_t *valp)
17305254Sgavinm {
17315254Sgavinm 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
17325254Sgavinm 
17335254Sgavinm 	/*
17345254Sgavinm 	 * Regardless of the handle class, we first check for am
17355254Sgavinm 	 * interposed value.  In the xVM case you probably want to
17365254Sgavinm 	 * place interposed values within the hypervisor itself, but
17375254Sgavinm 	 * we still allow interposing them in dom0 for test and bringup
17385254Sgavinm 	 * purposes.
17395254Sgavinm 	 */
17405254Sgavinm 	if ((hdl->cmih_msrsrc & CMI_MSR_FLAG_RD_INTERPOSEOK) &&
17415254Sgavinm 	    msri_lookup(hdl, msr, valp))
17425254Sgavinm 		return (CMI_SUCCESS);
17435254Sgavinm 
17447532SSean.Ye@Sun.COM 	if (HDLOPS(hdl)->cmio_rdmsr == NULL)
17457532SSean.Ye@Sun.COM 		return (CMIERR_NOTSUP);
17465254Sgavinm 
17477532SSean.Ye@Sun.COM 	return (HDLOPS(hdl)->cmio_rdmsr(hdl, msr, valp));
17485254Sgavinm }
17495254Sgavinm 
17505254Sgavinm cmi_errno_t
cmi_hdl_wrmsr(cmi_hdl_t ophdl,uint_t msr,uint64_t val)17515254Sgavinm cmi_hdl_wrmsr(cmi_hdl_t ophdl, uint_t msr, uint64_t val)
17525254Sgavinm {
17535254Sgavinm 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
17545254Sgavinm 
17555254Sgavinm 	/* Invalidate any interposed value */
17565254Sgavinm 	msri_rment(hdl, msr);
17575254Sgavinm 
17587532SSean.Ye@Sun.COM 	if (HDLOPS(hdl)->cmio_wrmsr == NULL)
17597532SSean.Ye@Sun.COM 		return (CMI_SUCCESS);	/* pretend all is ok */
17605254Sgavinm 
17617532SSean.Ye@Sun.COM 	return (HDLOPS(hdl)->cmio_wrmsr(hdl, msr, val));
17625254Sgavinm }
17635254Sgavinm 
17645254Sgavinm void
cmi_hdl_enable_mce(cmi_hdl_t ophdl)17655254Sgavinm cmi_hdl_enable_mce(cmi_hdl_t ophdl)
17665254Sgavinm {
17675254Sgavinm 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
17687532SSean.Ye@Sun.COM 	ulong_t cr4;
17695254Sgavinm 
17707532SSean.Ye@Sun.COM 	if (HDLOPS(hdl)->cmio_getcr4 == NULL ||
17717532SSean.Ye@Sun.COM 	    HDLOPS(hdl)->cmio_setcr4 == NULL)
17727532SSean.Ye@Sun.COM 		return;
17737532SSean.Ye@Sun.COM 
17747532SSean.Ye@Sun.COM 	cr4 = HDLOPS(hdl)->cmio_getcr4(hdl);
17757532SSean.Ye@Sun.COM 
17767532SSean.Ye@Sun.COM 	HDLOPS(hdl)->cmio_setcr4(hdl, cr4 | CR4_MCE);
17775254Sgavinm }
17785254Sgavinm 
17795254Sgavinm void
cmi_hdl_msrinterpose(cmi_hdl_t ophdl,cmi_mca_regs_t * regs,uint_t nregs)17805254Sgavinm cmi_hdl_msrinterpose(cmi_hdl_t ophdl, cmi_mca_regs_t *regs, uint_t nregs)
17815254Sgavinm {
17825254Sgavinm 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
17835254Sgavinm 	int i;
17845254Sgavinm 
17857532SSean.Ye@Sun.COM 	if (HDLOPS(hdl)->cmio_msrinterpose == NULL)
17867532SSean.Ye@Sun.COM 		return;
17877532SSean.Ye@Sun.COM 
17887532SSean.Ye@Sun.COM 	cmi_hdl_inj_begin(ophdl);
17897532SSean.Ye@Sun.COM 
17907532SSean.Ye@Sun.COM 	for (i = 0; i < nregs; i++, regs++)
17917532SSean.Ye@Sun.COM 		HDLOPS(hdl)->cmio_msrinterpose(hdl, regs->cmr_msrnum,
17927532SSean.Ye@Sun.COM 		    regs->cmr_msrval);
17937532SSean.Ye@Sun.COM 
17947532SSean.Ye@Sun.COM 	cmi_hdl_inj_end(ophdl);
17955254Sgavinm }
17965254Sgavinm 
17977532SSean.Ye@Sun.COM /*ARGSUSED*/
17987532SSean.Ye@Sun.COM void
cmi_hdl_msrforward(cmi_hdl_t ophdl,cmi_mca_regs_t * regs,uint_t nregs)17997532SSean.Ye@Sun.COM cmi_hdl_msrforward(cmi_hdl_t ophdl, cmi_mca_regs_t *regs, uint_t nregs)
18007532SSean.Ye@Sun.COM {
18017532SSean.Ye@Sun.COM #ifdef __xpv
18027532SSean.Ye@Sun.COM 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
18037532SSean.Ye@Sun.COM 	int i;
18047532SSean.Ye@Sun.COM 
18057532SSean.Ye@Sun.COM 	for (i = 0; i < nregs; i++, regs++)
18067532SSean.Ye@Sun.COM 		msri_addent(hdl, regs->cmr_msrnum, regs->cmr_msrval);
18077532SSean.Ye@Sun.COM #endif
18087532SSean.Ye@Sun.COM }
18097532SSean.Ye@Sun.COM 
18107532SSean.Ye@Sun.COM 
18115254Sgavinm void
cmi_pcird_nohw(void)18125254Sgavinm cmi_pcird_nohw(void)
18135254Sgavinm {
18145254Sgavinm 	cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_RD_HWOK;
18155254Sgavinm }
18165254Sgavinm 
18175254Sgavinm void
cmi_pciwr_nohw(void)18185254Sgavinm cmi_pciwr_nohw(void)
18195254Sgavinm {
18205254Sgavinm 	cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_WR_HWOK;
18215254Sgavinm }
18225254Sgavinm 
18235254Sgavinm static uint32_t
cmi_pci_get_cmn(int bus,int dev,int func,int reg,int asz,int * interpose,ddi_acc_handle_t hdl)18245254Sgavinm cmi_pci_get_cmn(int bus, int dev, int func, int reg, int asz,
18255254Sgavinm     int *interpose, ddi_acc_handle_t hdl)
18265254Sgavinm {
18275254Sgavinm 	uint32_t val;
18285254Sgavinm 
18295254Sgavinm 	if (cmi_pcicfg_flags & CMI_PCICFG_FLAG_RD_INTERPOSEOK &&
18305254Sgavinm 	    pcii_lookup(bus, dev, func, reg, asz, &val)) {
18315254Sgavinm 		if (interpose)
18325254Sgavinm 			*interpose = 1;
18335254Sgavinm 		return (val);
18345254Sgavinm 	}
18355254Sgavinm 	if (interpose)
18365254Sgavinm 		*interpose = 0;
18375254Sgavinm 
18385254Sgavinm 	if (!(cmi_pcicfg_flags & CMI_PCICFG_FLAG_RD_HWOK))
18395254Sgavinm 		return (0);
18405254Sgavinm 
18415254Sgavinm 	switch (asz) {
18425254Sgavinm 	case 1:
18435254Sgavinm 		if (hdl)
18445254Sgavinm 			val = pci_config_get8(hdl, (off_t)reg);
18455254Sgavinm 		else
184611947Ssrihari.venkatesan@oracle.com 			val = pci_cfgacc_get8(NULL, PCI_GETBDF(bus, dev, func),
184711947Ssrihari.venkatesan@oracle.com 			    reg);
18485254Sgavinm 		break;
18495254Sgavinm 	case 2:
18505254Sgavinm 		if (hdl)
18515254Sgavinm 			val = pci_config_get16(hdl, (off_t)reg);
18525254Sgavinm 		else
185311947Ssrihari.venkatesan@oracle.com 			val = pci_cfgacc_get16(NULL, PCI_GETBDF(bus, dev, func),
185411947Ssrihari.venkatesan@oracle.com 			    reg);
18555254Sgavinm 		break;
18565254Sgavinm 	case 4:
18575254Sgavinm 		if (hdl)
18585254Sgavinm 			val = pci_config_get32(hdl, (off_t)reg);
18595254Sgavinm 		else
186011947Ssrihari.venkatesan@oracle.com 			val = pci_cfgacc_get32(NULL, PCI_GETBDF(bus, dev, func),
186111947Ssrihari.venkatesan@oracle.com 			    reg);
18625254Sgavinm 		break;
18635254Sgavinm 	default:
18645254Sgavinm 		val = 0;
18655254Sgavinm 	}
18665254Sgavinm 	return (val);
18675254Sgavinm }
18685254Sgavinm 
18695254Sgavinm uint8_t
cmi_pci_getb(int bus,int dev,int func,int reg,int * interpose,ddi_acc_handle_t hdl)18705254Sgavinm cmi_pci_getb(int bus, int dev, int func, int reg, int *interpose,
18715254Sgavinm     ddi_acc_handle_t hdl)
18725254Sgavinm {
18735254Sgavinm 	return ((uint8_t)cmi_pci_get_cmn(bus, dev, func, reg, 1, interpose,
18745254Sgavinm 	    hdl));
18755254Sgavinm }
18765254Sgavinm 
18775254Sgavinm uint16_t
cmi_pci_getw(int bus,int dev,int func,int reg,int * interpose,ddi_acc_handle_t hdl)18785254Sgavinm cmi_pci_getw(int bus, int dev, int func, int reg, int *interpose,
18795254Sgavinm     ddi_acc_handle_t hdl)
18805254Sgavinm {
18815254Sgavinm 	return ((uint16_t)cmi_pci_get_cmn(bus, dev, func, reg, 2, interpose,
18825254Sgavinm 	    hdl));
18835254Sgavinm }
18845254Sgavinm 
18855254Sgavinm uint32_t
cmi_pci_getl(int bus,int dev,int func,int reg,int * interpose,ddi_acc_handle_t hdl)18865254Sgavinm cmi_pci_getl(int bus, int dev, int func, int reg, int *interpose,
18875254Sgavinm     ddi_acc_handle_t hdl)
18885254Sgavinm {
18895254Sgavinm 	return (cmi_pci_get_cmn(bus, dev, func, reg, 4, interpose, hdl));
18905254Sgavinm }
18915254Sgavinm 
18925254Sgavinm void
cmi_pci_interposeb(int bus,int dev,int func,int reg,uint8_t val)18935254Sgavinm cmi_pci_interposeb(int bus, int dev, int func, int reg, uint8_t val)
18945254Sgavinm {
18955254Sgavinm 	pcii_addent(bus, dev, func, reg, val, 1);
18965254Sgavinm }
18975254Sgavinm 
18985254Sgavinm void
cmi_pci_interposew(int bus,int dev,int func,int reg,uint16_t val)18995254Sgavinm cmi_pci_interposew(int bus, int dev, int func, int reg, uint16_t val)
19005254Sgavinm {
19015254Sgavinm 	pcii_addent(bus, dev, func, reg, val, 2);
19025254Sgavinm }
19035254Sgavinm 
19045254Sgavinm void
cmi_pci_interposel(int bus,int dev,int func,int reg,uint32_t val)19055254Sgavinm cmi_pci_interposel(int bus, int dev, int func, int reg, uint32_t val)
19065254Sgavinm {
19075254Sgavinm 	pcii_addent(bus, dev, func, reg, val, 4);
19085254Sgavinm }
19095254Sgavinm 
19105254Sgavinm static void
cmi_pci_put_cmn(int bus,int dev,int func,int reg,int asz,ddi_acc_handle_t hdl,uint32_t val)19115254Sgavinm cmi_pci_put_cmn(int bus, int dev, int func, int reg, int asz,
19125254Sgavinm     ddi_acc_handle_t hdl, uint32_t val)
19135254Sgavinm {
19145254Sgavinm 	/*
19155254Sgavinm 	 * If there is an interposed value for this register invalidate it.
19165254Sgavinm 	 */
19175254Sgavinm 	pcii_rment(bus, dev, func, reg, asz);
19185254Sgavinm 
19195254Sgavinm 	if (!(cmi_pcicfg_flags & CMI_PCICFG_FLAG_WR_HWOK))
19205254Sgavinm 		return;
19215254Sgavinm 
19225254Sgavinm 	switch (asz) {
19235254Sgavinm 	case 1:
19245254Sgavinm 		if (hdl)
19255254Sgavinm 			pci_config_put8(hdl, (off_t)reg, (uint8_t)val);
19265254Sgavinm 		else
192711947Ssrihari.venkatesan@oracle.com 			pci_cfgacc_put8(NULL, PCI_GETBDF(bus, dev, func), reg,
192811947Ssrihari.venkatesan@oracle.com 			    (uint8_t)val);
19295254Sgavinm 		break;
19305254Sgavinm 
19315254Sgavinm 	case 2:
19325254Sgavinm 		if (hdl)
19335254Sgavinm 			pci_config_put16(hdl, (off_t)reg, (uint16_t)val);
19345254Sgavinm 		else
193511947Ssrihari.venkatesan@oracle.com 			pci_cfgacc_put16(NULL, PCI_GETBDF(bus, dev, func), reg,
193611947Ssrihari.venkatesan@oracle.com 			    (uint16_t)val);
19375254Sgavinm 		break;
19385254Sgavinm 
19395254Sgavinm 	case 4:
19405254Sgavinm 		if (hdl)
19415254Sgavinm 			pci_config_put32(hdl, (off_t)reg, val);
19425254Sgavinm 		else
194311947Ssrihari.venkatesan@oracle.com 			pci_cfgacc_put32(NULL, PCI_GETBDF(bus, dev, func), reg,
194411947Ssrihari.venkatesan@oracle.com 			    val);
19455254Sgavinm 		break;
19465254Sgavinm 
19475254Sgavinm 	default:
19485254Sgavinm 		break;
19495254Sgavinm 	}
19505254Sgavinm }
19515254Sgavinm 
19527532SSean.Ye@Sun.COM void
cmi_pci_putb(int bus,int dev,int func,int reg,ddi_acc_handle_t hdl,uint8_t val)19535254Sgavinm cmi_pci_putb(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl,
19545254Sgavinm     uint8_t val)
19555254Sgavinm {
19565254Sgavinm 	cmi_pci_put_cmn(bus, dev, func, reg, 1, hdl, val);
19575254Sgavinm }
19585254Sgavinm 
19597532SSean.Ye@Sun.COM void
cmi_pci_putw(int bus,int dev,int func,int reg,ddi_acc_handle_t hdl,uint16_t val)19605254Sgavinm cmi_pci_putw(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl,
19615254Sgavinm     uint16_t val)
19625254Sgavinm {
19635254Sgavinm 	cmi_pci_put_cmn(bus, dev, func, reg, 2, hdl, val);
19645254Sgavinm }
19655254Sgavinm 
19667532SSean.Ye@Sun.COM void
cmi_pci_putl(int bus,int dev,int func,int reg,ddi_acc_handle_t hdl,uint32_t val)19675254Sgavinm cmi_pci_putl(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl,
19685254Sgavinm     uint32_t val)
19695254Sgavinm {
19705254Sgavinm 	cmi_pci_put_cmn(bus, dev, func, reg, 4, hdl, val);
19715254Sgavinm }
19727532SSean.Ye@Sun.COM 
19737532SSean.Ye@Sun.COM static const struct cmi_hdl_ops cmi_hdl_ops = {
19747532SSean.Ye@Sun.COM #ifdef __xpv
19757532SSean.Ye@Sun.COM 	/*
19767532SSean.Ye@Sun.COM 	 * CMI_HDL_SOLARIS_xVM_MCA - ops when we are an xVM dom0
19777532SSean.Ye@Sun.COM 	 */
19787532SSean.Ye@Sun.COM 	xpv_vendor,		/* cmio_vendor */
19797532SSean.Ye@Sun.COM 	xpv_vendorstr,		/* cmio_vendorstr */
19807532SSean.Ye@Sun.COM 	xpv_family,		/* cmio_family */
19817532SSean.Ye@Sun.COM 	xpv_model,		/* cmio_model */
19827532SSean.Ye@Sun.COM 	xpv_stepping,		/* cmio_stepping */
19837532SSean.Ye@Sun.COM 	xpv_chipid,		/* cmio_chipid */
198410947SSrihari.Venkatesan@Sun.COM 	xpv_procnodeid,		/* cmio_procnodeid */
19857532SSean.Ye@Sun.COM 	xpv_coreid,		/* cmio_coreid */
19867532SSean.Ye@Sun.COM 	xpv_strandid,		/* cmio_strandid */
198710947SSrihari.Venkatesan@Sun.COM 	xpv_procnodes_per_pkg,	/* cmio_procnodes_per_pkg */
198810942STom.Pothier@Sun.COM 	xpv_strand_apicid,	/* cmio_strand_apicid */
19897532SSean.Ye@Sun.COM 	xpv_chiprev,		/* cmio_chiprev */
19907532SSean.Ye@Sun.COM 	xpv_chiprevstr,		/* cmio_chiprevstr */
19917532SSean.Ye@Sun.COM 	xpv_getsockettype,	/* cmio_getsockettype */
19929482SKuriakose.Kuruvilla@Sun.COM 	xpv_getsocketstr,	/* cmio_getsocketstr */
19937532SSean.Ye@Sun.COM 	xpv_logical_id,		/* cmio_logical_id */
19947532SSean.Ye@Sun.COM 	NULL,			/* cmio_getcr4 */
19957532SSean.Ye@Sun.COM 	NULL,			/* cmio_setcr4 */
19967532SSean.Ye@Sun.COM 	xpv_rdmsr,		/* cmio_rdmsr */
19977532SSean.Ye@Sun.COM 	xpv_wrmsr,		/* cmio_wrmsr */
19987532SSean.Ye@Sun.COM 	xpv_msrinterpose,	/* cmio_msrinterpose */
19997532SSean.Ye@Sun.COM 	xpv_int,		/* cmio_int */
200010942STom.Pothier@Sun.COM 	xpv_online,		/* cmio_online */
200110942STom.Pothier@Sun.COM 	xpv_smbiosid,		/* cmio_smbiosid */
200210942STom.Pothier@Sun.COM 	xpv_smb_chipid,		/* cmio_smb_chipid */
200310942STom.Pothier@Sun.COM 	xpv_smb_bboard		/* cmio_smb_bboard */
20047532SSean.Ye@Sun.COM 
20057532SSean.Ye@Sun.COM #else	/* __xpv */
20067532SSean.Ye@Sun.COM 
20077532SSean.Ye@Sun.COM 	/*
20087532SSean.Ye@Sun.COM 	 * CMI_HDL_NATIVE - ops when apparently running on bare-metal
20097532SSean.Ye@Sun.COM 	 */
20107532SSean.Ye@Sun.COM 	ntv_vendor,		/* cmio_vendor */
20117532SSean.Ye@Sun.COM 	ntv_vendorstr,		/* cmio_vendorstr */
20127532SSean.Ye@Sun.COM 	ntv_family,		/* cmio_family */
20137532SSean.Ye@Sun.COM 	ntv_model,		/* cmio_model */
20147532SSean.Ye@Sun.COM 	ntv_stepping,		/* cmio_stepping */
20157532SSean.Ye@Sun.COM 	ntv_chipid,		/* cmio_chipid */
201610947SSrihari.Venkatesan@Sun.COM 	ntv_procnodeid,		/* cmio_procnodeid */
20177532SSean.Ye@Sun.COM 	ntv_coreid,		/* cmio_coreid */
20187532SSean.Ye@Sun.COM 	ntv_strandid,		/* cmio_strandid */
201910947SSrihari.Venkatesan@Sun.COM 	ntv_procnodes_per_pkg,	/* cmio_procnodes_per_pkg */
202010947SSrihari.Venkatesan@Sun.COM 	ntv_strand_apicid,	/* cmio_strand_apicid */
20217532SSean.Ye@Sun.COM 	ntv_chiprev,		/* cmio_chiprev */
20227532SSean.Ye@Sun.COM 	ntv_chiprevstr,		/* cmio_chiprevstr */
20237532SSean.Ye@Sun.COM 	ntv_getsockettype,	/* cmio_getsockettype */
20249482SKuriakose.Kuruvilla@Sun.COM 	ntv_getsocketstr,	/* cmio_getsocketstr */
20257532SSean.Ye@Sun.COM 	ntv_logical_id,		/* cmio_logical_id */
20267532SSean.Ye@Sun.COM 	ntv_getcr4,		/* cmio_getcr4 */
20277532SSean.Ye@Sun.COM 	ntv_setcr4,		/* cmio_setcr4 */
20287532SSean.Ye@Sun.COM 	ntv_rdmsr,		/* cmio_rdmsr */
20297532SSean.Ye@Sun.COM 	ntv_wrmsr,		/* cmio_wrmsr */
20307532SSean.Ye@Sun.COM 	ntv_msrinterpose,	/* cmio_msrinterpose */
20317532SSean.Ye@Sun.COM 	ntv_int,		/* cmio_int */
203210942STom.Pothier@Sun.COM 	ntv_online,		/* cmio_online */
203310942STom.Pothier@Sun.COM 	ntv_smbiosid,		/* cmio_smbiosid */
203410942STom.Pothier@Sun.COM 	ntv_smb_chipid,		/* cmio_smb_chipid */
203510942STom.Pothier@Sun.COM 	ntv_smb_bboard		/* cmio_smb_bboard */
20367532SSean.Ye@Sun.COM #endif
20377532SSean.Ye@Sun.COM };
2038