xref: /illumos-gate/usr/src/uts/i86pc/os/cmi_hw.c (revision 2cbc828d66d6088914f685ae0e77169ecc9fc7f9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2019, Joyent, Inc.
25  */
26 /*
27  * Copyright (c) 2010, Intel Corporation.
28  * All rights reserved.
29  */
30 
31 /*
32  * CPU Module Interface - hardware abstraction.
33  */
34 
35 #ifdef __xpv
36 #include <sys/xpv_user.h>
37 #endif
38 
39 #include <sys/types.h>
40 #include <sys/cpu_module.h>
41 #include <sys/kmem.h>
42 #include <sys/x86_archext.h>
43 #include <sys/cpuvar.h>
44 #include <sys/ksynch.h>
45 #include <sys/x_call.h>
46 #include <sys/pghw.h>
47 #include <sys/pci_cfgacc.h>
48 #include <sys/pci_cfgspace.h>
49 #include <sys/archsystm.h>
50 #include <sys/ontrap.h>
51 #include <sys/controlregs.h>
52 #include <sys/sunddi.h>
53 #include <sys/trap.h>
54 #include <sys/mca_x86.h>
55 #include <sys/processor.h>
56 #include <sys/cmn_err.h>
57 #include <sys/nvpair.h>
58 #include <sys/fm/util.h>
59 #include <sys/fm/protocol.h>
60 #include <sys/fm/smb/fmsmb.h>
61 #include <sys/cpu_module_impl.h>
62 
63 /*
64  * Variable which determines if the SMBIOS supports x86 generic topology; or
65  * if legacy topolgy enumeration will occur.
66  */
67 extern int x86gentopo_legacy;
68 
69 /*
70  * Outside of this file consumers use the opaque cmi_hdl_t.  This
71  * definition is duplicated in the generic_cpu mdb module, so keep
72  * them in-sync when making changes.
73  */
74 typedef struct cmi_hdl_impl {
75 	enum cmi_hdl_class cmih_class;		/* Handle nature */
76 	const struct cmi_hdl_ops *cmih_ops;	/* Operations vector */
77 	uint_t cmih_chipid;			/* Chipid of cpu resource */
78 	uint_t cmih_procnodeid;			/* Nodeid of cpu resource */
79 	uint_t cmih_coreid;			/* Core within die */
80 	uint_t cmih_strandid;			/* Thread within core */
81 	uint_t cmih_procnodes_per_pkg;		/* Nodes in a processor */
82 	boolean_t cmih_mstrand;			/* cores are multithreaded */
83 	volatile uint32_t *cmih_refcntp;	/* Reference count pointer */
84 	uint64_t cmih_msrsrc;			/* MSR data source flags */
85 	void *cmih_hdlpriv;			/* cmi_hw.c private data */
86 	void *cmih_spec;			/* cmi_hdl_{set,get}_specific */
87 	void *cmih_cmi;				/* cpu mod control structure */
88 	void *cmih_cmidata;			/* cpu mod private data */
89 	const struct cmi_mc_ops *cmih_mcops;	/* Memory-controller ops */
90 	void *cmih_mcdata;			/* Memory-controller data */
91 	uint64_t cmih_flags;			/* See CMIH_F_* below */
92 	uint16_t cmih_smbiosid;			/* SMBIOS Type 4 struct ID */
93 	uint_t cmih_smb_chipid;			/* SMBIOS factored chipid */
94 	nvlist_t *cmih_smb_bboard;		/* SMBIOS bboard nvlist */
95 } cmi_hdl_impl_t;
96 
97 #define	IMPLHDL(ophdl)	((cmi_hdl_impl_t *)ophdl)
98 #define	HDLOPS(hdl)	((hdl)->cmih_ops)
99 
100 #define	CMIH_F_INJACTV		0x1ULL
101 #define	CMIH_F_DEAD		0x2ULL
102 
103 /*
104  * Ops structure for handle operations.
105  */
106 struct cmi_hdl_ops {
107 	/*
108 	 * These ops are required in an implementation.
109 	 */
110 	uint_t (*cmio_vendor)(cmi_hdl_impl_t *);
111 	const char *(*cmio_vendorstr)(cmi_hdl_impl_t *);
112 	uint_t (*cmio_family)(cmi_hdl_impl_t *);
113 	uint_t (*cmio_model)(cmi_hdl_impl_t *);
114 	uint_t (*cmio_stepping)(cmi_hdl_impl_t *);
115 	uint_t (*cmio_chipid)(cmi_hdl_impl_t *);
116 	uint_t (*cmio_procnodeid)(cmi_hdl_impl_t *);
117 	uint_t (*cmio_coreid)(cmi_hdl_impl_t *);
118 	uint_t (*cmio_strandid)(cmi_hdl_impl_t *);
119 	uint_t (*cmio_procnodes_per_pkg)(cmi_hdl_impl_t *);
120 	uint_t (*cmio_strand_apicid)(cmi_hdl_impl_t *);
121 	uint32_t (*cmio_chiprev)(cmi_hdl_impl_t *);
122 	const char *(*cmio_chiprevstr)(cmi_hdl_impl_t *);
123 	uint32_t (*cmio_getsockettype)(cmi_hdl_impl_t *);
124 	const char *(*cmio_getsocketstr)(cmi_hdl_impl_t *);
125 	uint_t (*cmio_chipsig)(cmi_hdl_impl_t *);
126 
127 	id_t (*cmio_logical_id)(cmi_hdl_impl_t *);
128 	/*
129 	 * These ops are optional in an implementation.
130 	 */
131 	ulong_t (*cmio_getcr4)(cmi_hdl_impl_t *);
132 	void (*cmio_setcr4)(cmi_hdl_impl_t *, ulong_t);
133 	cmi_errno_t (*cmio_rdmsr)(cmi_hdl_impl_t *, uint_t, uint64_t *);
134 	cmi_errno_t (*cmio_wrmsr)(cmi_hdl_impl_t *, uint_t, uint64_t);
135 	cmi_errno_t (*cmio_msrinterpose)(cmi_hdl_impl_t *, uint_t, uint64_t);
136 	void (*cmio_int)(cmi_hdl_impl_t *, int);
137 	int (*cmio_online)(cmi_hdl_impl_t *, int, int *);
138 	uint16_t (*cmio_smbiosid) (cmi_hdl_impl_t *);
139 	uint_t (*cmio_smb_chipid)(cmi_hdl_impl_t *);
140 	nvlist_t *(*cmio_smb_bboard)(cmi_hdl_impl_t *);
141 };
142 
143 static const struct cmi_hdl_ops cmi_hdl_ops;
144 
145 /*
146  * Handles are looked up from contexts such as polling, injection etc
147  * where the context is reasonably well defined (although a poller could
148  * interrupt any old thread holding any old lock).  They are also looked
149  * up by machine check handlers, which may strike at inconvenient times
150  * such as during handle initialization or destruction or during handle
151  * lookup (which the #MC handler itself will also have to perform).
152  *
153  * So keeping handles in a linked list makes locking difficult when we
154  * consider #MC handlers.  Our solution is to have a look-up table indexed
155  * by that which uniquely identifies a handle - chip/core/strand id -
156  * with each entry a structure including a pointer to a handle
157  * structure for the resource, and a reference count for the handle.
158  * Reference counts are modified atomically.  The public cmi_hdl_hold
159  * always succeeds because this can only be used after handle creation
160  * and before the call to destruct, so the hold count is already at least one.
161  * In other functions that lookup a handle (cmi_hdl_lookup, cmi_hdl_any)
162  * we must be certain that the count has not already decrmented to zero
163  * before applying our hold.
164  *
165  * The table is an array of maximum number of chips defined in
166  * CMI_CHIPID_ARR_SZ indexed by the chip id. If the chip is not present, the
167  * entry is NULL. Each entry is a pointer to another array which contains a
168  * list of all strands of the chip. This first level table is allocated when
169  * first we want to populate an entry. The size of the latter (per chip) table
170  * is CMI_MAX_STRANDS_PER_CHIP and it is populated when one of its cpus starts.
171  *
172  * Ideally we should only allocate to the actual number of chips, cores per
173  * chip and strand per core. The number of chips is not available until all
174  * of them are passed. The number of cores and strands are partially available.
175  * For now we stick with the above approach.
176  */
177 #define	CMI_MAX_CHIPID_NBITS		6	/* max chipid of 63 */
178 #define	CMI_MAX_CORES_PER_CHIP_NBITS	4	/* 16 cores per chip max */
179 #define	CMI_MAX_STRANDS_PER_CORE_NBITS	3	/* 8 strands per core max */
180 
181 #define	CMI_MAX_CHIPID			((1 << (CMI_MAX_CHIPID_NBITS)) - 1)
182 #define	CMI_MAX_CORES_PER_CHIP(cbits)	(1 << (cbits))
183 #define	CMI_MAX_COREID(cbits)		((1 << (cbits)) - 1)
184 #define	CMI_MAX_STRANDS_PER_CORE(sbits)	(1 << (sbits))
185 #define	CMI_MAX_STRANDID(sbits)		((1 << (sbits)) - 1)
186 #define	CMI_MAX_STRANDS_PER_CHIP(cbits, sbits)	\
187 	(CMI_MAX_CORES_PER_CHIP(cbits) * CMI_MAX_STRANDS_PER_CORE(sbits))
188 
189 #define	CMI_CHIPID_ARR_SZ		(1 << CMI_MAX_CHIPID_NBITS)
190 
191 typedef struct cmi_hdl_ent {
192 	volatile uint32_t cmae_refcnt;
193 	cmi_hdl_impl_t *cmae_hdlp;
194 } cmi_hdl_ent_t;
195 
196 static cmi_hdl_ent_t *cmi_chip_tab[CMI_CHIPID_ARR_SZ];
197 
198 /*
199  * Default values for the number of core and strand bits.
200  */
201 uint_t cmi_core_nbits = CMI_MAX_CORES_PER_CHIP_NBITS;
202 uint_t cmi_strand_nbits = CMI_MAX_STRANDS_PER_CORE_NBITS;
203 static int cmi_ext_topo_check = 0;
204 
205 /*
206  * Controls where we will source PCI config space data.
207  */
208 #define	CMI_PCICFG_FLAG_RD_HWOK		0x0001
209 #define	CMI_PCICFG_FLAG_RD_INTERPOSEOK	0X0002
210 #define	CMI_PCICFG_FLAG_WR_HWOK		0x0004
211 #define	CMI_PCICFG_FLAG_WR_INTERPOSEOK	0X0008
212 
213 static uint64_t cmi_pcicfg_flags =
214     CMI_PCICFG_FLAG_RD_HWOK | CMI_PCICFG_FLAG_RD_INTERPOSEOK |
215     CMI_PCICFG_FLAG_WR_HWOK | CMI_PCICFG_FLAG_WR_INTERPOSEOK;
216 
217 /*
218  * The flags for individual cpus are kept in their per-cpu handle cmih_msrsrc
219  */
220 #define	CMI_MSR_FLAG_RD_HWOK		0x0001
221 #define	CMI_MSR_FLAG_RD_INTERPOSEOK	0x0002
222 #define	CMI_MSR_FLAG_WR_HWOK		0x0004
223 #define	CMI_MSR_FLAG_WR_INTERPOSEOK	0x0008
224 
225 int cmi_call_func_ntv_tries = 3;
226 
227 static cmi_errno_t
228 call_func_ntv(int cpuid, xc_func_t func, xc_arg_t arg1, xc_arg_t arg2)
229 {
230 	cmi_errno_t rc = -1;
231 	int i;
232 
233 	kpreempt_disable();
234 
235 	if (CPU->cpu_id == cpuid) {
236 		(*func)(arg1, arg2, (xc_arg_t)&rc);
237 	} else {
238 		/*
239 		 * This should not happen for a #MC trap or a poll, so
240 		 * this is likely an error injection or similar.
241 		 * We will try to cross call with xc_trycall - we
242 		 * can't guarantee success with xc_call because
243 		 * the interrupt code in the case of a #MC may
244 		 * already hold the xc mutex.
245 		 */
246 		for (i = 0; i < cmi_call_func_ntv_tries; i++) {
247 			cpuset_t cpus;
248 
249 			CPUSET_ONLY(cpus, cpuid);
250 			xc_priority(arg1, arg2, (xc_arg_t)&rc,
251 			    CPUSET2BV(cpus), func);
252 			if (rc != -1)
253 				break;
254 
255 			DELAY(1);
256 		}
257 	}
258 
259 	kpreempt_enable();
260 
261 	return (rc != -1 ? rc : CMIERR_DEADLOCK);
262 }
263 
264 static uint64_t injcnt;
265 
266 void
267 cmi_hdl_inj_begin(cmi_hdl_t ophdl)
268 {
269 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
270 
271 	if (hdl != NULL)
272 		hdl->cmih_flags |= CMIH_F_INJACTV;
273 	if (injcnt++ == 0) {
274 		cmn_err(CE_NOTE, "Hardware error injection/simulation "
275 		    "activity noted");
276 	}
277 }
278 
279 void
280 cmi_hdl_inj_end(cmi_hdl_t ophdl)
281 {
282 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
283 
284 	ASSERT(hdl == NULL || hdl->cmih_flags & CMIH_F_INJACTV);
285 	if (hdl != NULL)
286 		hdl->cmih_flags &= ~CMIH_F_INJACTV;
287 }
288 
289 boolean_t
290 cmi_inj_tainted(void)
291 {
292 	return (injcnt != 0 ? B_TRUE : B_FALSE);
293 }
294 
295 /*
296  *	 =======================================================
297  *	|	MSR Interposition				|
298  *	|	-----------------				|
299  *	|							|
300  *	 -------------------------------------------------------
301  */
302 
303 #define	CMI_MSRI_HASHSZ		16
304 #define	CMI_MSRI_HASHIDX(hdl, msr) \
305 	(((uintptr_t)(hdl) >> 3 + (msr)) % (CMI_MSRI_HASHSZ - 1))
306 
307 struct cmi_msri_bkt {
308 	kmutex_t msrib_lock;
309 	struct cmi_msri_hashent *msrib_head;
310 };
311 
312 struct cmi_msri_hashent {
313 	struct cmi_msri_hashent *msrie_next;
314 	struct cmi_msri_hashent *msrie_prev;
315 	cmi_hdl_impl_t *msrie_hdl;
316 	uint_t msrie_msrnum;
317 	uint64_t msrie_msrval;
318 };
319 
320 #define	CMI_MSRI_MATCH(ent, hdl, req_msr) \
321 	((ent)->msrie_hdl == (hdl) && (ent)->msrie_msrnum == (req_msr))
322 
323 static struct cmi_msri_bkt msrihash[CMI_MSRI_HASHSZ];
324 
325 static void
326 msri_addent(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
327 {
328 	int idx = CMI_MSRI_HASHIDX(hdl, msr);
329 	struct cmi_msri_bkt *hbp = &msrihash[idx];
330 	struct cmi_msri_hashent *hep;
331 
332 	mutex_enter(&hbp->msrib_lock);
333 
334 	for (hep = hbp->msrib_head; hep != NULL; hep = hep->msrie_next) {
335 		if (CMI_MSRI_MATCH(hep, hdl, msr))
336 			break;
337 	}
338 
339 	if (hep != NULL) {
340 		hep->msrie_msrval = val;
341 	} else {
342 		hep = kmem_alloc(sizeof (*hep), KM_SLEEP);
343 		hep->msrie_hdl = hdl;
344 		hep->msrie_msrnum = msr;
345 		hep->msrie_msrval = val;
346 
347 		if (hbp->msrib_head != NULL)
348 			hbp->msrib_head->msrie_prev = hep;
349 		hep->msrie_next = hbp->msrib_head;
350 		hep->msrie_prev = NULL;
351 		hbp->msrib_head = hep;
352 	}
353 
354 	mutex_exit(&hbp->msrib_lock);
355 }
356 
357 /*
358  * Look for a match for the given hanlde and msr.  Return 1 with valp
359  * filled if a match is found, otherwise return 0 with valp untouched.
360  */
361 static int
362 msri_lookup(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t *valp)
363 {
364 	int idx = CMI_MSRI_HASHIDX(hdl, msr);
365 	struct cmi_msri_bkt *hbp = &msrihash[idx];
366 	struct cmi_msri_hashent *hep;
367 
368 	/*
369 	 * This function is called during #MC trap handling, so we should
370 	 * consider the possibility that the hash mutex is held by the
371 	 * interrupted thread.  This should not happen because interposition
372 	 * is an artificial injection mechanism and the #MC is requested
373 	 * after adding entries, but just in case of a real #MC at an
374 	 * unlucky moment we'll use mutex_tryenter here.
375 	 */
376 	if (!mutex_tryenter(&hbp->msrib_lock))
377 		return (0);
378 
379 	for (hep = hbp->msrib_head; hep != NULL; hep = hep->msrie_next) {
380 		if (CMI_MSRI_MATCH(hep, hdl, msr)) {
381 			*valp = hep->msrie_msrval;
382 			break;
383 		}
384 	}
385 
386 	mutex_exit(&hbp->msrib_lock);
387 
388 	return (hep != NULL);
389 }
390 
391 /*
392  * Remove any interposed value that matches.
393  */
394 static void
395 msri_rment(cmi_hdl_impl_t *hdl, uint_t msr)
396 {
397 
398 	int idx = CMI_MSRI_HASHIDX(hdl, msr);
399 	struct cmi_msri_bkt *hbp = &msrihash[idx];
400 	struct cmi_msri_hashent *hep;
401 
402 	if (!mutex_tryenter(&hbp->msrib_lock))
403 		return;
404 
405 	for (hep = hbp->msrib_head; hep != NULL; hep = hep->msrie_next) {
406 		if (CMI_MSRI_MATCH(hep, hdl, msr)) {
407 			if (hep->msrie_prev != NULL)
408 				hep->msrie_prev->msrie_next = hep->msrie_next;
409 
410 			if (hep->msrie_next != NULL)
411 				hep->msrie_next->msrie_prev = hep->msrie_prev;
412 
413 			if (hbp->msrib_head == hep)
414 				hbp->msrib_head = hep->msrie_next;
415 
416 			kmem_free(hep, sizeof (*hep));
417 			break;
418 		}
419 	}
420 
421 	mutex_exit(&hbp->msrib_lock);
422 }
423 
424 /*
425  *	 =======================================================
426  *	|	PCI Config Space Interposition			|
427  *	|	------------------------------			|
428  *	|							|
429  *	 -------------------------------------------------------
430  */
431 
432 /*
433  * Hash for interposed PCI config space values.  We lookup on bus/dev/fun/offset
434  * and then record whether the value stashed was made with a byte, word or
435  * doubleword access;  we will only return a hit for an access of the
436  * same size.  If you access say a 32-bit register using byte accesses
437  * and then attempt to read the full 32-bit value back you will not obtain
438  * any sort of merged result - you get a lookup miss.
439  */
440 
441 #define	CMI_PCII_HASHSZ		16
442 #define	CMI_PCII_HASHIDX(b, d, f, o) \
443 	(((b) + (d) + (f) + (o)) % (CMI_PCII_HASHSZ - 1))
444 
445 struct cmi_pcii_bkt {
446 	kmutex_t pciib_lock;
447 	struct cmi_pcii_hashent *pciib_head;
448 };
449 
450 struct cmi_pcii_hashent {
451 	struct cmi_pcii_hashent *pcii_next;
452 	struct cmi_pcii_hashent *pcii_prev;
453 	int pcii_bus;
454 	int pcii_dev;
455 	int pcii_func;
456 	int pcii_reg;
457 	int pcii_asize;
458 	uint32_t pcii_val;
459 };
460 
461 #define	CMI_PCII_MATCH(ent, b, d, f, r, asz) \
462 	((ent)->pcii_bus == (b) && (ent)->pcii_dev == (d) && \
463 	(ent)->pcii_func == (f) && (ent)->pcii_reg == (r) && \
464 	(ent)->pcii_asize == (asz))
465 
466 static struct cmi_pcii_bkt pciihash[CMI_PCII_HASHSZ];
467 
468 
469 /*
470  * Add a new entry to the PCI interpose hash, overwriting any existing
471  * entry that is found.
472  */
473 static void
474 pcii_addent(int bus, int dev, int func, int reg, uint32_t val, int asz)
475 {
476 	int idx = CMI_PCII_HASHIDX(bus, dev, func, reg);
477 	struct cmi_pcii_bkt *hbp = &pciihash[idx];
478 	struct cmi_pcii_hashent *hep;
479 
480 	cmi_hdl_inj_begin(NULL);
481 
482 	mutex_enter(&hbp->pciib_lock);
483 
484 	for (hep = hbp->pciib_head; hep != NULL; hep = hep->pcii_next) {
485 		if (CMI_PCII_MATCH(hep, bus, dev, func, reg, asz))
486 			break;
487 	}
488 
489 	if (hep != NULL) {
490 		hep->pcii_val = val;
491 	} else {
492 		hep = kmem_alloc(sizeof (*hep), KM_SLEEP);
493 		hep->pcii_bus = bus;
494 		hep->pcii_dev = dev;
495 		hep->pcii_func = func;
496 		hep->pcii_reg = reg;
497 		hep->pcii_asize = asz;
498 		hep->pcii_val = val;
499 
500 		if (hbp->pciib_head != NULL)
501 			hbp->pciib_head->pcii_prev = hep;
502 		hep->pcii_next = hbp->pciib_head;
503 		hep->pcii_prev = NULL;
504 		hbp->pciib_head = hep;
505 	}
506 
507 	mutex_exit(&hbp->pciib_lock);
508 
509 	cmi_hdl_inj_end(NULL);
510 }
511 
512 /*
513  * Look for a match for the given bus/dev/func/reg; return 1 with valp
514  * filled if a match is found, otherwise return 0 with valp untouched.
515  */
516 static int
517 pcii_lookup(int bus, int dev, int func, int reg, int asz, uint32_t *valp)
518 {
519 	int idx = CMI_PCII_HASHIDX(bus, dev, func, reg);
520 	struct cmi_pcii_bkt *hbp = &pciihash[idx];
521 	struct cmi_pcii_hashent *hep;
522 
523 	if (!mutex_tryenter(&hbp->pciib_lock))
524 		return (0);
525 
526 	for (hep = hbp->pciib_head; hep != NULL; hep = hep->pcii_next) {
527 		if (CMI_PCII_MATCH(hep, bus, dev, func, reg, asz)) {
528 			*valp = hep->pcii_val;
529 			break;
530 		}
531 	}
532 
533 	mutex_exit(&hbp->pciib_lock);
534 
535 	return (hep != NULL);
536 }
537 
538 static void
539 pcii_rment(int bus, int dev, int func, int reg, int asz)
540 {
541 	int idx = CMI_PCII_HASHIDX(bus, dev, func, reg);
542 	struct cmi_pcii_bkt *hbp = &pciihash[idx];
543 	struct cmi_pcii_hashent *hep;
544 
545 	mutex_enter(&hbp->pciib_lock);
546 
547 	for (hep = hbp->pciib_head; hep != NULL; hep = hep->pcii_next) {
548 		if (CMI_PCII_MATCH(hep, bus, dev, func, reg, asz)) {
549 			if (hep->pcii_prev != NULL)
550 				hep->pcii_prev->pcii_next = hep->pcii_next;
551 
552 			if (hep->pcii_next != NULL)
553 				hep->pcii_next->pcii_prev = hep->pcii_prev;
554 
555 			if (hbp->pciib_head == hep)
556 				hbp->pciib_head = hep->pcii_next;
557 
558 			kmem_free(hep, sizeof (*hep));
559 			break;
560 		}
561 	}
562 
563 	mutex_exit(&hbp->pciib_lock);
564 }
565 
566 #ifndef __xpv
567 
568 /*
569  *	 =======================================================
570  *	|	Native methods					|
571  *	|	--------------					|
572  *	|							|
573  *	| These are used when we are running native on bare-	|
574  *	| metal, or simply don't know any better.		|
575  *	---------------------------------------------------------
576  */
577 
578 #define	HDLPRIV(hdl)	((cpu_t *)(hdl)->cmih_hdlpriv)
579 
580 static uint_t
581 ntv_vendor(cmi_hdl_impl_t *hdl)
582 {
583 	return (cpuid_getvendor(HDLPRIV(hdl)));
584 }
585 
586 static const char *
587 ntv_vendorstr(cmi_hdl_impl_t *hdl)
588 {
589 	return (cpuid_getvendorstr(HDLPRIV(hdl)));
590 }
591 
592 static uint_t
593 ntv_family(cmi_hdl_impl_t *hdl)
594 {
595 	return (cpuid_getfamily(HDLPRIV(hdl)));
596 }
597 
598 static uint_t
599 ntv_model(cmi_hdl_impl_t *hdl)
600 {
601 	return (cpuid_getmodel(HDLPRIV(hdl)));
602 }
603 
604 static uint_t
605 ntv_stepping(cmi_hdl_impl_t *hdl)
606 {
607 	return (cpuid_getstep(HDLPRIV(hdl)));
608 }
609 
610 static uint_t
611 ntv_chipid(cmi_hdl_impl_t *hdl)
612 {
613 	return (hdl->cmih_chipid);
614 
615 }
616 
617 static uint_t
618 ntv_procnodeid(cmi_hdl_impl_t *hdl)
619 {
620 	return (hdl->cmih_procnodeid);
621 }
622 
623 static uint_t
624 ntv_procnodes_per_pkg(cmi_hdl_impl_t *hdl)
625 {
626 	return (hdl->cmih_procnodes_per_pkg);
627 }
628 
629 static uint_t
630 ntv_coreid(cmi_hdl_impl_t *hdl)
631 {
632 	return (hdl->cmih_coreid);
633 }
634 
635 static uint_t
636 ntv_strandid(cmi_hdl_impl_t *hdl)
637 {
638 	return (hdl->cmih_strandid);
639 }
640 
641 static uint_t
642 ntv_strand_apicid(cmi_hdl_impl_t *hdl)
643 {
644 	return (cpuid_get_apicid(HDLPRIV(hdl)));
645 }
646 
647 static uint16_t
648 ntv_smbiosid(cmi_hdl_impl_t *hdl)
649 {
650 	return (hdl->cmih_smbiosid);
651 }
652 
653 static uint_t
654 ntv_smb_chipid(cmi_hdl_impl_t *hdl)
655 {
656 	return (hdl->cmih_smb_chipid);
657 }
658 
659 static nvlist_t *
660 ntv_smb_bboard(cmi_hdl_impl_t *hdl)
661 {
662 	return (hdl->cmih_smb_bboard);
663 }
664 
665 static uint32_t
666 ntv_chiprev(cmi_hdl_impl_t *hdl)
667 {
668 	return (cpuid_getchiprev(HDLPRIV(hdl)));
669 }
670 
671 static const char *
672 ntv_chiprevstr(cmi_hdl_impl_t *hdl)
673 {
674 	return (cpuid_getchiprevstr(HDLPRIV(hdl)));
675 }
676 
677 static uint32_t
678 ntv_getsockettype(cmi_hdl_impl_t *hdl)
679 {
680 	return (cpuid_getsockettype(HDLPRIV(hdl)));
681 }
682 
683 static const char *
684 ntv_getsocketstr(cmi_hdl_impl_t *hdl)
685 {
686 	return (cpuid_getsocketstr(HDLPRIV(hdl)));
687 }
688 
689 static uint_t
690 ntv_chipsig(cmi_hdl_impl_t *hdl)
691 {
692 	return (cpuid_getsig(HDLPRIV(hdl)));
693 }
694 
695 static id_t
696 ntv_logical_id(cmi_hdl_impl_t *hdl)
697 {
698 	return (HDLPRIV(hdl)->cpu_id);
699 }
700 
701 /*ARGSUSED*/
702 static int
703 ntv_getcr4_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
704 {
705 	ulong_t *dest = (ulong_t *)arg1;
706 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
707 
708 	*dest = getcr4();
709 	*rcp = CMI_SUCCESS;
710 
711 	return (0);
712 }
713 
714 static ulong_t
715 ntv_getcr4(cmi_hdl_impl_t *hdl)
716 {
717 	cpu_t *cp = HDLPRIV(hdl);
718 	ulong_t val;
719 
720 	(void) call_func_ntv(cp->cpu_id, ntv_getcr4_xc, (xc_arg_t)&val, 0);
721 
722 	return (val);
723 }
724 
725 /*ARGSUSED*/
726 static int
727 ntv_setcr4_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
728 {
729 	ulong_t val = (ulong_t)arg1;
730 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
731 
732 	setcr4(val);
733 	*rcp = CMI_SUCCESS;
734 
735 	return (0);
736 }
737 
738 static void
739 ntv_setcr4(cmi_hdl_impl_t *hdl, ulong_t val)
740 {
741 	cpu_t *cp = HDLPRIV(hdl);
742 
743 	(void) call_func_ntv(cp->cpu_id, ntv_setcr4_xc, (xc_arg_t)val, 0);
744 }
745 
746 volatile uint32_t cmi_trapped_rdmsr;
747 
748 /*ARGSUSED*/
749 static int
750 ntv_rdmsr_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
751 {
752 	uint_t msr = (uint_t)arg1;
753 	uint64_t *valp = (uint64_t *)arg2;
754 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
755 
756 	on_trap_data_t otd;
757 
758 	if (on_trap(&otd, OT_DATA_ACCESS) == 0) {
759 		if (checked_rdmsr(msr, valp) == 0)
760 			*rcp = CMI_SUCCESS;
761 		else
762 			*rcp = CMIERR_NOTSUP;
763 	} else {
764 		*rcp = CMIERR_MSRGPF;
765 		atomic_inc_32(&cmi_trapped_rdmsr);
766 	}
767 	no_trap();
768 
769 	return (0);
770 }
771 
772 static cmi_errno_t
773 ntv_rdmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t *valp)
774 {
775 	cpu_t *cp = HDLPRIV(hdl);
776 
777 	if (!(hdl->cmih_msrsrc & CMI_MSR_FLAG_RD_HWOK))
778 		return (CMIERR_INTERPOSE);
779 
780 	return (call_func_ntv(cp->cpu_id, ntv_rdmsr_xc,
781 	    (xc_arg_t)msr, (xc_arg_t)valp));
782 }
783 
784 volatile uint32_t cmi_trapped_wrmsr;
785 
786 /*ARGSUSED*/
787 static int
788 ntv_wrmsr_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
789 {
790 	uint_t msr = (uint_t)arg1;
791 	uint64_t val = *((uint64_t *)arg2);
792 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
793 	on_trap_data_t otd;
794 
795 	if (on_trap(&otd, OT_DATA_ACCESS) == 0) {
796 		if (checked_wrmsr(msr, val) == 0)
797 			*rcp = CMI_SUCCESS;
798 		else
799 			*rcp = CMIERR_NOTSUP;
800 	} else {
801 		*rcp = CMIERR_MSRGPF;
802 		atomic_inc_32(&cmi_trapped_wrmsr);
803 	}
804 	no_trap();
805 
806 	return (0);
807 
808 }
809 
810 static cmi_errno_t
811 ntv_wrmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
812 {
813 	cpu_t *cp = HDLPRIV(hdl);
814 
815 	if (!(hdl->cmih_msrsrc & CMI_MSR_FLAG_WR_HWOK))
816 		return (CMI_SUCCESS);
817 
818 	return (call_func_ntv(cp->cpu_id, ntv_wrmsr_xc,
819 	    (xc_arg_t)msr, (xc_arg_t)&val));
820 }
821 
822 static cmi_errno_t
823 ntv_msrinterpose(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
824 {
825 	msri_addent(hdl, msr, val);
826 	return (CMI_SUCCESS);
827 }
828 
829 /*ARGSUSED*/
830 static int
831 ntv_int_xc(xc_arg_t arg1, xc_arg_t arg2, xc_arg_t arg3)
832 {
833 	cmi_errno_t *rcp = (cmi_errno_t *)arg3;
834 	int int_no = (int)arg1;
835 
836 	if (int_no == T_MCE)
837 		int18();
838 	else
839 		int_cmci();
840 	*rcp = CMI_SUCCESS;
841 
842 	return (0);
843 }
844 
845 static void
846 ntv_int(cmi_hdl_impl_t *hdl, int int_no)
847 {
848 	cpu_t *cp = HDLPRIV(hdl);
849 
850 	(void) call_func_ntv(cp->cpu_id, ntv_int_xc, (xc_arg_t)int_no, 0);
851 }
852 
853 static int
854 ntv_online(cmi_hdl_impl_t *hdl, int new_status, int *old_status)
855 {
856 	int rc;
857 	processorid_t cpuid = HDLPRIV(hdl)->cpu_id;
858 
859 	while (mutex_tryenter(&cpu_lock) == 0) {
860 		if (hdl->cmih_flags & CMIH_F_DEAD)
861 			return (EBUSY);
862 		delay(1);
863 	}
864 	rc = p_online_internal_locked(cpuid, new_status, old_status);
865 	mutex_exit(&cpu_lock);
866 
867 	return (rc);
868 }
869 
870 #else	/* __xpv */
871 
872 /*
873  *	 =======================================================
874  *	|	xVM dom0 methods				|
875  *	|	----------------				|
876  *	|							|
877  *	| These are used when we are running as dom0 in		|
878  *	| a Solaris xVM context.				|
879  *	---------------------------------------------------------
880  */
881 
882 #define	HDLPRIV(hdl)	((xen_mc_lcpu_cookie_t)(hdl)->cmih_hdlpriv)
883 
884 extern uint_t _cpuid_vendorstr_to_vendorcode(char *);
885 
886 
887 static uint_t
888 xpv_vendor(cmi_hdl_impl_t *hdl)
889 {
890 	return (_cpuid_vendorstr_to_vendorcode((char *)xen_physcpu_vendorstr(
891 	    HDLPRIV(hdl))));
892 }
893 
894 static const char *
895 xpv_vendorstr(cmi_hdl_impl_t *hdl)
896 {
897 	return (xen_physcpu_vendorstr(HDLPRIV(hdl)));
898 }
899 
900 static uint_t
901 xpv_family(cmi_hdl_impl_t *hdl)
902 {
903 	return (xen_physcpu_family(HDLPRIV(hdl)));
904 }
905 
906 static uint_t
907 xpv_model(cmi_hdl_impl_t *hdl)
908 {
909 	return (xen_physcpu_model(HDLPRIV(hdl)));
910 }
911 
912 static uint_t
913 xpv_stepping(cmi_hdl_impl_t *hdl)
914 {
915 	return (xen_physcpu_stepping(HDLPRIV(hdl)));
916 }
917 
918 static uint_t
919 xpv_chipid(cmi_hdl_impl_t *hdl)
920 {
921 	return (hdl->cmih_chipid);
922 }
923 
924 static uint_t
925 xpv_procnodeid(cmi_hdl_impl_t *hdl)
926 {
927 	return (hdl->cmih_procnodeid);
928 }
929 
930 static uint_t
931 xpv_procnodes_per_pkg(cmi_hdl_impl_t *hdl)
932 {
933 	return (hdl->cmih_procnodes_per_pkg);
934 }
935 
936 static uint_t
937 xpv_coreid(cmi_hdl_impl_t *hdl)
938 {
939 	return (hdl->cmih_coreid);
940 }
941 
942 static uint_t
943 xpv_strandid(cmi_hdl_impl_t *hdl)
944 {
945 	return (hdl->cmih_strandid);
946 }
947 
948 static uint_t
949 xpv_strand_apicid(cmi_hdl_impl_t *hdl)
950 {
951 	return (xen_physcpu_initial_apicid(HDLPRIV(hdl)));
952 }
953 
954 static uint16_t
955 xpv_smbiosid(cmi_hdl_impl_t *hdl)
956 {
957 	return (hdl->cmih_smbiosid);
958 }
959 
960 static uint_t
961 xpv_smb_chipid(cmi_hdl_impl_t *hdl)
962 {
963 	return (hdl->cmih_smb_chipid);
964 }
965 
966 static nvlist_t *
967 xpv_smb_bboard(cmi_hdl_impl_t *hdl)
968 {
969 	return (hdl->cmih_smb_bboard);
970 }
971 
972 extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t);
973 
974 static uint32_t
975 xpv_chiprev(cmi_hdl_impl_t *hdl)
976 {
977 	return (_cpuid_chiprev(xpv_vendor(hdl), xpv_family(hdl),
978 	    xpv_model(hdl), xpv_stepping(hdl)));
979 }
980 
981 extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t);
982 
983 static const char *
984 xpv_chiprevstr(cmi_hdl_impl_t *hdl)
985 {
986 	return (_cpuid_chiprevstr(xpv_vendor(hdl), xpv_family(hdl),
987 	    xpv_model(hdl), xpv_stepping(hdl)));
988 }
989 
990 extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t);
991 
992 static uint32_t
993 xpv_getsockettype(cmi_hdl_impl_t *hdl)
994 {
995 	return (_cpuid_skt(xpv_vendor(hdl), xpv_family(hdl),
996 	    xpv_model(hdl), xpv_stepping(hdl)));
997 }
998 
999 extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t);
1000 
1001 static const char *
1002 xpv_getsocketstr(cmi_hdl_impl_t *hdl)
1003 {
1004 	return (_cpuid_sktstr(xpv_vendor(hdl), xpv_family(hdl),
1005 	    xpv_model(hdl), xpv_stepping(hdl)));
1006 }
1007 
1008 /* ARGSUSED */
1009 static uint_t
1010 xpv_chipsig(cmi_hdl_impl_t *hdl)
1011 {
1012 	return (0);
1013 }
1014 
1015 static id_t
1016 xpv_logical_id(cmi_hdl_impl_t *hdl)
1017 {
1018 	return (xen_physcpu_logical_id(HDLPRIV(hdl)));
1019 }
1020 
1021 static cmi_errno_t
1022 xpv_rdmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t *valp)
1023 {
1024 	switch (msr) {
1025 	case IA32_MSR_MCG_CAP:
1026 		*valp = xen_physcpu_mcg_cap(HDLPRIV(hdl));
1027 		break;
1028 
1029 	default:
1030 		return (CMIERR_NOTSUP);
1031 	}
1032 
1033 	return (CMI_SUCCESS);
1034 }
1035 
1036 /*
1037  * Request the hypervisor to write an MSR for us.  The hypervisor
1038  * will only accept MCA-related MSRs, as this is for MCA error
1039  * simulation purposes alone.  We will pre-screen MSRs for injection
1040  * so we don't bother the HV with bogus requests.  We will permit
1041  * injection to any MCA bank register, and to MCG_STATUS.
1042  */
1043 
1044 #define	IS_MCA_INJ_MSR(msr) \
1045 	(((msr) >= IA32_MSR_MC(0, CTL) && (msr) <= IA32_MSR_MC(10, MISC)) || \
1046 	(msr) == IA32_MSR_MCG_STATUS)
1047 
1048 static cmi_errno_t
1049 xpv_wrmsr_cmn(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val, boolean_t intpose)
1050 {
1051 	xen_mc_t xmc;
1052 	struct xen_mc_msrinject *mci = &xmc.u.mc_msrinject;
1053 
1054 	if (!(hdl->cmih_flags & CMIH_F_INJACTV))
1055 		return (CMIERR_NOTSUP);		/* for injection use only! */
1056 
1057 	if (!IS_MCA_INJ_MSR(msr))
1058 		return (CMIERR_API);
1059 
1060 	if (panicstr)
1061 		return (CMIERR_DEADLOCK);
1062 
1063 	mci->mcinj_cpunr = xen_physcpu_logical_id(HDLPRIV(hdl));
1064 	mci->mcinj_flags = intpose ? MC_MSRINJ_F_INTERPOSE : 0;
1065 	mci->mcinj_count = 1;	/* learn to batch sometime */
1066 	mci->mcinj_msr[0].reg = msr;
1067 	mci->mcinj_msr[0].value = val;
1068 
1069 	return (HYPERVISOR_mca(XEN_MC_msrinject, &xmc) ==
1070 	    0 ?  CMI_SUCCESS : CMIERR_NOTSUP);
1071 }
1072 
1073 static cmi_errno_t
1074 xpv_wrmsr(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
1075 {
1076 	return (xpv_wrmsr_cmn(hdl, msr, val, B_FALSE));
1077 }
1078 
1079 
1080 static cmi_errno_t
1081 xpv_msrinterpose(cmi_hdl_impl_t *hdl, uint_t msr, uint64_t val)
1082 {
1083 	return (xpv_wrmsr_cmn(hdl, msr, val, B_TRUE));
1084 }
1085 
1086 static void
1087 xpv_int(cmi_hdl_impl_t *hdl, int int_no)
1088 {
1089 	xen_mc_t xmc;
1090 	struct xen_mc_mceinject *mce = &xmc.u.mc_mceinject;
1091 
1092 	if (!(hdl->cmih_flags & CMIH_F_INJACTV))
1093 		return;
1094 
1095 	if (int_no != T_MCE) {
1096 		cmn_err(CE_WARN, "xpv_int: int_no %d unimplemented\n",
1097 		    int_no);
1098 	}
1099 
1100 	mce->mceinj_cpunr = xen_physcpu_logical_id(HDLPRIV(hdl));
1101 
1102 	(void) HYPERVISOR_mca(XEN_MC_mceinject, &xmc);
1103 }
1104 
1105 static int
1106 xpv_online(cmi_hdl_impl_t *hdl, int new_status, int *old_status)
1107 {
1108 	xen_sysctl_t xs;
1109 	int op, rc, status;
1110 
1111 	new_status &= ~P_FORCED;
1112 
1113 	switch (new_status) {
1114 	case P_STATUS:
1115 		op = XEN_SYSCTL_CPU_HOTPLUG_STATUS;
1116 		break;
1117 	case P_FAULTED:
1118 	case P_OFFLINE:
1119 		op = XEN_SYSCTL_CPU_HOTPLUG_OFFLINE;
1120 		break;
1121 	case P_ONLINE:
1122 		op = XEN_SYSCTL_CPU_HOTPLUG_ONLINE;
1123 		break;
1124 	default:
1125 		return (-1);
1126 	}
1127 
1128 	xs.cmd = XEN_SYSCTL_cpu_hotplug;
1129 	xs.interface_version = XEN_SYSCTL_INTERFACE_VERSION;
1130 	xs.u.cpu_hotplug.cpu = xen_physcpu_logical_id(HDLPRIV(hdl));
1131 	xs.u.cpu_hotplug.op = op;
1132 
1133 	if ((rc = HYPERVISOR_sysctl(&xs)) >= 0) {
1134 		status = rc;
1135 		rc = 0;
1136 		switch (status) {
1137 		case XEN_CPU_HOTPLUG_STATUS_NEW:
1138 			*old_status = P_OFFLINE;
1139 			break;
1140 		case XEN_CPU_HOTPLUG_STATUS_OFFLINE:
1141 			*old_status = P_FAULTED;
1142 			break;
1143 		case XEN_CPU_HOTPLUG_STATUS_ONLINE:
1144 			*old_status = P_ONLINE;
1145 			break;
1146 		default:
1147 			return (-1);
1148 		}
1149 	}
1150 
1151 	return (-rc);
1152 }
1153 
1154 #endif
1155 
1156 /*ARGSUSED*/
1157 static void *
1158 cpu_search(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
1159     uint_t strandid)
1160 {
1161 #ifdef __xpv
1162 	xen_mc_lcpu_cookie_t cpi;
1163 
1164 	for (cpi = xen_physcpu_next(NULL); cpi != NULL;
1165 	    cpi = xen_physcpu_next(cpi)) {
1166 		if (xen_physcpu_chipid(cpi) == chipid &&
1167 		    xen_physcpu_coreid(cpi) == coreid &&
1168 		    xen_physcpu_strandid(cpi) == strandid)
1169 			return ((void *)cpi);
1170 	}
1171 	return (NULL);
1172 
1173 #else	/* __xpv */
1174 
1175 	cpu_t *cp, *startcp;
1176 
1177 	kpreempt_disable();
1178 	cp = startcp = CPU;
1179 	do {
1180 		if (cmi_ntv_hwchipid(cp) == chipid &&
1181 		    cmi_ntv_hwcoreid(cp) == coreid &&
1182 		    cmi_ntv_hwstrandid(cp) == strandid) {
1183 			kpreempt_enable();
1184 			return ((void *)cp);
1185 		}
1186 
1187 		cp = cp->cpu_next;
1188 	} while (cp != startcp);
1189 	kpreempt_enable();
1190 	return (NULL);
1191 #endif	/* __ xpv */
1192 }
1193 
1194 static boolean_t
1195 cpu_is_cmt(void *priv)
1196 {
1197 #ifdef __xpv
1198 	return (xen_physcpu_is_cmt((xen_mc_lcpu_cookie_t)priv));
1199 #else /* __xpv */
1200 	cpu_t *cp = (cpu_t *)priv;
1201 
1202 	int strands_per_core = cpuid_get_ncpu_per_chip(cp) /
1203 	    cpuid_get_ncore_per_chip(cp);
1204 
1205 	return (strands_per_core > 1);
1206 #endif /* __xpv */
1207 }
1208 
1209 /*
1210  * Find the handle entry of a given cpu identified by a <chip,core,strand>
1211  * tuple.
1212  */
1213 static cmi_hdl_ent_t *
1214 cmi_hdl_ent_lookup(uint_t chipid, uint_t coreid, uint_t strandid)
1215 {
1216 	int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits,
1217 	    cmi_strand_nbits);
1218 
1219 	/*
1220 	 * Allocate per-chip table which contains a list of handle of
1221 	 * all strands of the chip.
1222 	 */
1223 	if (cmi_chip_tab[chipid] == NULL) {
1224 		size_t sz;
1225 		cmi_hdl_ent_t *pg;
1226 
1227 		sz = max_strands * sizeof (cmi_hdl_ent_t);
1228 		pg = kmem_zalloc(sz, KM_SLEEP);
1229 
1230 		/* test and set the per-chip table if it is not allocated */
1231 		if (atomic_cas_ptr(&cmi_chip_tab[chipid], NULL, pg) != NULL)
1232 			kmem_free(pg, sz); /* someone beats us */
1233 	}
1234 
1235 	return (cmi_chip_tab[chipid] +
1236 	    ((((coreid) & CMI_MAX_COREID(cmi_core_nbits)) << cmi_strand_nbits) |
1237 	    ((strandid) & CMI_MAX_STRANDID(cmi_strand_nbits))));
1238 }
1239 
1240 extern void cpuid_get_ext_topo(cpu_t *, uint_t *, uint_t *);
1241 
1242 cmi_hdl_t
1243 cmi_hdl_create(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
1244     uint_t strandid)
1245 {
1246 	cmi_hdl_impl_t *hdl;
1247 	void *priv;
1248 	cmi_hdl_ent_t *ent;
1249 	uint_t vendor;
1250 
1251 #ifdef __xpv
1252 	ASSERT(class == CMI_HDL_SOLARIS_xVM_MCA);
1253 #else
1254 	ASSERT(class == CMI_HDL_NATIVE);
1255 #endif
1256 
1257 	if ((priv = cpu_search(class, chipid, coreid, strandid)) == NULL)
1258 		return (NULL);
1259 
1260 	/*
1261 	 * Assume all chips in the system are the same type.
1262 	 * For Intel, attempt to check if extended topology is available
1263 	 * CPUID.EAX=0xB. If so, get the number of core and strand bits.
1264 	 */
1265 #ifdef __xpv
1266 	vendor = _cpuid_vendorstr_to_vendorcode(
1267 	    (char *)xen_physcpu_vendorstr((xen_mc_lcpu_cookie_t)priv));
1268 #else
1269 	vendor = cpuid_getvendor((cpu_t *)priv);
1270 #endif
1271 
1272 	switch (vendor) {
1273 	case X86_VENDOR_Intel:
1274 	case X86_VENDOR_AMD:
1275 	case X86_VENDOR_HYGON:
1276 		if (cmi_ext_topo_check == 0) {
1277 			cpuid_get_ext_topo((cpu_t *)priv, &cmi_core_nbits,
1278 			    &cmi_strand_nbits);
1279 			cmi_ext_topo_check = 1;
1280 		}
1281 	default:
1282 		break;
1283 	}
1284 
1285 	if (chipid > CMI_MAX_CHIPID ||
1286 	    coreid > CMI_MAX_COREID(cmi_core_nbits) ||
1287 	    strandid > CMI_MAX_STRANDID(cmi_strand_nbits))
1288 		return (NULL);
1289 
1290 	hdl = kmem_zalloc(sizeof (*hdl), KM_SLEEP);
1291 
1292 	hdl->cmih_class = class;
1293 	HDLOPS(hdl) = &cmi_hdl_ops;
1294 	hdl->cmih_chipid = chipid;
1295 	hdl->cmih_coreid = coreid;
1296 	hdl->cmih_strandid = strandid;
1297 	hdl->cmih_mstrand = cpu_is_cmt(priv);
1298 	hdl->cmih_hdlpriv = priv;
1299 #ifdef __xpv
1300 	hdl->cmih_msrsrc = CMI_MSR_FLAG_RD_INTERPOSEOK |
1301 	    CMI_MSR_FLAG_WR_INTERPOSEOK;
1302 
1303 	/*
1304 	 * XXX: need hypervisor support for procnodeid, for now assume
1305 	 * single-node processors (procnodeid = chipid)
1306 	 */
1307 	hdl->cmih_procnodeid = xen_physcpu_chipid((xen_mc_lcpu_cookie_t)priv);
1308 	hdl->cmih_procnodes_per_pkg = 1;
1309 #else   /* __xpv */
1310 	hdl->cmih_msrsrc = CMI_MSR_FLAG_RD_HWOK | CMI_MSR_FLAG_RD_INTERPOSEOK |
1311 	    CMI_MSR_FLAG_WR_HWOK | CMI_MSR_FLAG_WR_INTERPOSEOK;
1312 	hdl->cmih_procnodeid = cpuid_get_procnodeid((cpu_t *)priv);
1313 	hdl->cmih_procnodes_per_pkg =
1314 	    cpuid_get_procnodes_per_pkg((cpu_t *)priv);
1315 #endif  /* __xpv */
1316 
1317 	ent = cmi_hdl_ent_lookup(chipid, coreid, strandid);
1318 	if (ent->cmae_refcnt != 0 || ent->cmae_hdlp != NULL) {
1319 		/*
1320 		 * Somehow this (chipid, coreid, strandid) id tuple has
1321 		 * already been assigned!  This indicates that the
1322 		 * callers logic in determining these values is busted,
1323 		 * or perhaps undermined by bad BIOS setup.  Complain,
1324 		 * and refuse to initialize this tuple again as bad things
1325 		 * will happen.
1326 		 */
1327 		cmn_err(CE_NOTE, "cmi_hdl_create: chipid %d coreid %d "
1328 		    "strandid %d handle already allocated!",
1329 		    chipid, coreid, strandid);
1330 		kmem_free(hdl, sizeof (*hdl));
1331 		return (NULL);
1332 	}
1333 
1334 	/*
1335 	 * Once we store a nonzero reference count others can find this
1336 	 * handle via cmi_hdl_lookup etc.  This initial hold on the handle
1337 	 * is to be dropped only if some other part of cmi initialization
1338 	 * fails or, if it succeeds, at later cpu deconfigure.  Note the
1339 	 * the module private data we hold in cmih_cmi and cmih_cmidata
1340 	 * is still NULL at this point (the caller will fill it with
1341 	 * cmi_hdl_setcmi if it initializes) so consumers of handles
1342 	 * should always be ready for that possibility.
1343 	 */
1344 	ent->cmae_hdlp = hdl;
1345 	hdl->cmih_refcntp = &ent->cmae_refcnt;
1346 	ent->cmae_refcnt = 1;
1347 
1348 	return ((cmi_hdl_t)hdl);
1349 }
1350 
1351 void
1352 cmi_read_smbios(cmi_hdl_t ophdl)
1353 {
1354 
1355 	uint_t strand_apicid = UINT_MAX;
1356 	uint_t chip_inst = UINT_MAX;
1357 	uint16_t smb_id = USHRT_MAX;
1358 	int rc = 0;
1359 
1360 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1361 
1362 	/* set x86gentopo compatibility */
1363 	fm_smb_fmacompat();
1364 
1365 #ifndef __xpv
1366 	strand_apicid = ntv_strand_apicid(hdl);
1367 #else
1368 	strand_apicid = xpv_strand_apicid(hdl);
1369 #endif
1370 
1371 	if (!x86gentopo_legacy) {
1372 		/*
1373 		 * If fm_smb_chipinst() or fm_smb_bboard() fails,
1374 		 * topo reverts to legacy mode
1375 		 */
1376 		rc = fm_smb_chipinst(strand_apicid, &chip_inst, &smb_id);
1377 		if (rc == 0) {
1378 			hdl->cmih_smb_chipid = chip_inst;
1379 			hdl->cmih_smbiosid = smb_id;
1380 		} else {
1381 #ifdef DEBUG
1382 			cmn_err(CE_NOTE, "!cmi reads smbios chip info failed");
1383 #endif /* DEBUG */
1384 			return;
1385 		}
1386 
1387 		hdl->cmih_smb_bboard  = fm_smb_bboard(strand_apicid);
1388 #ifdef DEBUG
1389 		if (hdl->cmih_smb_bboard == NULL)
1390 			cmn_err(CE_NOTE,
1391 			    "!cmi reads smbios base boards info failed");
1392 #endif /* DEBUG */
1393 	}
1394 }
1395 
1396 void
1397 cmi_hdl_hold(cmi_hdl_t ophdl)
1398 {
1399 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1400 
1401 	ASSERT(*hdl->cmih_refcntp != 0); /* must not be the initial hold */
1402 
1403 	atomic_inc_32(hdl->cmih_refcntp);
1404 }
1405 
1406 static int
1407 cmi_hdl_canref(cmi_hdl_ent_t *ent)
1408 {
1409 	volatile uint32_t *refcntp;
1410 	uint32_t refcnt;
1411 
1412 	refcntp = &ent->cmae_refcnt;
1413 	refcnt = *refcntp;
1414 
1415 	if (refcnt == 0) {
1416 		/*
1417 		 * Associated object never existed, is being destroyed,
1418 		 * or has been destroyed.
1419 		 */
1420 		return (0);
1421 	}
1422 
1423 	/*
1424 	 * We cannot use atomic increment here because once the reference
1425 	 * count reaches zero it must never be bumped up again.
1426 	 */
1427 	while (refcnt != 0) {
1428 		if (atomic_cas_32(refcntp, refcnt, refcnt + 1) == refcnt)
1429 			return (1);
1430 		refcnt = *refcntp;
1431 	}
1432 
1433 	/*
1434 	 * Somebody dropped the reference count to 0 after our initial
1435 	 * check.
1436 	 */
1437 	return (0);
1438 }
1439 
1440 
1441 void
1442 cmi_hdl_rele(cmi_hdl_t ophdl)
1443 {
1444 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1445 
1446 	ASSERT(*hdl->cmih_refcntp > 0);
1447 	atomic_dec_32(hdl->cmih_refcntp);
1448 }
1449 
1450 void
1451 cmi_hdl_destroy(cmi_hdl_t ophdl)
1452 {
1453 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1454 	cmi_hdl_ent_t *ent;
1455 
1456 	/* Release the reference count held by cmi_hdl_create(). */
1457 	ASSERT(*hdl->cmih_refcntp > 0);
1458 	atomic_dec_32(hdl->cmih_refcntp);
1459 	hdl->cmih_flags |= CMIH_F_DEAD;
1460 
1461 	ent = cmi_hdl_ent_lookup(hdl->cmih_chipid, hdl->cmih_coreid,
1462 	    hdl->cmih_strandid);
1463 	/*
1464 	 * Use busy polling instead of condition variable here because
1465 	 * cmi_hdl_rele() may be called from #MC handler.
1466 	 */
1467 	while (cmi_hdl_canref(ent)) {
1468 		cmi_hdl_rele(ophdl);
1469 		delay(1);
1470 	}
1471 	ent->cmae_hdlp = NULL;
1472 
1473 	kmem_free(hdl, sizeof (*hdl));
1474 }
1475 
1476 void
1477 cmi_hdl_setspecific(cmi_hdl_t ophdl, void *arg)
1478 {
1479 	IMPLHDL(ophdl)->cmih_spec = arg;
1480 }
1481 
1482 void *
1483 cmi_hdl_getspecific(cmi_hdl_t ophdl)
1484 {
1485 	return (IMPLHDL(ophdl)->cmih_spec);
1486 }
1487 
1488 void
1489 cmi_hdl_setmc(cmi_hdl_t ophdl, const struct cmi_mc_ops *mcops, void *mcdata)
1490 {
1491 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1492 
1493 	ASSERT(hdl->cmih_mcops == NULL && hdl->cmih_mcdata == NULL);
1494 	hdl->cmih_mcops = mcops;
1495 	hdl->cmih_mcdata = mcdata;
1496 }
1497 
1498 const struct cmi_mc_ops *
1499 cmi_hdl_getmcops(cmi_hdl_t ophdl)
1500 {
1501 	return (IMPLHDL(ophdl)->cmih_mcops);
1502 }
1503 
1504 void *
1505 cmi_hdl_getmcdata(cmi_hdl_t ophdl)
1506 {
1507 	return (IMPLHDL(ophdl)->cmih_mcdata);
1508 }
1509 
1510 cmi_hdl_t
1511 cmi_hdl_lookup(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
1512     uint_t strandid)
1513 {
1514 	cmi_hdl_ent_t *ent;
1515 
1516 	if (chipid > CMI_MAX_CHIPID ||
1517 	    coreid > CMI_MAX_COREID(cmi_core_nbits) ||
1518 	    strandid > CMI_MAX_STRANDID(cmi_strand_nbits))
1519 		return (NULL);
1520 
1521 	ent = cmi_hdl_ent_lookup(chipid, coreid, strandid);
1522 
1523 	if (class == CMI_HDL_NEUTRAL)
1524 #ifdef __xpv
1525 		class = CMI_HDL_SOLARIS_xVM_MCA;
1526 #else
1527 		class = CMI_HDL_NATIVE;
1528 #endif
1529 
1530 	if (!cmi_hdl_canref(ent))
1531 		return (NULL);
1532 
1533 	if (ent->cmae_hdlp->cmih_class != class) {
1534 		cmi_hdl_rele((cmi_hdl_t)ent->cmae_hdlp);
1535 		return (NULL);
1536 	}
1537 
1538 	return ((cmi_hdl_t)ent->cmae_hdlp);
1539 }
1540 
1541 cmi_hdl_t
1542 cmi_hdl_any(void)
1543 {
1544 	int i, j;
1545 	cmi_hdl_ent_t *ent;
1546 	int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits,
1547 	    cmi_strand_nbits);
1548 
1549 	for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) {
1550 		if (cmi_chip_tab[i] == NULL)
1551 			continue;
1552 		for (j = 0, ent = cmi_chip_tab[i]; j < max_strands;
1553 		    j++, ent++) {
1554 			if (cmi_hdl_canref(ent))
1555 				return ((cmi_hdl_t)ent->cmae_hdlp);
1556 		}
1557 	}
1558 
1559 	return (NULL);
1560 }
1561 
1562 void
1563 cmi_hdl_walk(int (*cbfunc)(cmi_hdl_t, void *, void *, void *),
1564     void *arg1, void *arg2, void *arg3)
1565 {
1566 	int i, j;
1567 	cmi_hdl_ent_t *ent;
1568 	int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits,
1569 	    cmi_strand_nbits);
1570 
1571 	for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) {
1572 		if (cmi_chip_tab[i] == NULL)
1573 			continue;
1574 		for (j = 0, ent = cmi_chip_tab[i]; j < max_strands;
1575 		    j++, ent++) {
1576 			if (cmi_hdl_canref(ent)) {
1577 				cmi_hdl_impl_t *hdl = ent->cmae_hdlp;
1578 				if ((*cbfunc)((cmi_hdl_t)hdl, arg1, arg2, arg3)
1579 				    == CMI_HDL_WALK_DONE) {
1580 					cmi_hdl_rele((cmi_hdl_t)hdl);
1581 					return;
1582 				}
1583 				cmi_hdl_rele((cmi_hdl_t)hdl);
1584 			}
1585 		}
1586 	}
1587 }
1588 
1589 void
1590 cmi_hdl_setcmi(cmi_hdl_t ophdl, void *cmi, void *cmidata)
1591 {
1592 	IMPLHDL(ophdl)->cmih_cmidata = cmidata;
1593 	IMPLHDL(ophdl)->cmih_cmi = cmi;
1594 }
1595 
1596 void *
1597 cmi_hdl_getcmi(cmi_hdl_t ophdl)
1598 {
1599 	return (IMPLHDL(ophdl)->cmih_cmi);
1600 }
1601 
1602 void *
1603 cmi_hdl_getcmidata(cmi_hdl_t ophdl)
1604 {
1605 	return (IMPLHDL(ophdl)->cmih_cmidata);
1606 }
1607 
1608 enum cmi_hdl_class
1609 cmi_hdl_class(cmi_hdl_t ophdl)
1610 {
1611 	return (IMPLHDL(ophdl)->cmih_class);
1612 }
1613 
1614 #define	CMI_HDL_OPFUNC(what, type)				\
1615 	type							\
1616 	cmi_hdl_##what(cmi_hdl_t ophdl)				\
1617 	{							\
1618 		return (HDLOPS(IMPLHDL(ophdl))->		\
1619 		    cmio_##what(IMPLHDL(ophdl)));		\
1620 	}
1621 
1622 /* BEGIN CSTYLED */
1623 CMI_HDL_OPFUNC(vendor, uint_t)
1624 CMI_HDL_OPFUNC(vendorstr, const char *)
1625 CMI_HDL_OPFUNC(family, uint_t)
1626 CMI_HDL_OPFUNC(model, uint_t)
1627 CMI_HDL_OPFUNC(stepping, uint_t)
1628 CMI_HDL_OPFUNC(chipid, uint_t)
1629 CMI_HDL_OPFUNC(procnodeid, uint_t)
1630 CMI_HDL_OPFUNC(coreid, uint_t)
1631 CMI_HDL_OPFUNC(strandid, uint_t)
1632 CMI_HDL_OPFUNC(procnodes_per_pkg, uint_t)
1633 CMI_HDL_OPFUNC(strand_apicid, uint_t)
1634 CMI_HDL_OPFUNC(chiprev, uint32_t)
1635 CMI_HDL_OPFUNC(chiprevstr, const char *)
1636 CMI_HDL_OPFUNC(getsockettype, uint32_t)
1637 CMI_HDL_OPFUNC(getsocketstr, const char *)
1638 CMI_HDL_OPFUNC(logical_id, id_t)
1639 CMI_HDL_OPFUNC(smbiosid, uint16_t)
1640 CMI_HDL_OPFUNC(smb_chipid, uint_t)
1641 CMI_HDL_OPFUNC(smb_bboard, nvlist_t *)
1642 CMI_HDL_OPFUNC(chipsig, uint_t)
1643 /* END CSTYLED */
1644 
1645 boolean_t
1646 cmi_hdl_is_cmt(cmi_hdl_t ophdl)
1647 {
1648 	return (IMPLHDL(ophdl)->cmih_mstrand);
1649 }
1650 
1651 void
1652 cmi_hdl_int(cmi_hdl_t ophdl, int num)
1653 {
1654 	if (HDLOPS(IMPLHDL(ophdl))->cmio_int == NULL)
1655 		return;
1656 
1657 	cmi_hdl_inj_begin(ophdl);
1658 	HDLOPS(IMPLHDL(ophdl))->cmio_int(IMPLHDL(ophdl), num);
1659 	cmi_hdl_inj_end(NULL);
1660 }
1661 
1662 int
1663 cmi_hdl_online(cmi_hdl_t ophdl, int new_status, int *old_status)
1664 {
1665 	return (HDLOPS(IMPLHDL(ophdl))->cmio_online(IMPLHDL(ophdl),
1666 	    new_status, old_status));
1667 }
1668 
1669 #ifndef	__xpv
1670 /*
1671  * Return hardware chip instance; cpuid_get_chipid provides this directly.
1672  */
1673 uint_t
1674 cmi_ntv_hwchipid(cpu_t *cp)
1675 {
1676 	return (cpuid_get_chipid(cp));
1677 }
1678 
1679 /*
1680  * Return hardware node instance; cpuid_get_procnodeid provides this directly.
1681  */
1682 uint_t
1683 cmi_ntv_hwprocnodeid(cpu_t *cp)
1684 {
1685 	return (cpuid_get_procnodeid(cp));
1686 }
1687 
1688 /*
1689  * Return core instance within a single chip.
1690  */
1691 uint_t
1692 cmi_ntv_hwcoreid(cpu_t *cp)
1693 {
1694 	return (cpuid_get_pkgcoreid(cp));
1695 }
1696 
1697 /*
1698  * Return strand number within a single core.  cpuid_get_clogid numbers
1699  * all execution units (strands, or cores in unstranded models) sequentially
1700  * within a single chip.
1701  */
1702 uint_t
1703 cmi_ntv_hwstrandid(cpu_t *cp)
1704 {
1705 	int strands_per_core = cpuid_get_ncpu_per_chip(cp) /
1706 	    cpuid_get_ncore_per_chip(cp);
1707 
1708 	return (cpuid_get_clogid(cp) % strands_per_core);
1709 }
1710 
1711 static void
1712 cmi_ntv_hwdisable_mce_xc(void)
1713 {
1714 	ulong_t cr4;
1715 
1716 	cr4 = getcr4();
1717 	cr4 = cr4 & (~CR4_MCE);
1718 	setcr4(cr4);
1719 }
1720 
1721 void
1722 cmi_ntv_hwdisable_mce(cmi_hdl_t hdl)
1723 {
1724 	cpuset_t	set;
1725 	cmi_hdl_impl_t *thdl = IMPLHDL(hdl);
1726 	cpu_t *cp = HDLPRIV(thdl);
1727 
1728 	if (CPU->cpu_id == cp->cpu_id) {
1729 		cmi_ntv_hwdisable_mce_xc();
1730 	} else {
1731 		CPUSET_ONLY(set, cp->cpu_id);
1732 		xc_call(0, 0, 0, CPUSET2BV(set),
1733 		    (xc_func_t)cmi_ntv_hwdisable_mce_xc);
1734 	}
1735 }
1736 
1737 #endif	/* __xpv */
1738 
1739 void
1740 cmi_hdlconf_rdmsr_nohw(cmi_hdl_t ophdl)
1741 {
1742 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1743 
1744 	hdl->cmih_msrsrc &= ~CMI_MSR_FLAG_RD_HWOK;
1745 }
1746 
1747 void
1748 cmi_hdlconf_wrmsr_nohw(cmi_hdl_t ophdl)
1749 {
1750 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1751 
1752 	hdl->cmih_msrsrc &= ~CMI_MSR_FLAG_WR_HWOK;
1753 }
1754 
1755 cmi_errno_t
1756 cmi_hdl_rdmsr(cmi_hdl_t ophdl, uint_t msr, uint64_t *valp)
1757 {
1758 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1759 
1760 	/*
1761 	 * Regardless of the handle class, we first check for am
1762 	 * interposed value.  In the xVM case you probably want to
1763 	 * place interposed values within the hypervisor itself, but
1764 	 * we still allow interposing them in dom0 for test and bringup
1765 	 * purposes.
1766 	 */
1767 	if ((hdl->cmih_msrsrc & CMI_MSR_FLAG_RD_INTERPOSEOK) &&
1768 	    msri_lookup(hdl, msr, valp))
1769 		return (CMI_SUCCESS);
1770 
1771 	if (HDLOPS(hdl)->cmio_rdmsr == NULL)
1772 		return (CMIERR_NOTSUP);
1773 
1774 	return (HDLOPS(hdl)->cmio_rdmsr(hdl, msr, valp));
1775 }
1776 
1777 cmi_errno_t
1778 cmi_hdl_wrmsr(cmi_hdl_t ophdl, uint_t msr, uint64_t val)
1779 {
1780 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1781 
1782 	/* Invalidate any interposed value */
1783 	msri_rment(hdl, msr);
1784 
1785 	if (HDLOPS(hdl)->cmio_wrmsr == NULL)
1786 		return (CMI_SUCCESS);	/* pretend all is ok */
1787 
1788 	return (HDLOPS(hdl)->cmio_wrmsr(hdl, msr, val));
1789 }
1790 
1791 void
1792 cmi_hdl_enable_mce(cmi_hdl_t ophdl)
1793 {
1794 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1795 	ulong_t cr4;
1796 
1797 	if (HDLOPS(hdl)->cmio_getcr4 == NULL ||
1798 	    HDLOPS(hdl)->cmio_setcr4 == NULL)
1799 		return;
1800 
1801 	cr4 = HDLOPS(hdl)->cmio_getcr4(hdl);
1802 
1803 	HDLOPS(hdl)->cmio_setcr4(hdl, cr4 | CR4_MCE);
1804 }
1805 
1806 void
1807 cmi_hdl_msrinterpose(cmi_hdl_t ophdl, cmi_mca_regs_t *regs, uint_t nregs)
1808 {
1809 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1810 	int i;
1811 
1812 	if (HDLOPS(hdl)->cmio_msrinterpose == NULL)
1813 		return;
1814 
1815 	cmi_hdl_inj_begin(ophdl);
1816 
1817 	for (i = 0; i < nregs; i++, regs++)
1818 		HDLOPS(hdl)->cmio_msrinterpose(hdl, regs->cmr_msrnum,
1819 		    regs->cmr_msrval);
1820 
1821 	cmi_hdl_inj_end(ophdl);
1822 }
1823 
1824 /*ARGSUSED*/
1825 void
1826 cmi_hdl_msrforward(cmi_hdl_t ophdl, cmi_mca_regs_t *regs, uint_t nregs)
1827 {
1828 #ifdef __xpv
1829 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1830 	int i;
1831 
1832 	for (i = 0; i < nregs; i++, regs++)
1833 		msri_addent(hdl, regs->cmr_msrnum, regs->cmr_msrval);
1834 #endif
1835 }
1836 
1837 
1838 void
1839 cmi_pcird_nohw(void)
1840 {
1841 	cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_RD_HWOK;
1842 }
1843 
1844 void
1845 cmi_pciwr_nohw(void)
1846 {
1847 	cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_WR_HWOK;
1848 }
1849 
1850 static uint32_t
1851 cmi_pci_get_cmn(int bus, int dev, int func, int reg, int asz,
1852     int *interpose, ddi_acc_handle_t hdl)
1853 {
1854 	uint32_t val;
1855 
1856 	if (cmi_pcicfg_flags & CMI_PCICFG_FLAG_RD_INTERPOSEOK &&
1857 	    pcii_lookup(bus, dev, func, reg, asz, &val)) {
1858 		if (interpose)
1859 			*interpose = 1;
1860 		return (val);
1861 	}
1862 	if (interpose)
1863 		*interpose = 0;
1864 
1865 	if (!(cmi_pcicfg_flags & CMI_PCICFG_FLAG_RD_HWOK))
1866 		return (0);
1867 
1868 	switch (asz) {
1869 	case 1:
1870 		if (hdl)
1871 			val = pci_config_get8(hdl, (off_t)reg);
1872 		else
1873 			val = pci_cfgacc_get8(NULL, PCI_GETBDF(bus, dev, func),
1874 			    reg);
1875 		break;
1876 	case 2:
1877 		if (hdl)
1878 			val = pci_config_get16(hdl, (off_t)reg);
1879 		else
1880 			val = pci_cfgacc_get16(NULL, PCI_GETBDF(bus, dev, func),
1881 			    reg);
1882 		break;
1883 	case 4:
1884 		if (hdl)
1885 			val = pci_config_get32(hdl, (off_t)reg);
1886 		else
1887 			val = pci_cfgacc_get32(NULL, PCI_GETBDF(bus, dev, func),
1888 			    reg);
1889 		break;
1890 	default:
1891 		val = 0;
1892 	}
1893 	return (val);
1894 }
1895 
1896 uint8_t
1897 cmi_pci_getb(int bus, int dev, int func, int reg, int *interpose,
1898     ddi_acc_handle_t hdl)
1899 {
1900 	return ((uint8_t)cmi_pci_get_cmn(bus, dev, func, reg, 1, interpose,
1901 	    hdl));
1902 }
1903 
1904 uint16_t
1905 cmi_pci_getw(int bus, int dev, int func, int reg, int *interpose,
1906     ddi_acc_handle_t hdl)
1907 {
1908 	return ((uint16_t)cmi_pci_get_cmn(bus, dev, func, reg, 2, interpose,
1909 	    hdl));
1910 }
1911 
1912 uint32_t
1913 cmi_pci_getl(int bus, int dev, int func, int reg, int *interpose,
1914     ddi_acc_handle_t hdl)
1915 {
1916 	return (cmi_pci_get_cmn(bus, dev, func, reg, 4, interpose, hdl));
1917 }
1918 
1919 void
1920 cmi_pci_interposeb(int bus, int dev, int func, int reg, uint8_t val)
1921 {
1922 	pcii_addent(bus, dev, func, reg, val, 1);
1923 }
1924 
1925 void
1926 cmi_pci_interposew(int bus, int dev, int func, int reg, uint16_t val)
1927 {
1928 	pcii_addent(bus, dev, func, reg, val, 2);
1929 }
1930 
1931 void
1932 cmi_pci_interposel(int bus, int dev, int func, int reg, uint32_t val)
1933 {
1934 	pcii_addent(bus, dev, func, reg, val, 4);
1935 }
1936 
1937 static void
1938 cmi_pci_put_cmn(int bus, int dev, int func, int reg, int asz,
1939     ddi_acc_handle_t hdl, uint32_t val)
1940 {
1941 	/*
1942 	 * If there is an interposed value for this register invalidate it.
1943 	 */
1944 	pcii_rment(bus, dev, func, reg, asz);
1945 
1946 	if (!(cmi_pcicfg_flags & CMI_PCICFG_FLAG_WR_HWOK))
1947 		return;
1948 
1949 	switch (asz) {
1950 	case 1:
1951 		if (hdl)
1952 			pci_config_put8(hdl, (off_t)reg, (uint8_t)val);
1953 		else
1954 			pci_cfgacc_put8(NULL, PCI_GETBDF(bus, dev, func), reg,
1955 			    (uint8_t)val);
1956 		break;
1957 
1958 	case 2:
1959 		if (hdl)
1960 			pci_config_put16(hdl, (off_t)reg, (uint16_t)val);
1961 		else
1962 			pci_cfgacc_put16(NULL, PCI_GETBDF(bus, dev, func), reg,
1963 			    (uint16_t)val);
1964 		break;
1965 
1966 	case 4:
1967 		if (hdl)
1968 			pci_config_put32(hdl, (off_t)reg, val);
1969 		else
1970 			pci_cfgacc_put32(NULL, PCI_GETBDF(bus, dev, func), reg,
1971 			    val);
1972 		break;
1973 
1974 	default:
1975 		break;
1976 	}
1977 }
1978 
1979 void
1980 cmi_pci_putb(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl,
1981     uint8_t val)
1982 {
1983 	cmi_pci_put_cmn(bus, dev, func, reg, 1, hdl, val);
1984 }
1985 
1986 void
1987 cmi_pci_putw(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl,
1988     uint16_t val)
1989 {
1990 	cmi_pci_put_cmn(bus, dev, func, reg, 2, hdl, val);
1991 }
1992 
1993 void
1994 cmi_pci_putl(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl,
1995     uint32_t val)
1996 {
1997 	cmi_pci_put_cmn(bus, dev, func, reg, 4, hdl, val);
1998 }
1999 
2000 static const struct cmi_hdl_ops cmi_hdl_ops = {
2001 #ifdef __xpv
2002 	/*
2003 	 * CMI_HDL_SOLARIS_xVM_MCA - ops when we are an xVM dom0
2004 	 */
2005 	xpv_vendor,		/* cmio_vendor */
2006 	xpv_vendorstr,		/* cmio_vendorstr */
2007 	xpv_family,		/* cmio_family */
2008 	xpv_model,		/* cmio_model */
2009 	xpv_stepping,		/* cmio_stepping */
2010 	xpv_chipid,		/* cmio_chipid */
2011 	xpv_procnodeid,		/* cmio_procnodeid */
2012 	xpv_coreid,		/* cmio_coreid */
2013 	xpv_strandid,		/* cmio_strandid */
2014 	xpv_procnodes_per_pkg,	/* cmio_procnodes_per_pkg */
2015 	xpv_strand_apicid,	/* cmio_strand_apicid */
2016 	xpv_chiprev,		/* cmio_chiprev */
2017 	xpv_chiprevstr,		/* cmio_chiprevstr */
2018 	xpv_getsockettype,	/* cmio_getsockettype */
2019 	xpv_getsocketstr,	/* cmio_getsocketstr */
2020 	xpv_chipsig,		/* cmio_chipsig */
2021 	xpv_logical_id,		/* cmio_logical_id */
2022 	NULL,			/* cmio_getcr4 */
2023 	NULL,			/* cmio_setcr4 */
2024 	xpv_rdmsr,		/* cmio_rdmsr */
2025 	xpv_wrmsr,		/* cmio_wrmsr */
2026 	xpv_msrinterpose,	/* cmio_msrinterpose */
2027 	xpv_int,		/* cmio_int */
2028 	xpv_online,		/* cmio_online */
2029 	xpv_smbiosid,		/* cmio_smbiosid */
2030 	xpv_smb_chipid,		/* cmio_smb_chipid */
2031 	xpv_smb_bboard		/* cmio_smb_bboard */
2032 
2033 #else	/* __xpv */
2034 
2035 	/*
2036 	 * CMI_HDL_NATIVE - ops when apparently running on bare-metal
2037 	 */
2038 	ntv_vendor,		/* cmio_vendor */
2039 	ntv_vendorstr,		/* cmio_vendorstr */
2040 	ntv_family,		/* cmio_family */
2041 	ntv_model,		/* cmio_model */
2042 	ntv_stepping,		/* cmio_stepping */
2043 	ntv_chipid,		/* cmio_chipid */
2044 	ntv_procnodeid,		/* cmio_procnodeid */
2045 	ntv_coreid,		/* cmio_coreid */
2046 	ntv_strandid,		/* cmio_strandid */
2047 	ntv_procnodes_per_pkg,	/* cmio_procnodes_per_pkg */
2048 	ntv_strand_apicid,	/* cmio_strand_apicid */
2049 	ntv_chiprev,		/* cmio_chiprev */
2050 	ntv_chiprevstr,		/* cmio_chiprevstr */
2051 	ntv_getsockettype,	/* cmio_getsockettype */
2052 	ntv_getsocketstr,	/* cmio_getsocketstr */
2053 	ntv_chipsig,		/* cmio_chipsig */
2054 	ntv_logical_id,		/* cmio_logical_id */
2055 	ntv_getcr4,		/* cmio_getcr4 */
2056 	ntv_setcr4,		/* cmio_setcr4 */
2057 	ntv_rdmsr,		/* cmio_rdmsr */
2058 	ntv_wrmsr,		/* cmio_wrmsr */
2059 	ntv_msrinterpose,	/* cmio_msrinterpose */
2060 	ntv_int,		/* cmio_int */
2061 	ntv_online,		/* cmio_online */
2062 	ntv_smbiosid,		/* cmio_smbiosid */
2063 	ntv_smb_chipid,		/* cmio_smb_chipid */
2064 	ntv_smb_bboard		/* cmio_smb_bboard */
2065 #endif
2066 };
2067