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