xref: /illumos-gate/usr/src/uts/i86pc/os/cmi_hw.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
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 		if (cmi_ext_topo_check == 0) {
1276 			cpuid_get_ext_topo((cpu_t *)priv, &cmi_core_nbits,
1277 			    &cmi_strand_nbits);
1278 			cmi_ext_topo_check = 1;
1279 		}
1280 	default:
1281 		break;
1282 	}
1283 
1284 	if (chipid > CMI_MAX_CHIPID ||
1285 	    coreid > CMI_MAX_COREID(cmi_core_nbits) ||
1286 	    strandid > CMI_MAX_STRANDID(cmi_strand_nbits))
1287 		return (NULL);
1288 
1289 	hdl = kmem_zalloc(sizeof (*hdl), KM_SLEEP);
1290 
1291 	hdl->cmih_class = class;
1292 	HDLOPS(hdl) = &cmi_hdl_ops;
1293 	hdl->cmih_chipid = chipid;
1294 	hdl->cmih_coreid = coreid;
1295 	hdl->cmih_strandid = strandid;
1296 	hdl->cmih_mstrand = cpu_is_cmt(priv);
1297 	hdl->cmih_hdlpriv = priv;
1298 #ifdef __xpv
1299 	hdl->cmih_msrsrc = CMI_MSR_FLAG_RD_INTERPOSEOK |
1300 	    CMI_MSR_FLAG_WR_INTERPOSEOK;
1301 
1302 	/*
1303 	 * XXX: need hypervisor support for procnodeid, for now assume
1304 	 * single-node processors (procnodeid = chipid)
1305 	 */
1306 	hdl->cmih_procnodeid = xen_physcpu_chipid((xen_mc_lcpu_cookie_t)priv);
1307 	hdl->cmih_procnodes_per_pkg = 1;
1308 #else   /* __xpv */
1309 	hdl->cmih_msrsrc = CMI_MSR_FLAG_RD_HWOK | CMI_MSR_FLAG_RD_INTERPOSEOK |
1310 	    CMI_MSR_FLAG_WR_HWOK | CMI_MSR_FLAG_WR_INTERPOSEOK;
1311 	hdl->cmih_procnodeid = cpuid_get_procnodeid((cpu_t *)priv);
1312 	hdl->cmih_procnodes_per_pkg =
1313 	    cpuid_get_procnodes_per_pkg((cpu_t *)priv);
1314 #endif  /* __xpv */
1315 
1316 	ent = cmi_hdl_ent_lookup(chipid, coreid, strandid);
1317 	if (ent->cmae_refcnt != 0 || ent->cmae_hdlp != NULL) {
1318 		/*
1319 		 * Somehow this (chipid, coreid, strandid) id tuple has
1320 		 * already been assigned!  This indicates that the
1321 		 * callers logic in determining these values is busted,
1322 		 * or perhaps undermined by bad BIOS setup.  Complain,
1323 		 * and refuse to initialize this tuple again as bad things
1324 		 * will happen.
1325 		 */
1326 		cmn_err(CE_NOTE, "cmi_hdl_create: chipid %d coreid %d "
1327 		    "strandid %d handle already allocated!",
1328 		    chipid, coreid, strandid);
1329 		kmem_free(hdl, sizeof (*hdl));
1330 		return (NULL);
1331 	}
1332 
1333 	/*
1334 	 * Once we store a nonzero reference count others can find this
1335 	 * handle via cmi_hdl_lookup etc.  This initial hold on the handle
1336 	 * is to be dropped only if some other part of cmi initialization
1337 	 * fails or, if it succeeds, at later cpu deconfigure.  Note the
1338 	 * the module private data we hold in cmih_cmi and cmih_cmidata
1339 	 * is still NULL at this point (the caller will fill it with
1340 	 * cmi_hdl_setcmi if it initializes) so consumers of handles
1341 	 * should always be ready for that possibility.
1342 	 */
1343 	ent->cmae_hdlp = hdl;
1344 	hdl->cmih_refcntp = &ent->cmae_refcnt;
1345 	ent->cmae_refcnt = 1;
1346 
1347 	return ((cmi_hdl_t)hdl);
1348 }
1349 
1350 void
1351 cmi_read_smbios(cmi_hdl_t ophdl)
1352 {
1353 
1354 	uint_t strand_apicid = UINT_MAX;
1355 	uint_t chip_inst = UINT_MAX;
1356 	uint16_t smb_id = USHRT_MAX;
1357 	int rc = 0;
1358 
1359 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1360 
1361 	/* set x86gentopo compatibility */
1362 	fm_smb_fmacompat();
1363 
1364 #ifndef __xpv
1365 	strand_apicid = ntv_strand_apicid(hdl);
1366 #else
1367 	strand_apicid = xpv_strand_apicid(hdl);
1368 #endif
1369 
1370 	if (!x86gentopo_legacy) {
1371 		/*
1372 		 * If fm_smb_chipinst() or fm_smb_bboard() fails,
1373 		 * topo reverts to legacy mode
1374 		 */
1375 		rc = fm_smb_chipinst(strand_apicid, &chip_inst, &smb_id);
1376 		if (rc == 0) {
1377 			hdl->cmih_smb_chipid = chip_inst;
1378 			hdl->cmih_smbiosid = smb_id;
1379 		} else {
1380 #ifdef DEBUG
1381 			cmn_err(CE_NOTE, "!cmi reads smbios chip info failed");
1382 #endif /* DEBUG */
1383 			return;
1384 		}
1385 
1386 		hdl->cmih_smb_bboard  = fm_smb_bboard(strand_apicid);
1387 #ifdef DEBUG
1388 		if (hdl->cmih_smb_bboard == NULL)
1389 			cmn_err(CE_NOTE,
1390 			    "!cmi reads smbios base boards info failed");
1391 #endif /* DEBUG */
1392 	}
1393 }
1394 
1395 void
1396 cmi_hdl_hold(cmi_hdl_t ophdl)
1397 {
1398 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1399 
1400 	ASSERT(*hdl->cmih_refcntp != 0); /* must not be the initial hold */
1401 
1402 	atomic_inc_32(hdl->cmih_refcntp);
1403 }
1404 
1405 static int
1406 cmi_hdl_canref(cmi_hdl_ent_t *ent)
1407 {
1408 	volatile uint32_t *refcntp;
1409 	uint32_t refcnt;
1410 
1411 	refcntp = &ent->cmae_refcnt;
1412 	refcnt = *refcntp;
1413 
1414 	if (refcnt == 0) {
1415 		/*
1416 		 * Associated object never existed, is being destroyed,
1417 		 * or has been destroyed.
1418 		 */
1419 		return (0);
1420 	}
1421 
1422 	/*
1423 	 * We cannot use atomic increment here because once the reference
1424 	 * count reaches zero it must never be bumped up again.
1425 	 */
1426 	while (refcnt != 0) {
1427 		if (atomic_cas_32(refcntp, refcnt, refcnt + 1) == refcnt)
1428 			return (1);
1429 		refcnt = *refcntp;
1430 	}
1431 
1432 	/*
1433 	 * Somebody dropped the reference count to 0 after our initial
1434 	 * check.
1435 	 */
1436 	return (0);
1437 }
1438 
1439 
1440 void
1441 cmi_hdl_rele(cmi_hdl_t ophdl)
1442 {
1443 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1444 
1445 	ASSERT(*hdl->cmih_refcntp > 0);
1446 	atomic_dec_32(hdl->cmih_refcntp);
1447 }
1448 
1449 void
1450 cmi_hdl_destroy(cmi_hdl_t ophdl)
1451 {
1452 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1453 	cmi_hdl_ent_t *ent;
1454 
1455 	/* Release the reference count held by cmi_hdl_create(). */
1456 	ASSERT(*hdl->cmih_refcntp > 0);
1457 	atomic_dec_32(hdl->cmih_refcntp);
1458 	hdl->cmih_flags |= CMIH_F_DEAD;
1459 
1460 	ent = cmi_hdl_ent_lookup(hdl->cmih_chipid, hdl->cmih_coreid,
1461 	    hdl->cmih_strandid);
1462 	/*
1463 	 * Use busy polling instead of condition variable here because
1464 	 * cmi_hdl_rele() may be called from #MC handler.
1465 	 */
1466 	while (cmi_hdl_canref(ent)) {
1467 		cmi_hdl_rele(ophdl);
1468 		delay(1);
1469 	}
1470 	ent->cmae_hdlp = NULL;
1471 
1472 	kmem_free(hdl, sizeof (*hdl));
1473 }
1474 
1475 void
1476 cmi_hdl_setspecific(cmi_hdl_t ophdl, void *arg)
1477 {
1478 	IMPLHDL(ophdl)->cmih_spec = arg;
1479 }
1480 
1481 void *
1482 cmi_hdl_getspecific(cmi_hdl_t ophdl)
1483 {
1484 	return (IMPLHDL(ophdl)->cmih_spec);
1485 }
1486 
1487 void
1488 cmi_hdl_setmc(cmi_hdl_t ophdl, const struct cmi_mc_ops *mcops, void *mcdata)
1489 {
1490 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1491 
1492 	ASSERT(hdl->cmih_mcops == NULL && hdl->cmih_mcdata == NULL);
1493 	hdl->cmih_mcops = mcops;
1494 	hdl->cmih_mcdata = mcdata;
1495 }
1496 
1497 const struct cmi_mc_ops *
1498 cmi_hdl_getmcops(cmi_hdl_t ophdl)
1499 {
1500 	return (IMPLHDL(ophdl)->cmih_mcops);
1501 }
1502 
1503 void *
1504 cmi_hdl_getmcdata(cmi_hdl_t ophdl)
1505 {
1506 	return (IMPLHDL(ophdl)->cmih_mcdata);
1507 }
1508 
1509 cmi_hdl_t
1510 cmi_hdl_lookup(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
1511     uint_t strandid)
1512 {
1513 	cmi_hdl_ent_t *ent;
1514 
1515 	if (chipid > CMI_MAX_CHIPID ||
1516 	    coreid > CMI_MAX_COREID(cmi_core_nbits) ||
1517 	    strandid > CMI_MAX_STRANDID(cmi_strand_nbits))
1518 		return (NULL);
1519 
1520 	ent = cmi_hdl_ent_lookup(chipid, coreid, strandid);
1521 
1522 	if (class == CMI_HDL_NEUTRAL)
1523 #ifdef __xpv
1524 		class = CMI_HDL_SOLARIS_xVM_MCA;
1525 #else
1526 		class = CMI_HDL_NATIVE;
1527 #endif
1528 
1529 	if (!cmi_hdl_canref(ent))
1530 		return (NULL);
1531 
1532 	if (ent->cmae_hdlp->cmih_class != class) {
1533 		cmi_hdl_rele((cmi_hdl_t)ent->cmae_hdlp);
1534 		return (NULL);
1535 	}
1536 
1537 	return ((cmi_hdl_t)ent->cmae_hdlp);
1538 }
1539 
1540 cmi_hdl_t
1541 cmi_hdl_any(void)
1542 {
1543 	int i, j;
1544 	cmi_hdl_ent_t *ent;
1545 	int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits,
1546 	    cmi_strand_nbits);
1547 
1548 	for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) {
1549 		if (cmi_chip_tab[i] == NULL)
1550 			continue;
1551 		for (j = 0, ent = cmi_chip_tab[i]; j < max_strands;
1552 		    j++, ent++) {
1553 			if (cmi_hdl_canref(ent))
1554 				return ((cmi_hdl_t)ent->cmae_hdlp);
1555 		}
1556 	}
1557 
1558 	return (NULL);
1559 }
1560 
1561 void
1562 cmi_hdl_walk(int (*cbfunc)(cmi_hdl_t, void *, void *, void *),
1563     void *arg1, void *arg2, void *arg3)
1564 {
1565 	int i, j;
1566 	cmi_hdl_ent_t *ent;
1567 	int max_strands = CMI_MAX_STRANDS_PER_CHIP(cmi_core_nbits,
1568 	    cmi_strand_nbits);
1569 
1570 	for (i = 0; i < CMI_CHIPID_ARR_SZ; i++) {
1571 		if (cmi_chip_tab[i] == NULL)
1572 			continue;
1573 		for (j = 0, ent = cmi_chip_tab[i]; j < max_strands;
1574 		    j++, ent++) {
1575 			if (cmi_hdl_canref(ent)) {
1576 				cmi_hdl_impl_t *hdl = ent->cmae_hdlp;
1577 				if ((*cbfunc)((cmi_hdl_t)hdl, arg1, arg2, arg3)
1578 				    == CMI_HDL_WALK_DONE) {
1579 					cmi_hdl_rele((cmi_hdl_t)hdl);
1580 					return;
1581 				}
1582 				cmi_hdl_rele((cmi_hdl_t)hdl);
1583 			}
1584 		}
1585 	}
1586 }
1587 
1588 void
1589 cmi_hdl_setcmi(cmi_hdl_t ophdl, void *cmi, void *cmidata)
1590 {
1591 	IMPLHDL(ophdl)->cmih_cmidata = cmidata;
1592 	IMPLHDL(ophdl)->cmih_cmi = cmi;
1593 }
1594 
1595 void *
1596 cmi_hdl_getcmi(cmi_hdl_t ophdl)
1597 {
1598 	return (IMPLHDL(ophdl)->cmih_cmi);
1599 }
1600 
1601 void *
1602 cmi_hdl_getcmidata(cmi_hdl_t ophdl)
1603 {
1604 	return (IMPLHDL(ophdl)->cmih_cmidata);
1605 }
1606 
1607 enum cmi_hdl_class
1608 cmi_hdl_class(cmi_hdl_t ophdl)
1609 {
1610 	return (IMPLHDL(ophdl)->cmih_class);
1611 }
1612 
1613 #define	CMI_HDL_OPFUNC(what, type)				\
1614 	type							\
1615 	cmi_hdl_##what(cmi_hdl_t ophdl)				\
1616 	{							\
1617 		return (HDLOPS(IMPLHDL(ophdl))->		\
1618 		    cmio_##what(IMPLHDL(ophdl)));		\
1619 	}
1620 
1621 /* BEGIN CSTYLED */
1622 CMI_HDL_OPFUNC(vendor, uint_t)
1623 CMI_HDL_OPFUNC(vendorstr, const char *)
1624 CMI_HDL_OPFUNC(family, uint_t)
1625 CMI_HDL_OPFUNC(model, uint_t)
1626 CMI_HDL_OPFUNC(stepping, uint_t)
1627 CMI_HDL_OPFUNC(chipid, uint_t)
1628 CMI_HDL_OPFUNC(procnodeid, uint_t)
1629 CMI_HDL_OPFUNC(coreid, uint_t)
1630 CMI_HDL_OPFUNC(strandid, uint_t)
1631 CMI_HDL_OPFUNC(procnodes_per_pkg, uint_t)
1632 CMI_HDL_OPFUNC(strand_apicid, uint_t)
1633 CMI_HDL_OPFUNC(chiprev, uint32_t)
1634 CMI_HDL_OPFUNC(chiprevstr, const char *)
1635 CMI_HDL_OPFUNC(getsockettype, uint32_t)
1636 CMI_HDL_OPFUNC(getsocketstr, const char *)
1637 CMI_HDL_OPFUNC(logical_id, id_t)
1638 CMI_HDL_OPFUNC(smbiosid, uint16_t)
1639 CMI_HDL_OPFUNC(smb_chipid, uint_t)
1640 CMI_HDL_OPFUNC(smb_bboard, nvlist_t *)
1641 CMI_HDL_OPFUNC(chipsig, uint_t)
1642 /* END CSTYLED */
1643 
1644 boolean_t
1645 cmi_hdl_is_cmt(cmi_hdl_t ophdl)
1646 {
1647 	return (IMPLHDL(ophdl)->cmih_mstrand);
1648 }
1649 
1650 void
1651 cmi_hdl_int(cmi_hdl_t ophdl, int num)
1652 {
1653 	if (HDLOPS(IMPLHDL(ophdl))->cmio_int == NULL)
1654 		return;
1655 
1656 	cmi_hdl_inj_begin(ophdl);
1657 	HDLOPS(IMPLHDL(ophdl))->cmio_int(IMPLHDL(ophdl), num);
1658 	cmi_hdl_inj_end(NULL);
1659 }
1660 
1661 int
1662 cmi_hdl_online(cmi_hdl_t ophdl, int new_status, int *old_status)
1663 {
1664 	return (HDLOPS(IMPLHDL(ophdl))->cmio_online(IMPLHDL(ophdl),
1665 	    new_status, old_status));
1666 }
1667 
1668 #ifndef	__xpv
1669 /*
1670  * Return hardware chip instance; cpuid_get_chipid provides this directly.
1671  */
1672 uint_t
1673 cmi_ntv_hwchipid(cpu_t *cp)
1674 {
1675 	return (cpuid_get_chipid(cp));
1676 }
1677 
1678 /*
1679  * Return hardware node instance; cpuid_get_procnodeid provides this directly.
1680  */
1681 uint_t
1682 cmi_ntv_hwprocnodeid(cpu_t *cp)
1683 {
1684 	return (cpuid_get_procnodeid(cp));
1685 }
1686 
1687 /*
1688  * Return core instance within a single chip.
1689  */
1690 uint_t
1691 cmi_ntv_hwcoreid(cpu_t *cp)
1692 {
1693 	return (cpuid_get_pkgcoreid(cp));
1694 }
1695 
1696 /*
1697  * Return strand number within a single core.  cpuid_get_clogid numbers
1698  * all execution units (strands, or cores in unstranded models) sequentially
1699  * within a single chip.
1700  */
1701 uint_t
1702 cmi_ntv_hwstrandid(cpu_t *cp)
1703 {
1704 	int strands_per_core = cpuid_get_ncpu_per_chip(cp) /
1705 	    cpuid_get_ncore_per_chip(cp);
1706 
1707 	return (cpuid_get_clogid(cp) % strands_per_core);
1708 }
1709 
1710 static void
1711 cmi_ntv_hwdisable_mce_xc(void)
1712 {
1713 	ulong_t cr4;
1714 
1715 	cr4 = getcr4();
1716 	cr4 = cr4 & (~CR4_MCE);
1717 	setcr4(cr4);
1718 }
1719 
1720 void
1721 cmi_ntv_hwdisable_mce(cmi_hdl_t hdl)
1722 {
1723 	cpuset_t	set;
1724 	cmi_hdl_impl_t *thdl = IMPLHDL(hdl);
1725 	cpu_t *cp = HDLPRIV(thdl);
1726 
1727 	if (CPU->cpu_id == cp->cpu_id) {
1728 		cmi_ntv_hwdisable_mce_xc();
1729 	} else {
1730 		CPUSET_ONLY(set, cp->cpu_id);
1731 		xc_call(0, 0, 0, CPUSET2BV(set),
1732 		    (xc_func_t)cmi_ntv_hwdisable_mce_xc);
1733 	}
1734 }
1735 
1736 #endif	/* __xpv */
1737 
1738 void
1739 cmi_hdlconf_rdmsr_nohw(cmi_hdl_t ophdl)
1740 {
1741 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1742 
1743 	hdl->cmih_msrsrc &= ~CMI_MSR_FLAG_RD_HWOK;
1744 }
1745 
1746 void
1747 cmi_hdlconf_wrmsr_nohw(cmi_hdl_t ophdl)
1748 {
1749 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1750 
1751 	hdl->cmih_msrsrc &= ~CMI_MSR_FLAG_WR_HWOK;
1752 }
1753 
1754 cmi_errno_t
1755 cmi_hdl_rdmsr(cmi_hdl_t ophdl, uint_t msr, uint64_t *valp)
1756 {
1757 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1758 
1759 	/*
1760 	 * Regardless of the handle class, we first check for am
1761 	 * interposed value.  In the xVM case you probably want to
1762 	 * place interposed values within the hypervisor itself, but
1763 	 * we still allow interposing them in dom0 for test and bringup
1764 	 * purposes.
1765 	 */
1766 	if ((hdl->cmih_msrsrc & CMI_MSR_FLAG_RD_INTERPOSEOK) &&
1767 	    msri_lookup(hdl, msr, valp))
1768 		return (CMI_SUCCESS);
1769 
1770 	if (HDLOPS(hdl)->cmio_rdmsr == NULL)
1771 		return (CMIERR_NOTSUP);
1772 
1773 	return (HDLOPS(hdl)->cmio_rdmsr(hdl, msr, valp));
1774 }
1775 
1776 cmi_errno_t
1777 cmi_hdl_wrmsr(cmi_hdl_t ophdl, uint_t msr, uint64_t val)
1778 {
1779 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1780 
1781 	/* Invalidate any interposed value */
1782 	msri_rment(hdl, msr);
1783 
1784 	if (HDLOPS(hdl)->cmio_wrmsr == NULL)
1785 		return (CMI_SUCCESS);	/* pretend all is ok */
1786 
1787 	return (HDLOPS(hdl)->cmio_wrmsr(hdl, msr, val));
1788 }
1789 
1790 void
1791 cmi_hdl_enable_mce(cmi_hdl_t ophdl)
1792 {
1793 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1794 	ulong_t cr4;
1795 
1796 	if (HDLOPS(hdl)->cmio_getcr4 == NULL ||
1797 	    HDLOPS(hdl)->cmio_setcr4 == NULL)
1798 		return;
1799 
1800 	cr4 = HDLOPS(hdl)->cmio_getcr4(hdl);
1801 
1802 	HDLOPS(hdl)->cmio_setcr4(hdl, cr4 | CR4_MCE);
1803 }
1804 
1805 void
1806 cmi_hdl_msrinterpose(cmi_hdl_t ophdl, cmi_mca_regs_t *regs, uint_t nregs)
1807 {
1808 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1809 	int i;
1810 
1811 	if (HDLOPS(hdl)->cmio_msrinterpose == NULL)
1812 		return;
1813 
1814 	cmi_hdl_inj_begin(ophdl);
1815 
1816 	for (i = 0; i < nregs; i++, regs++)
1817 		HDLOPS(hdl)->cmio_msrinterpose(hdl, regs->cmr_msrnum,
1818 		    regs->cmr_msrval);
1819 
1820 	cmi_hdl_inj_end(ophdl);
1821 }
1822 
1823 /*ARGSUSED*/
1824 void
1825 cmi_hdl_msrforward(cmi_hdl_t ophdl, cmi_mca_regs_t *regs, uint_t nregs)
1826 {
1827 #ifdef __xpv
1828 	cmi_hdl_impl_t *hdl = IMPLHDL(ophdl);
1829 	int i;
1830 
1831 	for (i = 0; i < nregs; i++, regs++)
1832 		msri_addent(hdl, regs->cmr_msrnum, regs->cmr_msrval);
1833 #endif
1834 }
1835 
1836 
1837 void
1838 cmi_pcird_nohw(void)
1839 {
1840 	cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_RD_HWOK;
1841 }
1842 
1843 void
1844 cmi_pciwr_nohw(void)
1845 {
1846 	cmi_pcicfg_flags &= ~CMI_PCICFG_FLAG_WR_HWOK;
1847 }
1848 
1849 static uint32_t
1850 cmi_pci_get_cmn(int bus, int dev, int func, int reg, int asz,
1851     int *interpose, ddi_acc_handle_t hdl)
1852 {
1853 	uint32_t val;
1854 
1855 	if (cmi_pcicfg_flags & CMI_PCICFG_FLAG_RD_INTERPOSEOK &&
1856 	    pcii_lookup(bus, dev, func, reg, asz, &val)) {
1857 		if (interpose)
1858 			*interpose = 1;
1859 		return (val);
1860 	}
1861 	if (interpose)
1862 		*interpose = 0;
1863 
1864 	if (!(cmi_pcicfg_flags & CMI_PCICFG_FLAG_RD_HWOK))
1865 		return (0);
1866 
1867 	switch (asz) {
1868 	case 1:
1869 		if (hdl)
1870 			val = pci_config_get8(hdl, (off_t)reg);
1871 		else
1872 			val = pci_cfgacc_get8(NULL, PCI_GETBDF(bus, dev, func),
1873 			    reg);
1874 		break;
1875 	case 2:
1876 		if (hdl)
1877 			val = pci_config_get16(hdl, (off_t)reg);
1878 		else
1879 			val = pci_cfgacc_get16(NULL, PCI_GETBDF(bus, dev, func),
1880 			    reg);
1881 		break;
1882 	case 4:
1883 		if (hdl)
1884 			val = pci_config_get32(hdl, (off_t)reg);
1885 		else
1886 			val = pci_cfgacc_get32(NULL, PCI_GETBDF(bus, dev, func),
1887 			    reg);
1888 		break;
1889 	default:
1890 		val = 0;
1891 	}
1892 	return (val);
1893 }
1894 
1895 uint8_t
1896 cmi_pci_getb(int bus, int dev, int func, int reg, int *interpose,
1897     ddi_acc_handle_t hdl)
1898 {
1899 	return ((uint8_t)cmi_pci_get_cmn(bus, dev, func, reg, 1, interpose,
1900 	    hdl));
1901 }
1902 
1903 uint16_t
1904 cmi_pci_getw(int bus, int dev, int func, int reg, int *interpose,
1905     ddi_acc_handle_t hdl)
1906 {
1907 	return ((uint16_t)cmi_pci_get_cmn(bus, dev, func, reg, 2, interpose,
1908 	    hdl));
1909 }
1910 
1911 uint32_t
1912 cmi_pci_getl(int bus, int dev, int func, int reg, int *interpose,
1913     ddi_acc_handle_t hdl)
1914 {
1915 	return (cmi_pci_get_cmn(bus, dev, func, reg, 4, interpose, hdl));
1916 }
1917 
1918 void
1919 cmi_pci_interposeb(int bus, int dev, int func, int reg, uint8_t val)
1920 {
1921 	pcii_addent(bus, dev, func, reg, val, 1);
1922 }
1923 
1924 void
1925 cmi_pci_interposew(int bus, int dev, int func, int reg, uint16_t val)
1926 {
1927 	pcii_addent(bus, dev, func, reg, val, 2);
1928 }
1929 
1930 void
1931 cmi_pci_interposel(int bus, int dev, int func, int reg, uint32_t val)
1932 {
1933 	pcii_addent(bus, dev, func, reg, val, 4);
1934 }
1935 
1936 static void
1937 cmi_pci_put_cmn(int bus, int dev, int func, int reg, int asz,
1938     ddi_acc_handle_t hdl, uint32_t val)
1939 {
1940 	/*
1941 	 * If there is an interposed value for this register invalidate it.
1942 	 */
1943 	pcii_rment(bus, dev, func, reg, asz);
1944 
1945 	if (!(cmi_pcicfg_flags & CMI_PCICFG_FLAG_WR_HWOK))
1946 		return;
1947 
1948 	switch (asz) {
1949 	case 1:
1950 		if (hdl)
1951 			pci_config_put8(hdl, (off_t)reg, (uint8_t)val);
1952 		else
1953 			pci_cfgacc_put8(NULL, PCI_GETBDF(bus, dev, func), reg,
1954 			    (uint8_t)val);
1955 		break;
1956 
1957 	case 2:
1958 		if (hdl)
1959 			pci_config_put16(hdl, (off_t)reg, (uint16_t)val);
1960 		else
1961 			pci_cfgacc_put16(NULL, PCI_GETBDF(bus, dev, func), reg,
1962 			    (uint16_t)val);
1963 		break;
1964 
1965 	case 4:
1966 		if (hdl)
1967 			pci_config_put32(hdl, (off_t)reg, val);
1968 		else
1969 			pci_cfgacc_put32(NULL, PCI_GETBDF(bus, dev, func), reg,
1970 			    val);
1971 		break;
1972 
1973 	default:
1974 		break;
1975 	}
1976 }
1977 
1978 void
1979 cmi_pci_putb(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl,
1980     uint8_t val)
1981 {
1982 	cmi_pci_put_cmn(bus, dev, func, reg, 1, hdl, val);
1983 }
1984 
1985 void
1986 cmi_pci_putw(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl,
1987     uint16_t val)
1988 {
1989 	cmi_pci_put_cmn(bus, dev, func, reg, 2, hdl, val);
1990 }
1991 
1992 void
1993 cmi_pci_putl(int bus, int dev, int func, int reg, ddi_acc_handle_t hdl,
1994     uint32_t val)
1995 {
1996 	cmi_pci_put_cmn(bus, dev, func, reg, 4, hdl, val);
1997 }
1998 
1999 static const struct cmi_hdl_ops cmi_hdl_ops = {
2000 #ifdef __xpv
2001 	/*
2002 	 * CMI_HDL_SOLARIS_xVM_MCA - ops when we are an xVM dom0
2003 	 */
2004 	xpv_vendor,		/* cmio_vendor */
2005 	xpv_vendorstr,		/* cmio_vendorstr */
2006 	xpv_family,		/* cmio_family */
2007 	xpv_model,		/* cmio_model */
2008 	xpv_stepping,		/* cmio_stepping */
2009 	xpv_chipid,		/* cmio_chipid */
2010 	xpv_procnodeid,		/* cmio_procnodeid */
2011 	xpv_coreid,		/* cmio_coreid */
2012 	xpv_strandid,		/* cmio_strandid */
2013 	xpv_procnodes_per_pkg,	/* cmio_procnodes_per_pkg */
2014 	xpv_strand_apicid,	/* cmio_strand_apicid */
2015 	xpv_chiprev,		/* cmio_chiprev */
2016 	xpv_chiprevstr,		/* cmio_chiprevstr */
2017 	xpv_getsockettype,	/* cmio_getsockettype */
2018 	xpv_getsocketstr,	/* cmio_getsocketstr */
2019 	xpv_chipsig,		/* cmio_chipsig */
2020 	xpv_logical_id,		/* cmio_logical_id */
2021 	NULL,			/* cmio_getcr4 */
2022 	NULL,			/* cmio_setcr4 */
2023 	xpv_rdmsr,		/* cmio_rdmsr */
2024 	xpv_wrmsr,		/* cmio_wrmsr */
2025 	xpv_msrinterpose,	/* cmio_msrinterpose */
2026 	xpv_int,		/* cmio_int */
2027 	xpv_online,		/* cmio_online */
2028 	xpv_smbiosid,		/* cmio_smbiosid */
2029 	xpv_smb_chipid,		/* cmio_smb_chipid */
2030 	xpv_smb_bboard		/* cmio_smb_bboard */
2031 
2032 #else	/* __xpv */
2033 
2034 	/*
2035 	 * CMI_HDL_NATIVE - ops when apparently running on bare-metal
2036 	 */
2037 	ntv_vendor,		/* cmio_vendor */
2038 	ntv_vendorstr,		/* cmio_vendorstr */
2039 	ntv_family,		/* cmio_family */
2040 	ntv_model,		/* cmio_model */
2041 	ntv_stepping,		/* cmio_stepping */
2042 	ntv_chipid,		/* cmio_chipid */
2043 	ntv_procnodeid,		/* cmio_procnodeid */
2044 	ntv_coreid,		/* cmio_coreid */
2045 	ntv_strandid,		/* cmio_strandid */
2046 	ntv_procnodes_per_pkg,	/* cmio_procnodes_per_pkg */
2047 	ntv_strand_apicid,	/* cmio_strand_apicid */
2048 	ntv_chiprev,		/* cmio_chiprev */
2049 	ntv_chiprevstr,		/* cmio_chiprevstr */
2050 	ntv_getsockettype,	/* cmio_getsockettype */
2051 	ntv_getsocketstr,	/* cmio_getsocketstr */
2052 	ntv_chipsig,		/* cmio_chipsig */
2053 	ntv_logical_id,		/* cmio_logical_id */
2054 	ntv_getcr4,		/* cmio_getcr4 */
2055 	ntv_setcr4,		/* cmio_setcr4 */
2056 	ntv_rdmsr,		/* cmio_rdmsr */
2057 	ntv_wrmsr,		/* cmio_wrmsr */
2058 	ntv_msrinterpose,	/* cmio_msrinterpose */
2059 	ntv_int,		/* cmio_int */
2060 	ntv_online,		/* cmio_online */
2061 	ntv_smbiosid,		/* cmio_smbiosid */
2062 	ntv_smb_chipid,		/* cmio_smb_chipid */
2063 	ntv_smb_bboard		/* cmio_smb_bboard */
2064 #endif
2065 };
2066