xref: /titanic_51/usr/src/uts/sun4u/io/px/px_lib4u.c (revision 672986541be54a7a471bb088e60780c37e371d7e)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/kmem.h>
30 #include <sys/conf.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/fm/protocol.h>
34 #include <sys/fm/util.h>
35 #include <sys/modctl.h>
36 #include <sys/disp.h>
37 #include <sys/stat.h>
38 #include <sys/ddi_impldefs.h>
39 #include <sys/vmem.h>
40 #include <sys/iommutsb.h>
41 #include <sys/cpuvar.h>
42 #include <sys/ivintr.h>
43 #include <sys/byteorder.h>
44 #include <sys/hotplug/pci/pciehpc.h>
45 #include <sys/spl.h>
46 #include <px_obj.h>
47 #include <pcie_pwr.h>
48 #include "px_tools_var.h"
49 #include <px_regs.h>
50 #include <px_csr.h>
51 #include <sys/machsystm.h>
52 #include "px_lib4u.h"
53 #include "px_err.h"
54 #include "oberon_regs.h"
55 
56 #pragma weak jbus_stst_order
57 
58 extern void jbus_stst_order();
59 
60 ulong_t px_mmu_dvma_end = 0xfffffffful;
61 uint_t px_ranges_phi_mask = 0xfffffffful;
62 uint64_t *px_oberon_ubc_scratch_regs;
63 uint64_t px_paddr_mask;
64 
65 static int px_goto_l23ready(px_t *px_p);
66 static int px_goto_l0(px_t *px_p);
67 static int px_pre_pwron_check(px_t *px_p);
68 static uint32_t px_identity_init(px_t *px_p);
69 static boolean_t px_cpr_callb(void *arg, int code);
70 static uint_t px_cb_intr(caddr_t arg);
71 
72 /*
73  * px_lib_map_registers
74  *
75  * This function is called from the attach routine to map the registers
76  * accessed by this driver.
77  *
78  * used by: px_attach()
79  *
80  * return value: DDI_FAILURE on failure
81  */
82 int
83 px_lib_map_regs(pxu_t *pxu_p, dev_info_t *dip)
84 {
85 	ddi_device_acc_attr_t	attr;
86 	px_reg_bank_t		reg_bank = PX_REG_CSR;
87 
88 	DBG(DBG_ATTACH, dip, "px_lib_map_regs: pxu_p:0x%p, dip 0x%p\n",
89 		pxu_p, dip);
90 
91 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
92 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
93 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
94 
95 	/*
96 	 * PCI CSR Base
97 	 */
98 	if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank],
99 	    0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) {
100 		goto fail;
101 	}
102 
103 	reg_bank++;
104 
105 	/*
106 	 * XBUS CSR Base
107 	 */
108 	if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank],
109 	    0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) {
110 		goto fail;
111 	}
112 
113 	pxu_p->px_address[reg_bank] -= FIRE_CONTROL_STATUS;
114 
115 done:
116 	for (; reg_bank >= PX_REG_CSR; reg_bank--) {
117 		DBG(DBG_ATTACH, dip, "reg_bank 0x%x address 0x%p\n",
118 		    reg_bank, pxu_p->px_address[reg_bank]);
119 	}
120 
121 	return (DDI_SUCCESS);
122 
123 fail:
124 	cmn_err(CE_WARN, "%s%d: unable to map reg entry %d\n",
125 	    ddi_driver_name(dip), ddi_get_instance(dip), reg_bank);
126 
127 	for (reg_bank--; reg_bank >= PX_REG_CSR; reg_bank--) {
128 		pxu_p->px_address[reg_bank] = NULL;
129 		ddi_regs_map_free(&pxu_p->px_ac[reg_bank]);
130 	}
131 
132 	return (DDI_FAILURE);
133 }
134 
135 /*
136  * px_lib_unmap_regs:
137  *
138  * This routine unmaps the registers mapped by map_px_registers.
139  *
140  * used by: px_detach(), and error conditions in px_attach()
141  *
142  * return value: none
143  */
144 void
145 px_lib_unmap_regs(pxu_t *pxu_p)
146 {
147 	int i;
148 
149 	for (i = 0; i < PX_REG_MAX; i++) {
150 		if (pxu_p->px_ac[i])
151 			ddi_regs_map_free(&pxu_p->px_ac[i]);
152 	}
153 }
154 
155 int
156 px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl)
157 {
158 
159 	caddr_t			xbc_csr_base, csr_base;
160 	px_dvma_range_prop_t	px_dvma_range;
161 	pxu_t			*pxu_p;
162 	uint8_t			chip_mask;
163 	px_t			*px_p = DIP_TO_STATE(dip);
164 	px_chip_type_t		chip_type = px_identity_init(px_p);
165 
166 	DBG(DBG_ATTACH, dip, "px_lib_dev_init: dip 0x%p", dip);
167 
168 	if (chip_type == PX_CHIP_UNIDENTIFIED) {
169 		cmn_err(CE_WARN, "%s%d: Unrecognized Hardware Version\n",
170 		    NAMEINST(dip));
171 		return (DDI_FAILURE);
172 	}
173 
174 	chip_mask = BITMASK(chip_type);
175 	px_paddr_mask = (chip_type == PX_CHIP_FIRE) ? MMU_FIRE_PADDR_MASK :
176 	    MMU_OBERON_PADDR_MASK;
177 
178 	/*
179 	 * Allocate platform specific structure and link it to
180 	 * the px state structure.
181 	 */
182 	pxu_p = kmem_zalloc(sizeof (pxu_t), KM_SLEEP);
183 	pxu_p->chip_type = chip_type;
184 	pxu_p->portid  = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
185 	    "portid", -1);
186 
187 	/* Map in the registers */
188 	if (px_lib_map_regs(pxu_p, dip) == DDI_FAILURE) {
189 		kmem_free(pxu_p, sizeof (pxu_t));
190 
191 		return (DDI_FAILURE);
192 	}
193 
194 	xbc_csr_base = (caddr_t)pxu_p->px_address[PX_REG_XBC];
195 	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
196 
197 	pxu_p->tsb_cookie = iommu_tsb_alloc(pxu_p->portid);
198 	pxu_p->tsb_size = iommu_tsb_cookie_to_size(pxu_p->tsb_cookie);
199 	pxu_p->tsb_vaddr = iommu_tsb_cookie_to_va(pxu_p->tsb_cookie);
200 
201 	pxu_p->tsb_paddr = va_to_pa(pxu_p->tsb_vaddr);
202 
203 	/*
204 	 * Create "virtual-dma" property to support child devices
205 	 * needing to know DVMA range.
206 	 */
207 	px_dvma_range.dvma_base = (uint32_t)px_mmu_dvma_end + 1
208 	    - ((pxu_p->tsb_size >> 3) << MMU_PAGE_SHIFT);
209 	px_dvma_range.dvma_len = (uint32_t)
210 	    px_mmu_dvma_end - px_dvma_range.dvma_base + 1;
211 
212 	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
213 		"virtual-dma", (caddr_t)&px_dvma_range,
214 		sizeof (px_dvma_range_prop_t));
215 	/*
216 	 * Initilize all fire hardware specific blocks.
217 	 */
218 	hvio_cb_init(xbc_csr_base, pxu_p);
219 	hvio_ib_init(csr_base, pxu_p);
220 	hvio_pec_init(csr_base, pxu_p);
221 	hvio_mmu_init(csr_base, pxu_p);
222 
223 	px_p->px_plat_p = (void *)pxu_p;
224 
225 	/*
226 	 * Initialize all the interrupt handlers
227 	 */
228 	switch (PX_CHIP_TYPE(pxu_p)) {
229 	case PX_CHIP_OBERON:
230 		/*
231 		 * Oberon hotplug uses SPARE3 field in ILU Error Log Enable
232 		 * register to indicate the status of leaf reset,
233 		 * we need to preserve the value of this bit, and keep it in
234 		 * px_ilu_log_mask to reflect the state of the bit
235 		 */
236 		if (CSR_BR(csr_base, ILU_ERROR_LOG_ENABLE, SPARE3))
237 			px_ilu_log_mask |= (1ull <<
238 			    ILU_ERROR_LOG_ENABLE_SPARE3);
239 		else
240 			px_ilu_log_mask &= ~(1ull <<
241 			    ILU_ERROR_LOG_ENABLE_SPARE3);
242 
243 		px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE);
244 		px_fabric_die_rc_ue |= PCIE_AER_UCE_UC;
245 		break;
246 
247 	case PX_CHIP_FIRE:
248 		px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE);
249 		break;
250 
251 	default:
252 		cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n",
253 		    ddi_driver_name(dip), ddi_get_instance(dip));
254 		return (DDI_FAILURE);
255 	}
256 
257 	/* Initilize device handle */
258 	*dev_hdl = (devhandle_t)csr_base;
259 
260 	DBG(DBG_ATTACH, dip, "px_lib_dev_init: dev_hdl 0x%llx\n", *dev_hdl);
261 
262 	return (DDI_SUCCESS);
263 }
264 
265 int
266 px_lib_dev_fini(dev_info_t *dip)
267 {
268 	caddr_t			csr_base;
269 	uint8_t			chip_mask;
270 	px_t			*px_p = DIP_TO_STATE(dip);
271 	pxu_t			*pxu_p = (pxu_t *)px_p->px_plat_p;
272 
273 	DBG(DBG_DETACH, dip, "px_lib_dev_fini: dip 0x%p\n", dip);
274 
275 	/*
276 	 * Deinitialize all the interrupt handlers
277 	 */
278 	switch (PX_CHIP_TYPE(pxu_p)) {
279 	case PX_CHIP_OBERON:
280 	case PX_CHIP_FIRE:
281 		chip_mask = BITMASK(PX_CHIP_TYPE(pxu_p));
282 		csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
283 		px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_DISABLE);
284 		break;
285 
286 	default:
287 		cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n",
288 		    ddi_driver_name(dip), ddi_get_instance(dip));
289 		return (DDI_FAILURE);
290 	}
291 
292 	iommu_tsb_free(pxu_p->tsb_cookie);
293 
294 	px_lib_unmap_regs((pxu_t *)px_p->px_plat_p);
295 	kmem_free(px_p->px_plat_p, sizeof (pxu_t));
296 	px_p->px_plat_p = NULL;
297 
298 	return (DDI_SUCCESS);
299 }
300 
301 /*ARGSUSED*/
302 int
303 px_lib_intr_devino_to_sysino(dev_info_t *dip, devino_t devino,
304     sysino_t *sysino)
305 {
306 	px_t	*px_p = DIP_TO_STATE(dip);
307 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
308 	uint64_t	ret;
309 
310 	DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: dip 0x%p "
311 	    "devino 0x%x\n", dip, devino);
312 
313 	if ((ret = hvio_intr_devino_to_sysino(DIP_TO_HANDLE(dip),
314 	    pxu_p, devino, sysino)) != H_EOK) {
315 		DBG(DBG_LIB_INT, dip,
316 		    "hvio_intr_devino_to_sysino failed, ret 0x%lx\n", ret);
317 		return (DDI_FAILURE);
318 	}
319 
320 	DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: sysino 0x%llx\n",
321 	    *sysino);
322 
323 	return (DDI_SUCCESS);
324 }
325 
326 /*ARGSUSED*/
327 int
328 px_lib_intr_getvalid(dev_info_t *dip, sysino_t sysino,
329     intr_valid_state_t *intr_valid_state)
330 {
331 	uint64_t	ret;
332 
333 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: dip 0x%p sysino 0x%llx\n",
334 	    dip, sysino);
335 
336 	if ((ret = hvio_intr_getvalid(DIP_TO_HANDLE(dip),
337 	    sysino, intr_valid_state)) != H_EOK) {
338 		DBG(DBG_LIB_INT, dip, "hvio_intr_getvalid failed, ret 0x%lx\n",
339 		    ret);
340 		return (DDI_FAILURE);
341 	}
342 
343 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: intr_valid_state 0x%x\n",
344 	    *intr_valid_state);
345 
346 	return (DDI_SUCCESS);
347 }
348 
349 /*ARGSUSED*/
350 int
351 px_lib_intr_setvalid(dev_info_t *dip, sysino_t sysino,
352     intr_valid_state_t intr_valid_state)
353 {
354 	uint64_t	ret;
355 
356 	DBG(DBG_LIB_INT, dip, "px_lib_intr_setvalid: dip 0x%p sysino 0x%llx "
357 	    "intr_valid_state 0x%x\n", dip, sysino, intr_valid_state);
358 
359 	if ((ret = hvio_intr_setvalid(DIP_TO_HANDLE(dip),
360 	    sysino, intr_valid_state)) != H_EOK) {
361 		DBG(DBG_LIB_INT, dip, "hvio_intr_setvalid failed, ret 0x%lx\n",
362 		    ret);
363 		return (DDI_FAILURE);
364 	}
365 
366 	return (DDI_SUCCESS);
367 }
368 
369 /*ARGSUSED*/
370 int
371 px_lib_intr_getstate(dev_info_t *dip, sysino_t sysino,
372     intr_state_t *intr_state)
373 {
374 	uint64_t	ret;
375 
376 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: dip 0x%p sysino 0x%llx\n",
377 	    dip, sysino);
378 
379 	if ((ret = hvio_intr_getstate(DIP_TO_HANDLE(dip),
380 	    sysino, intr_state)) != H_EOK) {
381 		DBG(DBG_LIB_INT, dip, "hvio_intr_getstate failed, ret 0x%lx\n",
382 		    ret);
383 		return (DDI_FAILURE);
384 	}
385 
386 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: intr_state 0x%x\n",
387 	    *intr_state);
388 
389 	return (DDI_SUCCESS);
390 }
391 
392 /*ARGSUSED*/
393 int
394 px_lib_intr_setstate(dev_info_t *dip, sysino_t sysino,
395     intr_state_t intr_state)
396 {
397 	uint64_t	ret;
398 
399 	DBG(DBG_LIB_INT, dip, "px_lib_intr_setstate: dip 0x%p sysino 0x%llx "
400 	    "intr_state 0x%x\n", dip, sysino, intr_state);
401 
402 	if ((ret = hvio_intr_setstate(DIP_TO_HANDLE(dip),
403 	    sysino, intr_state)) != H_EOK) {
404 		DBG(DBG_LIB_INT, dip, "hvio_intr_setstate failed, ret 0x%lx\n",
405 		    ret);
406 		return (DDI_FAILURE);
407 	}
408 
409 	return (DDI_SUCCESS);
410 }
411 
412 /*ARGSUSED*/
413 int
414 px_lib_intr_gettarget(dev_info_t *dip, sysino_t sysino, cpuid_t *cpuid)
415 {
416 	px_t		*px_p = DIP_TO_STATE(dip);
417 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
418 	uint64_t	ret;
419 
420 	DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: dip 0x%p sysino 0x%llx\n",
421 	    dip, sysino);
422 
423 	if ((ret = hvio_intr_gettarget(DIP_TO_HANDLE(dip), pxu_p,
424 	    sysino, cpuid)) != H_EOK) {
425 		DBG(DBG_LIB_INT, dip, "hvio_intr_gettarget failed, ret 0x%lx\n",
426 		    ret);
427 		return (DDI_FAILURE);
428 	}
429 
430 	DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: cpuid 0x%x\n", cpuid);
431 
432 	return (DDI_SUCCESS);
433 }
434 
435 /*ARGSUSED*/
436 int
437 px_lib_intr_settarget(dev_info_t *dip, sysino_t sysino, cpuid_t cpuid)
438 {
439 	px_t		*px_p = DIP_TO_STATE(dip);
440 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
441 	uint64_t	ret;
442 
443 	DBG(DBG_LIB_INT, dip, "px_lib_intr_settarget: dip 0x%p sysino 0x%llx "
444 	    "cpuid 0x%x\n", dip, sysino, cpuid);
445 
446 	if ((ret = hvio_intr_settarget(DIP_TO_HANDLE(dip), pxu_p,
447 	    sysino, cpuid)) != H_EOK) {
448 		DBG(DBG_LIB_INT, dip, "hvio_intr_settarget failed, ret 0x%lx\n",
449 		    ret);
450 		return (DDI_FAILURE);
451 	}
452 
453 	return (DDI_SUCCESS);
454 }
455 
456 /*ARGSUSED*/
457 int
458 px_lib_intr_reset(dev_info_t *dip)
459 {
460 	devino_t	ino;
461 	sysino_t	sysino;
462 
463 	DBG(DBG_LIB_INT, dip, "px_lib_intr_reset: dip 0x%p\n", dip);
464 
465 	/* Reset all Interrupts */
466 	for (ino = 0; ino < INTERRUPT_MAPPING_ENTRIES; ino++) {
467 		if (px_lib_intr_devino_to_sysino(dip, ino,
468 		    &sysino) != DDI_SUCCESS)
469 			return (BF_FATAL);
470 
471 		if (px_lib_intr_setstate(dip, sysino,
472 		    INTR_IDLE_STATE) != DDI_SUCCESS)
473 			return (BF_FATAL);
474 	}
475 
476 	return (BF_NONE);
477 }
478 
479 /*ARGSUSED*/
480 int
481 px_lib_iommu_map(dev_info_t *dip, tsbid_t tsbid, pages_t pages,
482     io_attributes_t attr, void *addr, size_t pfn_index, int flags)
483 {
484 	px_t		*px_p = DIP_TO_STATE(dip);
485 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
486 	uint64_t	ret;
487 
488 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_map: dip 0x%p tsbid 0x%llx "
489 	    "pages 0x%x attr 0x%x addr 0x%p pfn_index 0x%llx flags 0x%x\n",
490 	    dip, tsbid, pages, attr, addr, pfn_index, flags);
491 
492 	if ((ret = hvio_iommu_map(px_p->px_dev_hdl, pxu_p, tsbid, pages,
493 	    attr, addr, pfn_index, flags)) != H_EOK) {
494 		DBG(DBG_LIB_DMA, dip,
495 		    "px_lib_iommu_map failed, ret 0x%lx\n", ret);
496 		return (DDI_FAILURE);
497 	}
498 
499 	return (DDI_SUCCESS);
500 }
501 
502 /*ARGSUSED*/
503 int
504 px_lib_iommu_demap(dev_info_t *dip, tsbid_t tsbid, pages_t pages)
505 {
506 	px_t		*px_p = DIP_TO_STATE(dip);
507 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
508 	uint64_t	ret;
509 
510 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_demap: dip 0x%p tsbid 0x%llx "
511 	    "pages 0x%x\n", dip, tsbid, pages);
512 
513 	if ((ret = hvio_iommu_demap(px_p->px_dev_hdl, pxu_p, tsbid, pages))
514 	    != H_EOK) {
515 		DBG(DBG_LIB_DMA, dip,
516 		    "px_lib_iommu_demap failed, ret 0x%lx\n", ret);
517 
518 		return (DDI_FAILURE);
519 	}
520 
521 	return (DDI_SUCCESS);
522 }
523 
524 /*ARGSUSED*/
525 int
526 px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, io_attributes_t *attr_p,
527     r_addr_t *r_addr_p)
528 {
529 	px_t	*px_p = DIP_TO_STATE(dip);
530 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
531 	uint64_t	ret;
532 
533 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: dip 0x%p tsbid 0x%llx\n",
534 	    dip, tsbid);
535 
536 	if ((ret = hvio_iommu_getmap(DIP_TO_HANDLE(dip), pxu_p, tsbid,
537 	    attr_p, r_addr_p)) != H_EOK) {
538 		DBG(DBG_LIB_DMA, dip,
539 		    "hvio_iommu_getmap failed, ret 0x%lx\n", ret);
540 
541 		return ((ret == H_ENOMAP) ? DDI_DMA_NOMAPPING:DDI_FAILURE);
542 	}
543 
544 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: attr 0x%x r_addr 0x%llx\n",
545 	    *attr_p, *r_addr_p);
546 
547 	return (DDI_SUCCESS);
548 }
549 
550 
551 /*
552  * Checks dma attributes against system bypass ranges
553  * The bypass range is determined by the hardware. Return them so the
554  * common code can do generic checking against them.
555  */
556 /*ARGSUSED*/
557 int
558 px_lib_dma_bypass_rngchk(dev_info_t *dip, ddi_dma_attr_t *attr_p,
559     uint64_t *lo_p, uint64_t *hi_p)
560 {
561 	px_t	*px_p = DIP_TO_STATE(dip);
562 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
563 
564 	*lo_p = hvio_get_bypass_base(pxu_p);
565 	*hi_p = hvio_get_bypass_end(pxu_p);
566 
567 	return (DDI_SUCCESS);
568 }
569 
570 
571 /*ARGSUSED*/
572 int
573 px_lib_iommu_getbypass(dev_info_t *dip, r_addr_t ra, io_attributes_t attr,
574     io_addr_t *io_addr_p)
575 {
576 	uint64_t	ret;
577 	px_t	*px_p = DIP_TO_STATE(dip);
578 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
579 
580 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: dip 0x%p ra 0x%llx "
581 	    "attr 0x%x\n", dip, ra, attr);
582 
583 	if ((ret = hvio_iommu_getbypass(DIP_TO_HANDLE(dip), pxu_p, ra,
584 	    attr, io_addr_p)) != H_EOK) {
585 		DBG(DBG_LIB_DMA, dip,
586 		    "hvio_iommu_getbypass failed, ret 0x%lx\n", ret);
587 		return (DDI_FAILURE);
588 	}
589 
590 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: io_addr 0x%llx\n",
591 	    *io_addr_p);
592 
593 	return (DDI_SUCCESS);
594 }
595 
596 /*
597  * bus dma sync entry point.
598  */
599 /*ARGSUSED*/
600 int
601 px_lib_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
602     off_t off, size_t len, uint_t cache_flags)
603 {
604 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
605 	px_t	*px_p = DIP_TO_STATE(dip);
606 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
607 
608 	DBG(DBG_LIB_DMA, dip, "px_lib_dma_sync: dip 0x%p rdip 0x%p "
609 	    "handle 0x%llx off 0x%x len 0x%x flags 0x%x\n",
610 	    dip, rdip, handle, off, len, cache_flags);
611 
612 	/*
613 	 * No flush needed for Oberon
614 	 */
615 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON)
616 		return (DDI_SUCCESS);
617 
618 	/*
619 	 * jbus_stst_order is found only in certain cpu modules.
620 	 * Just return success if not present.
621 	 */
622 	if (&jbus_stst_order == NULL)
623 		return (DDI_SUCCESS);
624 
625 	if (!(mp->dmai_flags & PX_DMAI_FLAGS_INUSE)) {
626 		cmn_err(CE_WARN, "%s%d: Unbound dma handle %p.",
627 		    ddi_driver_name(rdip), ddi_get_instance(rdip), (void *)mp);
628 
629 		return (DDI_FAILURE);
630 	}
631 
632 	if (mp->dmai_flags & PX_DMAI_FLAGS_NOSYNC)
633 		return (DDI_SUCCESS);
634 
635 	/*
636 	 * No flush needed when sending data from memory to device.
637 	 * Nothing to do to "sync" memory to what device would already see.
638 	 */
639 	if (!(mp->dmai_rflags & DDI_DMA_READ) ||
640 	    ((cache_flags & PX_DMA_SYNC_DDI_FLAGS) == DDI_DMA_SYNC_FORDEV))
641 		return (DDI_SUCCESS);
642 
643 	/*
644 	 * Perform necessary cpu workaround to ensure jbus ordering.
645 	 * CPU's internal "invalidate FIFOs" are flushed.
646 	 */
647 
648 #if !defined(lint)
649 	kpreempt_disable();
650 #endif
651 	jbus_stst_order();
652 #if !defined(lint)
653 	kpreempt_enable();
654 #endif
655 	return (DDI_SUCCESS);
656 }
657 
658 /*
659  * MSIQ Functions:
660  */
661 /*ARGSUSED*/
662 int
663 px_lib_msiq_init(dev_info_t *dip)
664 {
665 	px_t		*px_p = DIP_TO_STATE(dip);
666 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
667 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
668 	px_dvma_addr_t	pg_index;
669 	size_t		size;
670 	int		ret;
671 
672 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_init: dip 0x%p\n", dip);
673 
674 	/*
675 	 * Map the EQ memory into the Fire MMU (has to be 512KB aligned)
676 	 * and then initialize the base address register.
677 	 *
678 	 * Allocate entries from Fire IOMMU so that the resulting address
679 	 * is properly aligned.  Calculate the index of the first allocated
680 	 * entry.  Note: The size of the mapping is assumed to be a multiple
681 	 * of the page size.
682 	 */
683 	size = msiq_state_p->msiq_cnt *
684 	    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
685 
686 	pxu_p->msiq_mapped_p = vmem_xalloc(px_p->px_mmu_p->mmu_dvma_map,
687 	    size, (512 * 1024), 0, 0, NULL, NULL, VM_NOSLEEP | VM_BESTFIT);
688 
689 	if (pxu_p->msiq_mapped_p == NULL)
690 		return (DDI_FAILURE);
691 
692 	pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p,
693 	    MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p));
694 
695 	if ((ret = px_lib_iommu_map(px_p->px_dip, PCI_TSBID(0, pg_index),
696 	    MMU_BTOP(size), PCI_MAP_ATTR_WRITE, msiq_state_p->msiq_buf_p,
697 	    0, MMU_MAP_BUF)) != DDI_SUCCESS) {
698 		DBG(DBG_LIB_MSIQ, dip,
699 		    "hvio_msiq_init failed, ret 0x%lx\n", ret);
700 
701 		(void) px_lib_msiq_fini(dip);
702 		return (DDI_FAILURE);
703 	}
704 
705 	(void) hvio_msiq_init(DIP_TO_HANDLE(dip), pxu_p);
706 
707 	return (DDI_SUCCESS);
708 }
709 
710 /*ARGSUSED*/
711 int
712 px_lib_msiq_fini(dev_info_t *dip)
713 {
714 	px_t		*px_p = DIP_TO_STATE(dip);
715 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
716 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
717 	px_dvma_addr_t	pg_index;
718 	size_t		size;
719 
720 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_fini: dip 0x%p\n", dip);
721 
722 	/*
723 	 * Unmap and free the EQ memory that had been mapped
724 	 * into the Fire IOMMU.
725 	 */
726 	size = msiq_state_p->msiq_cnt *
727 	    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
728 
729 	pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p,
730 	    MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p));
731 
732 	(void) px_lib_iommu_demap(px_p->px_dip,
733 	    PCI_TSBID(0, pg_index), MMU_BTOP(size));
734 
735 	/* Free the entries from the Fire MMU */
736 	vmem_xfree(px_p->px_mmu_p->mmu_dvma_map,
737 	    (void *)pxu_p->msiq_mapped_p, size);
738 
739 	return (DDI_SUCCESS);
740 }
741 
742 /*ARGSUSED*/
743 int
744 px_lib_msiq_info(dev_info_t *dip, msiqid_t msiq_id, r_addr_t *ra_p,
745     uint_t *msiq_rec_cnt_p)
746 {
747 	px_t		*px_p = DIP_TO_STATE(dip);
748 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
749 	size_t		msiq_size;
750 
751 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: dip 0x%p msiq_id 0x%x\n",
752 	    dip, msiq_id);
753 
754 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
755 	ra_p = (r_addr_t *)((caddr_t)msiq_state_p->msiq_buf_p +
756 	    (msiq_id * msiq_size));
757 
758 	*msiq_rec_cnt_p = msiq_state_p->msiq_rec_cnt;
759 
760 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: ra_p 0x%p msiq_rec_cnt 0x%x\n",
761 	    ra_p, *msiq_rec_cnt_p);
762 
763 	return (DDI_SUCCESS);
764 }
765 
766 /*ARGSUSED*/
767 int
768 px_lib_msiq_getvalid(dev_info_t *dip, msiqid_t msiq_id,
769     pci_msiq_valid_state_t *msiq_valid_state)
770 {
771 	uint64_t	ret;
772 
773 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: dip 0x%p msiq_id 0x%x\n",
774 	    dip, msiq_id);
775 
776 	if ((ret = hvio_msiq_getvalid(DIP_TO_HANDLE(dip),
777 	    msiq_id, msiq_valid_state)) != H_EOK) {
778 		DBG(DBG_LIB_MSIQ, dip,
779 		    "hvio_msiq_getvalid failed, ret 0x%lx\n", ret);
780 		return (DDI_FAILURE);
781 	}
782 
783 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: msiq_valid_state 0x%x\n",
784 	    *msiq_valid_state);
785 
786 	return (DDI_SUCCESS);
787 }
788 
789 /*ARGSUSED*/
790 int
791 px_lib_msiq_setvalid(dev_info_t *dip, msiqid_t msiq_id,
792     pci_msiq_valid_state_t msiq_valid_state)
793 {
794 	uint64_t	ret;
795 
796 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setvalid: dip 0x%p msiq_id 0x%x "
797 	    "msiq_valid_state 0x%x\n", dip, msiq_id, msiq_valid_state);
798 
799 	if ((ret = hvio_msiq_setvalid(DIP_TO_HANDLE(dip),
800 	    msiq_id, msiq_valid_state)) != H_EOK) {
801 		DBG(DBG_LIB_MSIQ, dip,
802 		    "hvio_msiq_setvalid failed, ret 0x%lx\n", ret);
803 		return (DDI_FAILURE);
804 	}
805 
806 	return (DDI_SUCCESS);
807 }
808 
809 /*ARGSUSED*/
810 int
811 px_lib_msiq_getstate(dev_info_t *dip, msiqid_t msiq_id,
812     pci_msiq_state_t *msiq_state)
813 {
814 	uint64_t	ret;
815 
816 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: dip 0x%p msiq_id 0x%x\n",
817 	    dip, msiq_id);
818 
819 	if ((ret = hvio_msiq_getstate(DIP_TO_HANDLE(dip),
820 	    msiq_id, msiq_state)) != H_EOK) {
821 		DBG(DBG_LIB_MSIQ, dip,
822 		    "hvio_msiq_getstate failed, ret 0x%lx\n", ret);
823 		return (DDI_FAILURE);
824 	}
825 
826 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: msiq_state 0x%x\n",
827 	    *msiq_state);
828 
829 	return (DDI_SUCCESS);
830 }
831 
832 /*ARGSUSED*/
833 int
834 px_lib_msiq_setstate(dev_info_t *dip, msiqid_t msiq_id,
835     pci_msiq_state_t msiq_state)
836 {
837 	uint64_t	ret;
838 
839 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setstate: dip 0x%p msiq_id 0x%x "
840 	    "msiq_state 0x%x\n", dip, msiq_id, msiq_state);
841 
842 	if ((ret = hvio_msiq_setstate(DIP_TO_HANDLE(dip),
843 	    msiq_id, msiq_state)) != H_EOK) {
844 		DBG(DBG_LIB_MSIQ, dip,
845 		    "hvio_msiq_setstate failed, ret 0x%lx\n", ret);
846 		return (DDI_FAILURE);
847 	}
848 
849 	return (DDI_SUCCESS);
850 }
851 
852 /*ARGSUSED*/
853 int
854 px_lib_msiq_gethead(dev_info_t *dip, msiqid_t msiq_id,
855     msiqhead_t *msiq_head)
856 {
857 	uint64_t	ret;
858 
859 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: dip 0x%p msiq_id 0x%x\n",
860 	    dip, msiq_id);
861 
862 	if ((ret = hvio_msiq_gethead(DIP_TO_HANDLE(dip),
863 	    msiq_id, msiq_head)) != H_EOK) {
864 		DBG(DBG_LIB_MSIQ, dip,
865 		    "hvio_msiq_gethead failed, ret 0x%lx\n", ret);
866 		return (DDI_FAILURE);
867 	}
868 
869 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: msiq_head 0x%x\n",
870 	    *msiq_head);
871 
872 	return (DDI_SUCCESS);
873 }
874 
875 /*ARGSUSED*/
876 int
877 px_lib_msiq_sethead(dev_info_t *dip, msiqid_t msiq_id,
878     msiqhead_t msiq_head)
879 {
880 	uint64_t	ret;
881 
882 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_sethead: dip 0x%p msiq_id 0x%x "
883 	    "msiq_head 0x%x\n", dip, msiq_id, msiq_head);
884 
885 	if ((ret = hvio_msiq_sethead(DIP_TO_HANDLE(dip),
886 	    msiq_id, msiq_head)) != H_EOK) {
887 		DBG(DBG_LIB_MSIQ, dip,
888 		    "hvio_msiq_sethead failed, ret 0x%lx\n", ret);
889 		return (DDI_FAILURE);
890 	}
891 
892 	return (DDI_SUCCESS);
893 }
894 
895 /*ARGSUSED*/
896 int
897 px_lib_msiq_gettail(dev_info_t *dip, msiqid_t msiq_id,
898     msiqtail_t *msiq_tail)
899 {
900 	uint64_t	ret;
901 
902 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: dip 0x%p msiq_id 0x%x\n",
903 	    dip, msiq_id);
904 
905 	if ((ret = hvio_msiq_gettail(DIP_TO_HANDLE(dip),
906 	    msiq_id, msiq_tail)) != H_EOK) {
907 		DBG(DBG_LIB_MSIQ, dip,
908 		    "hvio_msiq_gettail failed, ret 0x%lx\n", ret);
909 		return (DDI_FAILURE);
910 	}
911 
912 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: msiq_tail 0x%x\n",
913 	    *msiq_tail);
914 
915 	return (DDI_SUCCESS);
916 }
917 
918 /*ARGSUSED*/
919 void
920 px_lib_get_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p,
921     msiq_rec_t *msiq_rec_p)
922 {
923 	eq_rec_t	*eq_rec_p = (eq_rec_t *)msiq_head_p;
924 
925 	DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p eq_rec_p 0x%p\n",
926 	    dip, eq_rec_p);
927 
928 	if (!eq_rec_p->eq_rec_fmt_type) {
929 		/* Set msiq_rec_type to zero */
930 		msiq_rec_p->msiq_rec_type = 0;
931 
932 		return;
933 	}
934 
935 	DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: EQ RECORD, "
936 	    "eq_rec_rid 0x%llx eq_rec_fmt_type 0x%llx "
937 	    "eq_rec_len 0x%llx eq_rec_addr0 0x%llx "
938 	    "eq_rec_addr1 0x%llx eq_rec_data0 0x%llx "
939 	    "eq_rec_data1 0x%llx\n", eq_rec_p->eq_rec_rid,
940 	    eq_rec_p->eq_rec_fmt_type, eq_rec_p->eq_rec_len,
941 	    eq_rec_p->eq_rec_addr0, eq_rec_p->eq_rec_addr1,
942 	    eq_rec_p->eq_rec_data0, eq_rec_p->eq_rec_data1);
943 
944 	/*
945 	 * Only upper 4 bits of eq_rec_fmt_type is used
946 	 * to identify the EQ record type.
947 	 */
948 	switch (eq_rec_p->eq_rec_fmt_type >> 3) {
949 	case EQ_REC_MSI32:
950 		msiq_rec_p->msiq_rec_type = MSI32_REC;
951 
952 		msiq_rec_p->msiq_rec_data.msi.msi_data =
953 		    eq_rec_p->eq_rec_data0;
954 		break;
955 	case EQ_REC_MSI64:
956 		msiq_rec_p->msiq_rec_type = MSI64_REC;
957 
958 		msiq_rec_p->msiq_rec_data.msi.msi_data =
959 		    eq_rec_p->eq_rec_data0;
960 		break;
961 	case EQ_REC_MSG:
962 		msiq_rec_p->msiq_rec_type = MSG_REC;
963 
964 		msiq_rec_p->msiq_rec_data.msg.msg_route =
965 		    eq_rec_p->eq_rec_fmt_type & 7;
966 		msiq_rec_p->msiq_rec_data.msg.msg_targ = eq_rec_p->eq_rec_rid;
967 		msiq_rec_p->msiq_rec_data.msg.msg_code = eq_rec_p->eq_rec_data0;
968 		break;
969 	default:
970 		cmn_err(CE_WARN, "%s%d: px_lib_get_msiq_rec: "
971 		    "0x%x is an unknown EQ record type",
972 		    ddi_driver_name(dip), ddi_get_instance(dip),
973 		    (int)eq_rec_p->eq_rec_fmt_type);
974 		break;
975 	}
976 
977 	msiq_rec_p->msiq_rec_rid = eq_rec_p->eq_rec_rid;
978 	msiq_rec_p->msiq_rec_msi_addr = ((eq_rec_p->eq_rec_addr1 << 16) |
979 	    (eq_rec_p->eq_rec_addr0 << 2));
980 }
981 
982 /*ARGSUSED*/
983 void
984 px_lib_clr_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p)
985 {
986 	eq_rec_t	*eq_rec_p = (eq_rec_t *)msiq_head_p;
987 
988 	DBG(DBG_LIB_MSIQ, dip, "px_lib_clr_msiq_rec: dip 0x%p eq_rec_p 0x%p\n",
989 	    dip, eq_rec_p);
990 
991 	if (eq_rec_p->eq_rec_fmt_type) {
992 		/* Zero out eq_rec_fmt_type field */
993 		eq_rec_p->eq_rec_fmt_type = 0;
994 	}
995 }
996 
997 /*
998  * MSI Functions:
999  */
1000 /*ARGSUSED*/
1001 int
1002 px_lib_msi_init(dev_info_t *dip)
1003 {
1004 	px_t		*px_p = DIP_TO_STATE(dip);
1005 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
1006 	uint64_t	ret;
1007 
1008 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_init: dip 0x%p\n", dip);
1009 
1010 	if ((ret = hvio_msi_init(DIP_TO_HANDLE(dip),
1011 	    msi_state_p->msi_addr32, msi_state_p->msi_addr64)) != H_EOK) {
1012 		DBG(DBG_LIB_MSIQ, dip, "px_lib_msi_init failed, ret 0x%lx\n",
1013 		    ret);
1014 		return (DDI_FAILURE);
1015 	}
1016 
1017 	return (DDI_SUCCESS);
1018 }
1019 
1020 /*ARGSUSED*/
1021 int
1022 px_lib_msi_getmsiq(dev_info_t *dip, msinum_t msi_num,
1023     msiqid_t *msiq_id)
1024 {
1025 	uint64_t	ret;
1026 
1027 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: dip 0x%p msi_num 0x%x\n",
1028 	    dip, msi_num);
1029 
1030 	if ((ret = hvio_msi_getmsiq(DIP_TO_HANDLE(dip),
1031 	    msi_num, msiq_id)) != H_EOK) {
1032 		DBG(DBG_LIB_MSI, dip,
1033 		    "hvio_msi_getmsiq failed, ret 0x%lx\n", ret);
1034 		return (DDI_FAILURE);
1035 	}
1036 
1037 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: msiq_id 0x%x\n",
1038 	    *msiq_id);
1039 
1040 	return (DDI_SUCCESS);
1041 }
1042 
1043 /*ARGSUSED*/
1044 int
1045 px_lib_msi_setmsiq(dev_info_t *dip, msinum_t msi_num,
1046     msiqid_t msiq_id, msi_type_t msitype)
1047 {
1048 	uint64_t	ret;
1049 
1050 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setmsiq: dip 0x%p msi_num 0x%x "
1051 	    "msq_id 0x%x\n", dip, msi_num, msiq_id);
1052 
1053 	if ((ret = hvio_msi_setmsiq(DIP_TO_HANDLE(dip),
1054 	    msi_num, msiq_id)) != H_EOK) {
1055 		DBG(DBG_LIB_MSI, dip,
1056 		    "hvio_msi_setmsiq failed, ret 0x%lx\n", ret);
1057 		return (DDI_FAILURE);
1058 	}
1059 
1060 	return (DDI_SUCCESS);
1061 }
1062 
1063 /*ARGSUSED*/
1064 int
1065 px_lib_msi_getvalid(dev_info_t *dip, msinum_t msi_num,
1066     pci_msi_valid_state_t *msi_valid_state)
1067 {
1068 	uint64_t	ret;
1069 
1070 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: dip 0x%p msi_num 0x%x\n",
1071 	    dip, msi_num);
1072 
1073 	if ((ret = hvio_msi_getvalid(DIP_TO_HANDLE(dip),
1074 	    msi_num, msi_valid_state)) != H_EOK) {
1075 		DBG(DBG_LIB_MSI, dip,
1076 		    "hvio_msi_getvalid failed, ret 0x%lx\n", ret);
1077 		return (DDI_FAILURE);
1078 	}
1079 
1080 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: msiq_id 0x%x\n",
1081 	    *msi_valid_state);
1082 
1083 	return (DDI_SUCCESS);
1084 }
1085 
1086 /*ARGSUSED*/
1087 int
1088 px_lib_msi_setvalid(dev_info_t *dip, msinum_t msi_num,
1089     pci_msi_valid_state_t msi_valid_state)
1090 {
1091 	uint64_t	ret;
1092 
1093 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setvalid: dip 0x%p msi_num 0x%x "
1094 	    "msi_valid_state 0x%x\n", dip, msi_num, msi_valid_state);
1095 
1096 	if ((ret = hvio_msi_setvalid(DIP_TO_HANDLE(dip),
1097 	    msi_num, msi_valid_state)) != H_EOK) {
1098 		DBG(DBG_LIB_MSI, dip,
1099 		    "hvio_msi_setvalid failed, ret 0x%lx\n", ret);
1100 		return (DDI_FAILURE);
1101 	}
1102 
1103 	return (DDI_SUCCESS);
1104 }
1105 
1106 /*ARGSUSED*/
1107 int
1108 px_lib_msi_getstate(dev_info_t *dip, msinum_t msi_num,
1109     pci_msi_state_t *msi_state)
1110 {
1111 	uint64_t	ret;
1112 
1113 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: dip 0x%p msi_num 0x%x\n",
1114 	    dip, msi_num);
1115 
1116 	if ((ret = hvio_msi_getstate(DIP_TO_HANDLE(dip),
1117 	    msi_num, msi_state)) != H_EOK) {
1118 		DBG(DBG_LIB_MSI, dip,
1119 		    "hvio_msi_getstate failed, ret 0x%lx\n", ret);
1120 		return (DDI_FAILURE);
1121 	}
1122 
1123 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: msi_state 0x%x\n",
1124 	    *msi_state);
1125 
1126 	return (DDI_SUCCESS);
1127 }
1128 
1129 /*ARGSUSED*/
1130 int
1131 px_lib_msi_setstate(dev_info_t *dip, msinum_t msi_num,
1132     pci_msi_state_t msi_state)
1133 {
1134 	uint64_t	ret;
1135 
1136 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setstate: dip 0x%p msi_num 0x%x "
1137 	    "msi_state 0x%x\n", dip, msi_num, msi_state);
1138 
1139 	if ((ret = hvio_msi_setstate(DIP_TO_HANDLE(dip),
1140 	    msi_num, msi_state)) != H_EOK) {
1141 		DBG(DBG_LIB_MSI, dip,
1142 		    "hvio_msi_setstate failed, ret 0x%lx\n", ret);
1143 		return (DDI_FAILURE);
1144 	}
1145 
1146 	return (DDI_SUCCESS);
1147 }
1148 
1149 /*
1150  * MSG Functions:
1151  */
1152 /*ARGSUSED*/
1153 int
1154 px_lib_msg_getmsiq(dev_info_t *dip, pcie_msg_type_t msg_type,
1155     msiqid_t *msiq_id)
1156 {
1157 	uint64_t	ret;
1158 
1159 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_getmsiq: dip 0x%p msg_type 0x%x\n",
1160 	    dip, msg_type);
1161 
1162 	if ((ret = hvio_msg_getmsiq(DIP_TO_HANDLE(dip),
1163 	    msg_type, msiq_id)) != H_EOK) {
1164 		DBG(DBG_LIB_MSG, dip,
1165 		    "hvio_msg_getmsiq failed, ret 0x%lx\n", ret);
1166 		return (DDI_FAILURE);
1167 	}
1168 
1169 	DBG(DBG_LIB_MSI, dip, "px_lib_msg_getmsiq: msiq_id 0x%x\n",
1170 	    *msiq_id);
1171 
1172 	return (DDI_SUCCESS);
1173 }
1174 
1175 /*ARGSUSED*/
1176 int
1177 px_lib_msg_setmsiq(dev_info_t *dip, pcie_msg_type_t msg_type,
1178     msiqid_t msiq_id)
1179 {
1180 	uint64_t	ret;
1181 
1182 	DBG(DBG_LIB_MSG, dip, "px_lib_msi_setstate: dip 0x%p msg_type 0x%x "
1183 	    "msiq_id 0x%x\n", dip, msg_type, msiq_id);
1184 
1185 	if ((ret = hvio_msg_setmsiq(DIP_TO_HANDLE(dip),
1186 	    msg_type, msiq_id)) != H_EOK) {
1187 		DBG(DBG_LIB_MSG, dip,
1188 		    "hvio_msg_setmsiq failed, ret 0x%lx\n", ret);
1189 		return (DDI_FAILURE);
1190 	}
1191 
1192 	return (DDI_SUCCESS);
1193 }
1194 
1195 /*ARGSUSED*/
1196 int
1197 px_lib_msg_getvalid(dev_info_t *dip, pcie_msg_type_t msg_type,
1198     pcie_msg_valid_state_t *msg_valid_state)
1199 {
1200 	uint64_t	ret;
1201 
1202 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_getvalid: dip 0x%p msg_type 0x%x\n",
1203 	    dip, msg_type);
1204 
1205 	if ((ret = hvio_msg_getvalid(DIP_TO_HANDLE(dip), msg_type,
1206 	    msg_valid_state)) != H_EOK) {
1207 		DBG(DBG_LIB_MSG, dip,
1208 		    "hvio_msg_getvalid failed, ret 0x%lx\n", ret);
1209 		return (DDI_FAILURE);
1210 	}
1211 
1212 	DBG(DBG_LIB_MSI, dip, "px_lib_msg_getvalid: msg_valid_state 0x%x\n",
1213 	    *msg_valid_state);
1214 
1215 	return (DDI_SUCCESS);
1216 }
1217 
1218 /*ARGSUSED*/
1219 int
1220 px_lib_msg_setvalid(dev_info_t *dip, pcie_msg_type_t msg_type,
1221     pcie_msg_valid_state_t msg_valid_state)
1222 {
1223 	uint64_t	ret;
1224 
1225 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_setvalid: dip 0x%p msg_type 0x%x "
1226 	    "msg_valid_state 0x%x\n", dip, msg_type, msg_valid_state);
1227 
1228 	if ((ret = hvio_msg_setvalid(DIP_TO_HANDLE(dip), msg_type,
1229 	    msg_valid_state)) != H_EOK) {
1230 		DBG(DBG_LIB_MSG, dip,
1231 		    "hvio_msg_setvalid failed, ret 0x%lx\n", ret);
1232 		return (DDI_FAILURE);
1233 	}
1234 
1235 	return (DDI_SUCCESS);
1236 }
1237 
1238 /*
1239  * Suspend/Resume Functions:
1240  * Currently unsupported by hypervisor
1241  */
1242 int
1243 px_lib_suspend(dev_info_t *dip)
1244 {
1245 	px_t		*px_p = DIP_TO_STATE(dip);
1246 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
1247 	px_cb_t		*cb_p = PX2CB(px_p);
1248 	devhandle_t	dev_hdl, xbus_dev_hdl;
1249 	uint64_t	ret = H_EOK;
1250 
1251 	DBG(DBG_DETACH, dip, "px_lib_suspend: dip 0x%p\n", dip);
1252 
1253 	dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR];
1254 	xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC];
1255 
1256 	if ((ret = hvio_suspend(dev_hdl, pxu_p)) != H_EOK)
1257 		goto fail;
1258 
1259 	if (--cb_p->attachcnt == 0) {
1260 		ret = hvio_cb_suspend(xbus_dev_hdl, pxu_p);
1261 		if (ret != H_EOK)
1262 			cb_p->attachcnt++;
1263 	}
1264 	pxu_p->cpr_flag = PX_ENTERED_CPR;
1265 
1266 fail:
1267 	return ((ret != H_EOK) ? DDI_FAILURE: DDI_SUCCESS);
1268 }
1269 
1270 void
1271 px_lib_resume(dev_info_t *dip)
1272 {
1273 	px_t		*px_p = DIP_TO_STATE(dip);
1274 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
1275 	px_cb_t		*cb_p = PX2CB(px_p);
1276 	devhandle_t	dev_hdl, xbus_dev_hdl;
1277 	devino_t	pec_ino = px_p->px_inos[PX_INTR_PEC];
1278 	devino_t	xbc_ino = px_p->px_inos[PX_INTR_XBC];
1279 
1280 	DBG(DBG_ATTACH, dip, "px_lib_resume: dip 0x%p\n", dip);
1281 
1282 	dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR];
1283 	xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC];
1284 
1285 	if (++cb_p->attachcnt == 1)
1286 		hvio_cb_resume(dev_hdl, xbus_dev_hdl, xbc_ino, pxu_p);
1287 
1288 	hvio_resume(dev_hdl, pec_ino, pxu_p);
1289 }
1290 
1291 /*
1292  * Generate a unique Oberon UBC ID based on the Logicial System Board and
1293  * the IO Channel from the portid property field.
1294  */
1295 static uint64_t
1296 oberon_get_ubc_id(dev_info_t *dip)
1297 {
1298 	px_t	*px_p = DIP_TO_STATE(dip);
1299 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
1300 	uint64_t	ubc_id;
1301 
1302 	/*
1303 	 * Generate a unique 6 bit UBC ID using the 2 IO_Channel#[1:0] bits and
1304 	 * the 4 LSB_ID[3:0] bits from the Oberon's portid property.
1305 	 */
1306 	ubc_id = (((pxu_p->portid >> OBERON_PORT_ID_IOC) &
1307 	    OBERON_PORT_ID_IOC_MASK) | (((pxu_p->portid >>
1308 	    OBERON_PORT_ID_LSB) & OBERON_PORT_ID_LSB_MASK)
1309 	    << OBERON_UBC_ID_LSB));
1310 
1311 	return (ubc_id);
1312 }
1313 
1314 /*
1315  * Oberon does not have a UBC scratch register, so alloc an array of scratch
1316  * registers when needed and use a unique UBC ID as an index. This code
1317  * can be simplified if we use a pre-allocated array. They are currently
1318  * being dynamically allocated because it's only needed by the Oberon.
1319  */
1320 static void
1321 oberon_set_cb(dev_info_t *dip, uint64_t val)
1322 {
1323 	uint64_t	ubc_id;
1324 
1325 	if (px_oberon_ubc_scratch_regs == NULL)
1326 		px_oberon_ubc_scratch_regs =
1327 		    (uint64_t *)kmem_zalloc(sizeof (uint64_t)*
1328 		    OBERON_UBC_ID_MAX, KM_SLEEP);
1329 
1330 	ubc_id = oberon_get_ubc_id(dip);
1331 
1332 	px_oberon_ubc_scratch_regs[ubc_id] = val;
1333 
1334 	/*
1335 	 * Check if any scratch registers are still in use. If all scratch
1336 	 * registers are currently set to zero, then deallocate the scratch
1337 	 * register array.
1338 	 */
1339 	for (ubc_id = 0; ubc_id < OBERON_UBC_ID_MAX; ubc_id++) {
1340 		if (px_oberon_ubc_scratch_regs[ubc_id] != NULL)
1341 			return;
1342 	}
1343 
1344 	/*
1345 	 * All scratch registers are set to zero so deallocate the scratch
1346 	 * register array and set the pointer to NULL.
1347 	 */
1348 	kmem_free(px_oberon_ubc_scratch_regs,
1349 	    (sizeof (uint64_t)*OBERON_UBC_ID_MAX));
1350 
1351 	px_oberon_ubc_scratch_regs = NULL;
1352 }
1353 
1354 /*
1355  * Oberon does not have a UBC scratch register, so use an allocated array of
1356  * scratch registers and use the unique UBC ID as an index into that array.
1357  */
1358 static uint64_t
1359 oberon_get_cb(dev_info_t *dip)
1360 {
1361 	uint64_t	ubc_id;
1362 
1363 	if (px_oberon_ubc_scratch_regs == NULL)
1364 		return (0);
1365 
1366 	ubc_id = oberon_get_ubc_id(dip);
1367 
1368 	return (px_oberon_ubc_scratch_regs[ubc_id]);
1369 }
1370 
1371 /*
1372  * Misc Functions:
1373  * Currently unsupported by hypervisor
1374  */
1375 static uint64_t
1376 px_get_cb(dev_info_t *dip)
1377 {
1378 	px_t	*px_p = DIP_TO_STATE(dip);
1379 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
1380 
1381 	/*
1382 	 * Oberon does not currently have Scratchpad registers.
1383 	 */
1384 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON)
1385 		return (oberon_get_cb(dip));
1386 
1387 	return (CSR_XR((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1));
1388 }
1389 
1390 static void
1391 px_set_cb(dev_info_t *dip, uint64_t val)
1392 {
1393 	px_t	*px_p = DIP_TO_STATE(dip);
1394 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
1395 
1396 	/*
1397 	 * Oberon does not currently have Scratchpad registers.
1398 	 */
1399 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) {
1400 		oberon_set_cb(dip, val);
1401 		return;
1402 	}
1403 
1404 	CSR_XS((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1, val);
1405 }
1406 
1407 /*ARGSUSED*/
1408 int
1409 px_lib_map_vconfig(dev_info_t *dip,
1410 	ddi_map_req_t *mp, pci_config_offset_t off,
1411 		pci_regspec_t *rp, caddr_t *addrp)
1412 {
1413 	/*
1414 	 * No special config space access services in this layer.
1415 	 */
1416 	return (DDI_FAILURE);
1417 }
1418 
1419 void
1420 px_lib_map_attr_check(ddi_map_req_t *mp)
1421 {
1422 	ddi_acc_hdl_t *hp = mp->map_handlep;
1423 
1424 	/* fire does not accept byte masks from PIO store merge */
1425 	if (hp->ah_acc.devacc_attr_dataorder == DDI_STORECACHING_OK_ACC)
1426 		hp->ah_acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1427 }
1428 
1429 /* This function is called only by poke, caut put and pxtool poke. */
1430 void
1431 px_lib_clr_errs(px_t *px_p, dev_info_t *rdip, uint64_t addr)
1432 {
1433 	px_pec_t	*pec_p = px_p->px_pec_p;
1434 	dev_info_t	*rpdip = px_p->px_dip;
1435 	int		rc_err, fab_err, i;
1436 	int		acctype = pec_p->pec_safeacc_type;
1437 	ddi_fm_error_t	derr;
1438 	px_ranges_t	*ranges_p;
1439 	int		range_len;
1440 	uint32_t	addr_high, addr_low;
1441 	pcie_req_id_t	bdf = 0;
1442 
1443 	/* Create the derr */
1444 	bzero(&derr, sizeof (ddi_fm_error_t));
1445 	derr.fme_version = DDI_FME_VERSION;
1446 	derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
1447 	derr.fme_flag = acctype;
1448 
1449 	if (acctype == DDI_FM_ERR_EXPECTED) {
1450 		derr.fme_status = DDI_FM_NONFATAL;
1451 		ndi_fm_acc_err_set(pec_p->pec_acc_hdl, &derr);
1452 	}
1453 
1454 	mutex_enter(&px_p->px_fm_mutex);
1455 
1456 	/* send ereport/handle/clear fire registers */
1457 	rc_err = px_err_cmn_intr(px_p, &derr, PX_LIB_CALL, PX_FM_BLOCK_ALL);
1458 
1459 	/* Figure out if this is a cfg or mem32 access */
1460 	addr_high = (uint32_t)(addr >> 32);
1461 	addr_low = (uint32_t)addr;
1462 	range_len = px_p->px_ranges_length / sizeof (px_ranges_t);
1463 	i = 0;
1464 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
1465 		if (ranges_p->parent_high == addr_high) {
1466 			switch (ranges_p->child_high & PCI_ADDR_MASK) {
1467 			case PCI_ADDR_CONFIG:
1468 				bdf = (pcie_req_id_t)(addr_low >> 12);
1469 				addr_low = 0;
1470 				break;
1471 			case PCI_ADDR_MEM32:
1472 				if (rdip)
1473 					(void) pcie_get_bdf_from_dip(rdip,
1474 					    &bdf);
1475 				else
1476 					bdf = NULL;
1477 				break;
1478 			}
1479 			break;
1480 		}
1481 	}
1482 
1483 	px_rp_en_q(px_p, bdf, addr_low, NULL);
1484 
1485 	/*
1486 	 * XXX - Current code scans the fabric for all px_tool accesses.
1487 	 * In future, do not scan fabric for px_tool access to IO Root Nexus
1488 	 */
1489 	fab_err = pf_scan_fabric(rpdip, &derr, px_p->px_dq_p,
1490 	    &px_p->px_dq_tail);
1491 
1492 	mutex_exit(&px_p->px_fm_mutex);
1493 
1494 	px_err_panic(rc_err, PX_RC, fab_err);
1495 }
1496 
1497 #ifdef  DEBUG
1498 int	px_peekfault_cnt = 0;
1499 int	px_pokefault_cnt = 0;
1500 #endif  /* DEBUG */
1501 
1502 /*ARGSUSED*/
1503 static int
1504 px_lib_do_poke(dev_info_t *dip, dev_info_t *rdip,
1505     peekpoke_ctlops_t *in_args)
1506 {
1507 	px_t *px_p = DIP_TO_STATE(dip);
1508 	px_pec_t *pec_p = px_p->px_pec_p;
1509 	int err = DDI_SUCCESS;
1510 	on_trap_data_t otd;
1511 
1512 	mutex_enter(&pec_p->pec_pokefault_mutex);
1513 	pec_p->pec_ontrap_data = &otd;
1514 	pec_p->pec_safeacc_type = DDI_FM_ERR_POKE;
1515 
1516 	/* Set up protected environment. */
1517 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
1518 		uintptr_t tramp = otd.ot_trampoline;
1519 
1520 		otd.ot_trampoline = (uintptr_t)&poke_fault;
1521 		err = do_poke(in_args->size, (void *)in_args->dev_addr,
1522 		    (void *)in_args->host_addr);
1523 		otd.ot_trampoline = tramp;
1524 	} else
1525 		err = DDI_FAILURE;
1526 
1527 	px_lib_clr_errs(px_p, rdip, in_args->dev_addr);
1528 
1529 	if (otd.ot_trap & OT_DATA_ACCESS)
1530 		err = DDI_FAILURE;
1531 
1532 	/* Take down protected environment. */
1533 	no_trap();
1534 
1535 	pec_p->pec_ontrap_data = NULL;
1536 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1537 	mutex_exit(&pec_p->pec_pokefault_mutex);
1538 
1539 #ifdef  DEBUG
1540 	if (err == DDI_FAILURE)
1541 		px_pokefault_cnt++;
1542 #endif
1543 	return (err);
1544 }
1545 
1546 /*ARGSUSED*/
1547 static int
1548 px_lib_do_caut_put(dev_info_t *dip, dev_info_t *rdip,
1549     peekpoke_ctlops_t *cautacc_ctlops_arg)
1550 {
1551 	size_t size = cautacc_ctlops_arg->size;
1552 	uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr;
1553 	uintptr_t host_addr = cautacc_ctlops_arg->host_addr;
1554 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle;
1555 	size_t repcount = cautacc_ctlops_arg->repcount;
1556 	uint_t flags = cautacc_ctlops_arg->flags;
1557 
1558 	px_t *px_p = DIP_TO_STATE(dip);
1559 	px_pec_t *pec_p = px_p->px_pec_p;
1560 	int err = DDI_SUCCESS;
1561 
1562 	/*
1563 	 * Note that i_ndi_busop_access_enter ends up grabbing the pokefault
1564 	 * mutex.
1565 	 */
1566 	i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
1567 
1568 	pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap;
1569 	pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED;
1570 	hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED;
1571 
1572 	if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) {
1573 		for (; repcount; repcount--) {
1574 			switch (size) {
1575 
1576 			case sizeof (uint8_t):
1577 				i_ddi_put8(hp, (uint8_t *)dev_addr,
1578 				    *(uint8_t *)host_addr);
1579 				break;
1580 
1581 			case sizeof (uint16_t):
1582 				i_ddi_put16(hp, (uint16_t *)dev_addr,
1583 				    *(uint16_t *)host_addr);
1584 				break;
1585 
1586 			case sizeof (uint32_t):
1587 				i_ddi_put32(hp, (uint32_t *)dev_addr,
1588 				    *(uint32_t *)host_addr);
1589 				break;
1590 
1591 			case sizeof (uint64_t):
1592 				i_ddi_put64(hp, (uint64_t *)dev_addr,
1593 				    *(uint64_t *)host_addr);
1594 				break;
1595 			}
1596 
1597 			host_addr += size;
1598 
1599 			if (flags == DDI_DEV_AUTOINCR)
1600 				dev_addr += size;
1601 
1602 			px_lib_clr_errs(px_p, rdip, dev_addr);
1603 
1604 			if (pec_p->pec_ontrap_data->ot_trap & OT_DATA_ACCESS) {
1605 				err = DDI_FAILURE;
1606 #ifdef  DEBUG
1607 				px_pokefault_cnt++;
1608 #endif
1609 				break;
1610 			}
1611 		}
1612 	}
1613 
1614 	i_ddi_notrap((ddi_acc_handle_t)hp);
1615 	pec_p->pec_ontrap_data = NULL;
1616 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1617 	i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
1618 	hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED;
1619 
1620 	return (err);
1621 }
1622 
1623 
1624 int
1625 px_lib_ctlops_poke(dev_info_t *dip, dev_info_t *rdip,
1626     peekpoke_ctlops_t *in_args)
1627 {
1628 	return (in_args->handle ? px_lib_do_caut_put(dip, rdip, in_args) :
1629 	    px_lib_do_poke(dip, rdip, in_args));
1630 }
1631 
1632 
1633 /*ARGSUSED*/
1634 static int
1635 px_lib_do_peek(dev_info_t *dip, peekpoke_ctlops_t *in_args)
1636 {
1637 	px_t *px_p = DIP_TO_STATE(dip);
1638 	px_pec_t *pec_p = px_p->px_pec_p;
1639 	int err = DDI_SUCCESS;
1640 	on_trap_data_t otd;
1641 
1642 	mutex_enter(&pec_p->pec_pokefault_mutex);
1643 	mutex_enter(&px_p->px_fm_mutex);
1644 	pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK;
1645 	mutex_exit(&px_p->px_fm_mutex);
1646 
1647 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
1648 		uintptr_t tramp = otd.ot_trampoline;
1649 
1650 		otd.ot_trampoline = (uintptr_t)&peek_fault;
1651 		err = do_peek(in_args->size, (void *)in_args->dev_addr,
1652 		    (void *)in_args->host_addr);
1653 		otd.ot_trampoline = tramp;
1654 	} else
1655 		err = DDI_FAILURE;
1656 
1657 	no_trap();
1658 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1659 	mutex_exit(&pec_p->pec_pokefault_mutex);
1660 
1661 #ifdef  DEBUG
1662 	if (err == DDI_FAILURE)
1663 		px_peekfault_cnt++;
1664 #endif
1665 	return (err);
1666 }
1667 
1668 
1669 static int
1670 px_lib_do_caut_get(dev_info_t *dip, peekpoke_ctlops_t *cautacc_ctlops_arg)
1671 {
1672 	size_t size = cautacc_ctlops_arg->size;
1673 	uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr;
1674 	uintptr_t host_addr = cautacc_ctlops_arg->host_addr;
1675 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle;
1676 	size_t repcount = cautacc_ctlops_arg->repcount;
1677 	uint_t flags = cautacc_ctlops_arg->flags;
1678 
1679 	px_t *px_p = DIP_TO_STATE(dip);
1680 	px_pec_t *pec_p = px_p->px_pec_p;
1681 	int err = DDI_SUCCESS;
1682 
1683 	/*
1684 	 * Note that i_ndi_busop_access_enter ends up grabbing the pokefault
1685 	 * mutex.
1686 	 */
1687 	i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
1688 
1689 	pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap;
1690 	pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED;
1691 	hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED;
1692 
1693 	if (repcount == 1) {
1694 		if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) {
1695 			i_ddi_caut_get(size, (void *)dev_addr,
1696 			    (void *)host_addr);
1697 		} else {
1698 			int i;
1699 			uint8_t *ff_addr = (uint8_t *)host_addr;
1700 			for (i = 0; i < size; i++)
1701 				*ff_addr++ = 0xff;
1702 
1703 			err = DDI_FAILURE;
1704 #ifdef  DEBUG
1705 			px_peekfault_cnt++;
1706 #endif
1707 		}
1708 	} else {
1709 		if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) {
1710 			for (; repcount; repcount--) {
1711 				i_ddi_caut_get(size, (void *)dev_addr,
1712 				    (void *)host_addr);
1713 
1714 				host_addr += size;
1715 
1716 				if (flags == DDI_DEV_AUTOINCR)
1717 					dev_addr += size;
1718 			}
1719 		} else {
1720 			err = DDI_FAILURE;
1721 #ifdef  DEBUG
1722 			px_peekfault_cnt++;
1723 #endif
1724 		}
1725 	}
1726 
1727 	i_ddi_notrap((ddi_acc_handle_t)hp);
1728 	pec_p->pec_ontrap_data = NULL;
1729 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1730 	i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
1731 	hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED;
1732 
1733 	return (err);
1734 }
1735 
1736 /*ARGSUSED*/
1737 int
1738 px_lib_ctlops_peek(dev_info_t *dip, dev_info_t *rdip,
1739     peekpoke_ctlops_t *in_args, void *result)
1740 {
1741 	result = (void *)in_args->host_addr;
1742 	return (in_args->handle ? px_lib_do_caut_get(dip, in_args) :
1743 	    px_lib_do_peek(dip, in_args));
1744 }
1745 
1746 /*
1747  * implements PPM interface
1748  */
1749 int
1750 px_lib_pmctl(int cmd, px_t *px_p)
1751 {
1752 	ASSERT((cmd & ~PPMREQ_MASK) == PPMREQ);
1753 	switch (cmd) {
1754 	case PPMREQ_PRE_PWR_OFF:
1755 		/*
1756 		 * Currently there is no device power management for
1757 		 * the root complex (fire). When there is we need to make
1758 		 * sure that it is at full power before trying to send the
1759 		 * PME_Turn_Off message.
1760 		 */
1761 		DBG(DBG_PWR, px_p->px_dip,
1762 		    "ioctl: request to send PME_Turn_Off\n");
1763 		return (px_goto_l23ready(px_p));
1764 
1765 	case PPMREQ_PRE_PWR_ON:
1766 		DBG(DBG_PWR, px_p->px_dip, "ioctl: PRE_PWR_ON request\n");
1767 		return (px_pre_pwron_check(px_p));
1768 
1769 	case PPMREQ_POST_PWR_ON:
1770 		DBG(DBG_PWR, px_p->px_dip, "ioctl: POST_PWR_ON request\n");
1771 		return (px_goto_l0(px_p));
1772 
1773 	default:
1774 		return (DDI_FAILURE);
1775 	}
1776 }
1777 
1778 /*
1779  * sends PME_Turn_Off message to put the link in L2/L3 ready state.
1780  * called by px_ioctl.
1781  * returns DDI_SUCCESS or DDI_FAILURE
1782  * 1. Wait for link to be in L1 state (link status reg)
1783  * 2. write to PME_Turn_off reg to boradcast
1784  * 3. set timeout
1785  * 4. If timeout, return failure.
1786  * 5. If PM_TO_Ack, wait till link is in L2/L3 ready
1787  */
1788 static int
1789 px_goto_l23ready(px_t *px_p)
1790 {
1791 	pcie_pwr_t	*pwr_p;
1792 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
1793 	caddr_t	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
1794 	int		ret = DDI_SUCCESS;
1795 	clock_t		end, timeleft;
1796 	int		mutex_held = 1;
1797 
1798 	/* If no PM info, return failure */
1799 	if (!PCIE_PMINFO(px_p->px_dip) ||
1800 	    !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip)))
1801 		return (DDI_FAILURE);
1802 
1803 	mutex_enter(&pwr_p->pwr_lock);
1804 	mutex_enter(&px_p->px_l23ready_lock);
1805 	/* Clear the PME_To_ACK receieved flag */
1806 	px_p->px_pm_flags &= ~PX_PMETOACK_RECVD;
1807 	/*
1808 	 * When P25 is the downstream device, after receiving
1809 	 * PME_To_ACK, fire will go to Detect state, which causes
1810 	 * the link down event. Inform FMA that this is expected.
1811 	 * In case of all other cards complaint with the pci express
1812 	 * spec, this will happen when the power is re-applied. FMA
1813 	 * code will clear this flag after one instance of LDN. Since
1814 	 * there will not be a LDN event for the spec compliant cards,
1815 	 * we need to clear the flag after receiving PME_To_ACK.
1816 	 */
1817 	px_p->px_pm_flags |= PX_LDN_EXPECTED;
1818 	if (px_send_pme_turnoff(csr_base) != DDI_SUCCESS) {
1819 		ret = DDI_FAILURE;
1820 		goto l23ready_done;
1821 	}
1822 	px_p->px_pm_flags |= PX_PME_TURNOFF_PENDING;
1823 
1824 	end = ddi_get_lbolt() + drv_usectohz(px_pme_to_ack_timeout);
1825 	while (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) {
1826 		timeleft = cv_timedwait(&px_p->px_l23ready_cv,
1827 		    &px_p->px_l23ready_lock, end);
1828 		/*
1829 		 * if cv_timedwait returns -1, it is either
1830 		 * 1) timed out or
1831 		 * 2) there was a pre-mature wakeup but by the time
1832 		 * cv_timedwait is called again end < lbolt i.e.
1833 		 * end is in the past.
1834 		 * 3) By the time we make first cv_timedwait call,
1835 		 * end < lbolt is true.
1836 		 */
1837 		if (timeleft == -1)
1838 			break;
1839 	}
1840 	if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) {
1841 		/*
1842 		 * Either timedout or interrupt didn't get a
1843 		 * chance to grab the mutex and set the flag.
1844 		 * release the mutex and delay for sometime.
1845 		 * This will 1) give a chance for interrupt to
1846 		 * set the flag 2) creates a delay between two
1847 		 * consequetive requests.
1848 		 */
1849 		mutex_exit(&px_p->px_l23ready_lock);
1850 		delay(drv_usectohz(50 * PX_MSEC_TO_USEC));
1851 		mutex_held = 0;
1852 		if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) {
1853 			ret = DDI_FAILURE;
1854 			DBG(DBG_PWR, px_p->px_dip, " Timed out while waiting"
1855 			    " for PME_TO_ACK\n");
1856 		}
1857 	}
1858 	px_p->px_pm_flags &=
1859 	    ~(PX_PME_TURNOFF_PENDING | PX_PMETOACK_RECVD | PX_LDN_EXPECTED);
1860 
1861 l23ready_done:
1862 	if (mutex_held)
1863 		mutex_exit(&px_p->px_l23ready_lock);
1864 	/*
1865 	 * Wait till link is in L1 idle, if sending PME_Turn_Off
1866 	 * was succesful.
1867 	 */
1868 	if (ret == DDI_SUCCESS) {
1869 		if (px_link_wait4l1idle(csr_base) != DDI_SUCCESS) {
1870 			DBG(DBG_PWR, px_p->px_dip, " Link is not at L1"
1871 			    " even though we received PME_To_ACK.\n");
1872 			/*
1873 			 * Workaround for hardware bug with P25.
1874 			 * Due to a hardware bug with P25, link state
1875 			 * will be Detect state rather than L1 after
1876 			 * link is transitioned to L23Ready state. Since
1877 			 * we don't know whether link is L23ready state
1878 			 * without Fire's state being L1_idle, we delay
1879 			 * here just to make sure that we wait till link
1880 			 * is transitioned to L23Ready state.
1881 			 */
1882 			delay(drv_usectohz(100 * PX_MSEC_TO_USEC));
1883 		}
1884 		pwr_p->pwr_link_lvl = PM_LEVEL_L3;
1885 
1886 	}
1887 	mutex_exit(&pwr_p->pwr_lock);
1888 	return (ret);
1889 }
1890 
1891 /*
1892  * Message interrupt handler intended to be shared for both
1893  * PME and PME_TO_ACK msg handling, currently only handles
1894  * PME_To_ACK message.
1895  */
1896 uint_t
1897 px_pmeq_intr(caddr_t arg)
1898 {
1899 	px_t	*px_p = (px_t *)arg;
1900 
1901 	DBG(DBG_PWR, px_p->px_dip, " PME_To_ACK received \n");
1902 	mutex_enter(&px_p->px_l23ready_lock);
1903 	cv_broadcast(&px_p->px_l23ready_cv);
1904 	if (px_p->px_pm_flags & PX_PME_TURNOFF_PENDING) {
1905 		px_p->px_pm_flags |= PX_PMETOACK_RECVD;
1906 	} else {
1907 		/*
1908 		 * This maybe the second ack received. If so then,
1909 		 * we should be receiving it during wait4L1 stage.
1910 		 */
1911 		px_p->px_pmetoack_ignored++;
1912 	}
1913 	mutex_exit(&px_p->px_l23ready_lock);
1914 	return (DDI_INTR_CLAIMED);
1915 }
1916 
1917 static int
1918 px_pre_pwron_check(px_t *px_p)
1919 {
1920 	pcie_pwr_t	*pwr_p;
1921 
1922 	/* If no PM info, return failure */
1923 	if (!PCIE_PMINFO(px_p->px_dip) ||
1924 	    !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip)))
1925 		return (DDI_FAILURE);
1926 
1927 	/*
1928 	 * For the spec compliant downstream cards link down
1929 	 * is expected when the device is powered on.
1930 	 */
1931 	px_p->px_pm_flags |= PX_LDN_EXPECTED;
1932 	return (pwr_p->pwr_link_lvl == PM_LEVEL_L3 ? DDI_SUCCESS : DDI_FAILURE);
1933 }
1934 
1935 static int
1936 px_goto_l0(px_t *px_p)
1937 {
1938 	pcie_pwr_t	*pwr_p;
1939 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
1940 	caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
1941 	int		ret = DDI_SUCCESS;
1942 	uint64_t	time_spent = 0;
1943 
1944 	/* If no PM info, return failure */
1945 	if (!PCIE_PMINFO(px_p->px_dip) ||
1946 	    !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip)))
1947 		return (DDI_FAILURE);
1948 
1949 	mutex_enter(&pwr_p->pwr_lock);
1950 	/*
1951 	 * The following link retrain activity will cause LDN and LUP event.
1952 	 * Receiving LDN prior to receiving LUP is expected, not an error in
1953 	 * this case.  Receiving LUP indicates link is fully up to support
1954 	 * powering up down stream device, and of course any further LDN and
1955 	 * LUP outside this context will be error.
1956 	 */
1957 	px_p->px_lup_pending = 1;
1958 	if (px_link_retrain(csr_base) != DDI_SUCCESS) {
1959 		ret = DDI_FAILURE;
1960 		goto l0_done;
1961 	}
1962 
1963 	/* LUP event takes the order of 15ms amount of time to occur */
1964 	for (; px_p->px_lup_pending && (time_spent < px_lup_poll_to);
1965 	    time_spent += px_lup_poll_interval)
1966 		drv_usecwait(px_lup_poll_interval);
1967 	if (px_p->px_lup_pending)
1968 		ret = DDI_FAILURE;
1969 l0_done:
1970 	px_enable_detect_quiet(csr_base);
1971 	if (ret == DDI_SUCCESS)
1972 		pwr_p->pwr_link_lvl = PM_LEVEL_L0;
1973 	mutex_exit(&pwr_p->pwr_lock);
1974 	return (ret);
1975 }
1976 
1977 /*
1978  * Extract the drivers binding name to identify which chip we're binding to.
1979  * Whenever a new bus bridge is created, the driver alias entry should be
1980  * added here to identify the device if needed.  If a device isn't added,
1981  * the identity defaults to PX_CHIP_UNIDENTIFIED.
1982  */
1983 static uint32_t
1984 px_identity_init(px_t *px_p)
1985 {
1986 	dev_info_t	*dip = px_p->px_dip;
1987 	char		*name = ddi_binding_name(dip);
1988 	uint32_t	revision = 0;
1989 
1990 	revision = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1991 	    "module-revision#", 0);
1992 
1993 	/* Check for Fire driver binding name */
1994 	if (strcmp(name, "pciex108e,80f0") == 0) {
1995 		DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: "
1996 		    "(FIRE), module-revision %d\n", NAMEINST(dip),
1997 		    revision);
1998 
1999 		return ((revision >= FIRE_MOD_REV_20) ?
2000 		    PX_CHIP_FIRE : PX_CHIP_UNIDENTIFIED);
2001 	}
2002 
2003 	/* Check for Oberon driver binding name */
2004 	if (strcmp(name, "pciex108e,80f8") == 0) {
2005 		DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: "
2006 		    "(OBERON), module-revision %d\n", NAMEINST(dip),
2007 		    revision);
2008 
2009 		return (PX_CHIP_OBERON);
2010 	}
2011 
2012 	DBG(DBG_ATTACH, dip, "%s%d: Unknown PCI Express Host bridge %s %x\n",
2013 	    ddi_driver_name(dip), ddi_get_instance(dip), name, revision);
2014 
2015 	return (PX_CHIP_UNIDENTIFIED);
2016 }
2017 
2018 int
2019 px_err_add_intr(px_fault_t *px_fault_p)
2020 {
2021 	dev_info_t	*dip = px_fault_p->px_fh_dip;
2022 	px_t		*px_p = DIP_TO_STATE(dip);
2023 
2024 	VERIFY(add_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL,
2025 	    (intrfunc)px_fault_p->px_err_func, (caddr_t)px_fault_p,
2026 	    NULL, NULL) == 0);
2027 
2028 	px_ib_intr_enable(px_p, intr_dist_cpuid(), px_fault_p->px_intr_ino);
2029 
2030 	return (DDI_SUCCESS);
2031 }
2032 
2033 void
2034 px_err_rem_intr(px_fault_t *px_fault_p)
2035 {
2036 	dev_info_t	*dip = px_fault_p->px_fh_dip;
2037 	px_t		*px_p = DIP_TO_STATE(dip);
2038 
2039 	px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino,
2040 		IB_INTR_WAIT);
2041 
2042 	VERIFY(rem_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL) == 0);
2043 }
2044 
2045 /*
2046  * px_cb_intr_redist() - sun4u only, CB interrupt redistribution
2047  */
2048 void
2049 px_cb_intr_redist(void *arg)
2050 {
2051 	px_cb_t		*cb_p = (px_cb_t *)arg;
2052 	px_cb_list_t	*pxl;
2053 	px_t		*pxp = NULL;
2054 	px_fault_t	*f_p = NULL;
2055 	uint32_t	new_cpuid;
2056 	intr_valid_state_t	enabled = 0;
2057 
2058 	mutex_enter(&cb_p->cb_mutex);
2059 
2060 	pxl = cb_p->pxl;
2061 	if (!pxl)
2062 		goto cb_done;
2063 
2064 	pxp = pxl->pxp;
2065 	f_p = &pxp->px_cb_fault;
2066 	for (; pxl && (f_p->px_fh_sysino != cb_p->sysino); ) {
2067 		pxl = pxl->next;
2068 		pxp = pxl->pxp;
2069 		f_p = &pxp->px_cb_fault;
2070 	}
2071 	if (pxl == NULL)
2072 		goto cb_done;
2073 
2074 	new_cpuid =  intr_dist_cpuid();
2075 	if (new_cpuid == cb_p->cpuid)
2076 		goto cb_done;
2077 
2078 	if ((px_lib_intr_getvalid(pxp->px_dip, f_p->px_fh_sysino, &enabled)
2079 	    != DDI_SUCCESS) || !enabled) {
2080 		DBG(DBG_IB, pxp->px_dip, "px_cb_intr_redist: CB not enabled, "
2081 		    "sysino(0x%x)\n", f_p->px_fh_sysino);
2082 		goto cb_done;
2083 	}
2084 
2085 	PX_INTR_DISABLE(pxp->px_dip, f_p->px_fh_sysino);
2086 
2087 	cb_p->cpuid = new_cpuid;
2088 	cb_p->sysino = f_p->px_fh_sysino;
2089 	PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid);
2090 
2091 cb_done:
2092 	mutex_exit(&cb_p->cb_mutex);
2093 }
2094 
2095 /*
2096  * px_cb_add_intr() - Called from attach(9E) to create CB if not yet
2097  * created, to add CB interrupt vector always, but enable only once.
2098  */
2099 int
2100 px_cb_add_intr(px_fault_t *fault_p)
2101 {
2102 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip);
2103 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
2104 	px_cb_t		*cb_p = (px_cb_t *)px_get_cb(fault_p->px_fh_dip);
2105 	px_cb_list_t	*pxl, *pxl_new;
2106 	boolean_t	is_proxy = B_FALSE;
2107 
2108 	/* create cb */
2109 	if (cb_p == NULL) {
2110 		cb_p = kmem_zalloc(sizeof (px_cb_t), KM_SLEEP);
2111 
2112 		mutex_init(&cb_p->cb_mutex, NULL, MUTEX_DRIVER,
2113 		    (void *) ipltospl(FM_ERR_PIL));
2114 
2115 		cb_p->px_cb_func = px_cb_intr;
2116 		pxu_p->px_cb_p = cb_p;
2117 		px_set_cb(fault_p->px_fh_dip, (uint64_t)cb_p);
2118 
2119 		/* px_lib_dev_init allows only FIRE and OBERON */
2120 		px_err_reg_enable(
2121 		    (pxu_p->chip_type == PX_CHIP_FIRE) ?
2122 			PX_ERR_JBC : PX_ERR_UBC,
2123 		    pxu_p->px_address[PX_REG_XBC]);
2124 	} else
2125 		pxu_p->px_cb_p = cb_p;
2126 
2127 	/* register cb interrupt */
2128 	VERIFY(add_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL,
2129 	    (intrfunc)cb_p->px_cb_func, (caddr_t)cb_p, NULL, NULL) == 0);
2130 
2131 
2132 	/* update cb list */
2133 	mutex_enter(&cb_p->cb_mutex);
2134 	if (cb_p->pxl == NULL) {
2135 		is_proxy = B_TRUE;
2136 		pxl = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP);
2137 		pxl->pxp = px_p;
2138 		cb_p->pxl = pxl;
2139 		cb_p->sysino = fault_p->px_fh_sysino;
2140 		cb_p->cpuid = intr_dist_cpuid();
2141 	} else {
2142 		/*
2143 		 * Find the last pxl or
2144 		 * stop short at encountering a redundent entry, or
2145 		 * both.
2146 		 */
2147 		pxl = cb_p->pxl;
2148 		for (; !(pxl->pxp == px_p) && pxl->next; pxl = pxl->next);
2149 		ASSERT(pxl->pxp != px_p);
2150 
2151 		/* add to linked list */
2152 		pxl_new = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP);
2153 		pxl_new->pxp = px_p;
2154 		pxl->next = pxl_new;
2155 	}
2156 	cb_p->attachcnt++;
2157 	mutex_exit(&cb_p->cb_mutex);
2158 
2159 	if (is_proxy) {
2160 		/* add to interrupt redistribution list */
2161 		intr_dist_add(px_cb_intr_redist, cb_p);
2162 
2163 		/* enable cb hw interrupt */
2164 		px_ib_intr_enable(px_p, cb_p->cpuid, fault_p->px_intr_ino);
2165 	}
2166 
2167 	return (DDI_SUCCESS);
2168 }
2169 
2170 /*
2171  * px_cb_rem_intr() - Called from detach(9E) to remove its CB
2172  * interrupt vector, to shift proxy to the next available px,
2173  * or disable CB interrupt when itself is the last.
2174  */
2175 void
2176 px_cb_rem_intr(px_fault_t *fault_p)
2177 {
2178 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip), *pxp;
2179 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
2180 	px_cb_t		*cb_p = PX2CB(px_p);
2181 	px_cb_list_t	*pxl, *prev;
2182 	px_fault_t	*f_p;
2183 
2184 	ASSERT(cb_p->pxl);
2185 
2186 	/* find and remove this px, and update cb list */
2187 	mutex_enter(&cb_p->cb_mutex);
2188 
2189 	pxl = cb_p->pxl;
2190 	if (pxl->pxp == px_p) {
2191 		cb_p->pxl = pxl->next;
2192 	} else {
2193 		prev = pxl;
2194 		pxl = pxl->next;
2195 		for (; pxl && (pxl->pxp != px_p); prev = pxl, pxl = pxl->next);
2196 		if (!pxl) {
2197 			cmn_err(CE_WARN, "px_cb_rem_intr: can't find px_p 0x%p "
2198 			    "in registered CB list.", (void *)px_p);
2199 			mutex_exit(&cb_p->cb_mutex);
2200 			return;
2201 		}
2202 		prev->next = pxl->next;
2203 	}
2204 	pxu_p->px_cb_p = NULL;
2205 	cb_p->attachcnt--;
2206 	kmem_free(pxl, sizeof (px_cb_list_t));
2207 	mutex_exit(&cb_p->cb_mutex);
2208 
2209 	/* disable cb hw interrupt */
2210 	if (fault_p->px_fh_sysino == cb_p->sysino)
2211 		px_ib_intr_disable(px_p->px_ib_p, fault_p->px_intr_ino,
2212 		    IB_INTR_WAIT);
2213 
2214 	/* if last px, remove from interrupt redistribution list */
2215 	if (cb_p->pxl == NULL)
2216 		intr_dist_rem(px_cb_intr_redist, cb_p);
2217 
2218 	/* de-register interrupt */
2219 	VERIFY(rem_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL) == 0);
2220 
2221 	/* if not last px, assign next px to manage cb */
2222 	mutex_enter(&cb_p->cb_mutex);
2223 	if (cb_p->pxl) {
2224 		if (fault_p->px_fh_sysino == cb_p->sysino) {
2225 			pxp = cb_p->pxl->pxp;
2226 			f_p = &pxp->px_cb_fault;
2227 			cb_p->sysino = f_p->px_fh_sysino;
2228 
2229 			PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid);
2230 			(void) px_lib_intr_setstate(pxp->px_dip, cb_p->sysino,
2231 			    INTR_IDLE_STATE);
2232 		}
2233 		mutex_exit(&cb_p->cb_mutex);
2234 		return;
2235 	}
2236 
2237 	/* clean up after the last px */
2238 	mutex_exit(&cb_p->cb_mutex);
2239 
2240 	/* px_lib_dev_init allows only FIRE and OBERON */
2241 	px_err_reg_disable(
2242 	    (pxu_p->chip_type == PX_CHIP_FIRE) ? PX_ERR_JBC : PX_ERR_UBC,
2243 	    pxu_p->px_address[PX_REG_XBC]);
2244 
2245 	mutex_destroy(&cb_p->cb_mutex);
2246 	px_set_cb(fault_p->px_fh_dip, 0ull);
2247 	kmem_free(cb_p, sizeof (px_cb_t));
2248 }
2249 
2250 /*
2251  * px_cb_intr() - sun4u only,  CB interrupt dispatcher
2252  */
2253 uint_t
2254 px_cb_intr(caddr_t arg)
2255 {
2256 	px_cb_t		*cb_p = (px_cb_t *)arg;
2257 	px_t		*pxp;
2258 	px_fault_t	*f_p;
2259 	int		ret;
2260 
2261 	mutex_enter(&cb_p->cb_mutex);
2262 
2263 	if (!cb_p->pxl) {
2264 		mutex_exit(&cb_p->cb_mutex);
2265 		return (DDI_INTR_UNCLAIMED);
2266 	}
2267 
2268 	pxp = cb_p->pxl->pxp;
2269 	f_p = &pxp->px_cb_fault;
2270 
2271 	ret = f_p->px_err_func((caddr_t)f_p);
2272 
2273 	mutex_exit(&cb_p->cb_mutex);
2274 	return (ret);
2275 }
2276 
2277 #ifdef	FMA
2278 void
2279 px_fill_rc_status(px_fault_t *px_fault_p, pciex_rc_error_regs_t *rc_status)
2280 {
2281 	/* populate the rc_status by reading the registers - TBD */
2282 }
2283 #endif /* FMA */
2284 
2285 /*
2286  * Unprotected raw reads/writes of fabric device's config space.
2287  * Only used for temporary PCI-E Fabric Error Handling.
2288  */
2289 uint32_t
2290 px_fab_get(px_t *px_p, pcie_req_id_t bdf, uint16_t offset)
2291 {
2292 	px_ranges_t	*rp = px_p->px_ranges_p;
2293 	uint64_t	range_prop, base_addr;
2294 	int		bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
2295 	uint32_t	val;
2296 
2297 	/* Get Fire's Physical Base Address */
2298 	range_prop = px_get_range_prop(px_p, rp, bank);
2299 
2300 	/* Get config space first. */
2301 	base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset);
2302 
2303 	val = ldphysio(base_addr);
2304 
2305 	return (LE_32(val));
2306 }
2307 
2308 void
2309 px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset,
2310     uint32_t val) {
2311 	px_ranges_t	*rp = px_p->px_ranges_p;
2312 	uint64_t	range_prop, base_addr;
2313 	int		bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
2314 
2315 	/* Get Fire's Physical Base Address */
2316 	range_prop = px_get_range_prop(px_p, rp, bank);
2317 
2318 	/* Get config space first. */
2319 	base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset);
2320 
2321 	stphysio(base_addr, LE_32(val));
2322 }
2323 
2324 /*
2325  * cpr callback
2326  *
2327  * disable fabric error msg interrupt prior to suspending
2328  * all device drivers; re-enable fabric error msg interrupt
2329  * after all devices are resumed.
2330  */
2331 static boolean_t
2332 px_cpr_callb(void *arg, int code)
2333 {
2334 	px_t		*px_p = (px_t *)arg;
2335 	px_ib_t		*ib_p = px_p->px_ib_p;
2336 	px_pec_t	*pec_p = px_p->px_pec_p;
2337 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
2338 	caddr_t		csr_base;
2339 	devino_t	ce_ino, nf_ino, f_ino;
2340 	px_ino_t	*ce_ino_p, *nf_ino_p, *f_ino_p;
2341 	uint64_t	imu_log_enable, imu_intr_enable;
2342 	uint64_t	imu_log_mask, imu_intr_mask;
2343 
2344 	ce_ino = px_msiqid_to_devino(px_p, pec_p->pec_corr_msg_msiq_id);
2345 	nf_ino = px_msiqid_to_devino(px_p, pec_p->pec_non_fatal_msg_msiq_id);
2346 	f_ino = px_msiqid_to_devino(px_p, pec_p->pec_fatal_msg_msiq_id);
2347 	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
2348 
2349 	imu_log_enable = CSR_XR(csr_base, IMU_ERROR_LOG_ENABLE);
2350 	imu_intr_enable = CSR_XR(csr_base, IMU_INTERRUPT_ENABLE);
2351 
2352 	imu_log_mask = BITMASK(IMU_ERROR_LOG_ENABLE_FATAL_MES_NOT_EN_LOG_EN) |
2353 	    BITMASK(IMU_ERROR_LOG_ENABLE_NONFATAL_MES_NOT_EN_LOG_EN) |
2354 	    BITMASK(IMU_ERROR_LOG_ENABLE_COR_MES_NOT_EN_LOG_EN);
2355 
2356 	imu_intr_mask =
2357 	    BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_S_INT_EN) |
2358 	    BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_S_INT_EN) |
2359 	    BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_S_INT_EN) |
2360 	    BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_P_INT_EN) |
2361 	    BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_P_INT_EN) |
2362 	    BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_P_INT_EN);
2363 
2364 	switch (code) {
2365 	case CB_CODE_CPR_CHKPT:
2366 		/* disable imu rbne on corr/nonfatal/fatal errors */
2367 		CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE,
2368 		    imu_log_enable & (~imu_log_mask));
2369 
2370 		CSR_XS(csr_base, IMU_INTERRUPT_ENABLE,
2371 		    imu_intr_enable & (~imu_intr_mask));
2372 
2373 		/* disable CORR intr mapping */
2374 		px_ib_intr_disable(ib_p, ce_ino, IB_INTR_NOWAIT);
2375 
2376 		/* disable NON FATAL intr mapping */
2377 		px_ib_intr_disable(ib_p, nf_ino, IB_INTR_NOWAIT);
2378 
2379 		/* disable FATAL intr mapping */
2380 		px_ib_intr_disable(ib_p, f_ino, IB_INTR_NOWAIT);
2381 
2382 		break;
2383 
2384 	case CB_CODE_CPR_RESUME:
2385 		pxu_p->cpr_flag = PX_NOT_CPR;
2386 		mutex_enter(&ib_p->ib_ino_lst_mutex);
2387 
2388 		ce_ino_p = px_ib_locate_ino(ib_p, ce_ino);
2389 		nf_ino_p = px_ib_locate_ino(ib_p, nf_ino);
2390 		f_ino_p = px_ib_locate_ino(ib_p, f_ino);
2391 
2392 		/* enable CORR intr mapping */
2393 		if (ce_ino_p)
2394 			px_ib_intr_enable(px_p, ce_ino_p->ino_cpuid, ce_ino);
2395 		else
2396 			cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to "
2397 			    "reenable PCIe Correctable msg intr.\n");
2398 
2399 		/* enable NON FATAL intr mapping */
2400 		if (nf_ino_p)
2401 			px_ib_intr_enable(px_p, nf_ino_p->ino_cpuid, nf_ino);
2402 		else
2403 			cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to "
2404 			    "reenable PCIe Non Fatal msg intr.\n");
2405 
2406 		/* enable FATAL intr mapping */
2407 		if (f_ino_p)
2408 			px_ib_intr_enable(px_p, f_ino_p->ino_cpuid, f_ino);
2409 		else
2410 			cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to "
2411 			    "reenable PCIe Fatal msg intr.\n");
2412 
2413 		mutex_exit(&ib_p->ib_ino_lst_mutex);
2414 
2415 		/* enable corr/nonfatal/fatal not enable error */
2416 		CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE, (imu_log_enable |
2417 		    (imu_log_mask & px_imu_log_mask)));
2418 		CSR_XS(csr_base, IMU_INTERRUPT_ENABLE, (imu_intr_enable |
2419 		    (imu_intr_mask & px_imu_intr_mask)));
2420 
2421 		break;
2422 	}
2423 
2424 	return (B_TRUE);
2425 }
2426 
2427 uint64_t
2428 px_get_rng_parent_hi_mask(px_t *px_p)
2429 {
2430 	pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p;
2431 	uint64_t mask;
2432 
2433 	switch (PX_CHIP_TYPE(pxu_p)) {
2434 	case PX_CHIP_OBERON:
2435 		mask = OBERON_RANGE_PROP_MASK;
2436 		break;
2437 	case PX_CHIP_FIRE:
2438 		mask = PX_RANGE_PROP_MASK;
2439 		break;
2440 	default:
2441 		mask = PX_RANGE_PROP_MASK;
2442 	}
2443 
2444 	return (mask);
2445 }
2446 
2447 /*
2448  * fetch chip's range propery's value
2449  */
2450 uint64_t
2451 px_get_range_prop(px_t *px_p, px_ranges_t *rp, int bank)
2452 {
2453 	uint64_t mask, range_prop;
2454 
2455 	mask = px_get_rng_parent_hi_mask(px_p);
2456 	range_prop = (((uint64_t)(rp[bank].parent_high & mask)) << 32) |
2457 		rp[bank].parent_low;
2458 
2459 	return (range_prop);
2460 }
2461 
2462 /*
2463  * add cpr callback
2464  */
2465 void
2466 px_cpr_add_callb(px_t *px_p)
2467 {
2468 	px_p->px_cprcb_id = callb_add(px_cpr_callb, (void *)px_p,
2469 	CB_CL_CPR_POST_USER, "px_cpr");
2470 }
2471 
2472 /*
2473  * remove cpr callback
2474  */
2475 void
2476 px_cpr_rem_callb(px_t *px_p)
2477 {
2478 	(void) callb_delete(px_p->px_cprcb_id);
2479 }
2480 
2481 /*ARGSUSED*/
2482 static uint_t
2483 px_hp_intr(caddr_t arg1, caddr_t arg2)
2484 {
2485 	px_t *px_p = (px_t *)arg1;
2486 	int rval;
2487 
2488 	rval = pciehpc_intr(px_p->px_dip);
2489 
2490 #ifdef  DEBUG
2491 	if (rval == DDI_INTR_UNCLAIMED)
2492 	    cmn_err(CE_WARN, "%s%d: UNCLAIMED intr\n",
2493 		ddi_driver_name(px_p->px_dip),
2494 		ddi_get_instance(px_p->px_dip));
2495 #endif
2496 
2497 	return (rval);
2498 }
2499 
2500 int
2501 px_lib_hotplug_init(dev_info_t *dip, void *arg)
2502 {
2503 	px_t	*px_p = DIP_TO_STATE(dip);
2504 	uint64_t ret;
2505 
2506 	if ((ret = hvio_hotplug_init(dip, arg)) == DDI_SUCCESS) {
2507 		sysino_t sysino;
2508 
2509 		if (px_lib_intr_devino_to_sysino(px_p->px_dip,
2510 		    px_p->px_inos[PX_INTR_HOTPLUG], &sysino) !=
2511 		    DDI_SUCCESS) {
2512 #ifdef	DEBUG
2513 			cmn_err(CE_WARN, "%s%d: devino_to_sysino fails\n",
2514 			    ddi_driver_name(px_p->px_dip),
2515 			    ddi_get_instance(px_p->px_dip));
2516 #endif
2517 			return (DDI_FAILURE);
2518 		}
2519 
2520 		VERIFY(add_ivintr(sysino, PX_PCIEHP_PIL,
2521 		    (intrfunc)px_hp_intr, (caddr_t)px_p, NULL, NULL) == 0);
2522 
2523 		px_ib_intr_enable(px_p, intr_dist_cpuid(),
2524 		    px_p->px_inos[PX_INTR_HOTPLUG]);
2525 	}
2526 
2527 	return (ret);
2528 }
2529 
2530 void
2531 px_lib_hotplug_uninit(dev_info_t *dip)
2532 {
2533 	if (hvio_hotplug_uninit(dip) == DDI_SUCCESS) {
2534 		px_t	*px_p = DIP_TO_STATE(dip);
2535 		sysino_t sysino;
2536 
2537 		if (px_lib_intr_devino_to_sysino(px_p->px_dip,
2538 		    px_p->px_inos[PX_INTR_HOTPLUG], &sysino) !=
2539 		    DDI_SUCCESS) {
2540 #ifdef	DEBUG
2541 			cmn_err(CE_WARN, "%s%d: devino_to_sysino fails\n",
2542 			    ddi_driver_name(px_p->px_dip),
2543 			    ddi_get_instance(px_p->px_dip));
2544 #endif
2545 			return;
2546 		}
2547 
2548 		px_ib_intr_disable(px_p->px_ib_p,
2549 		    px_p->px_inos[PX_INTR_HOTPLUG], IB_INTR_WAIT);
2550 
2551 		VERIFY(rem_ivintr(sysino, PX_PCIEHP_PIL) == 0);
2552 	}
2553 }
2554 
2555 /*
2556  * px_hp_intr_redist() - sun4u only, HP interrupt redistribution
2557  */
2558 void
2559 px_hp_intr_redist(px_t *px_p)
2560 {
2561 	if (px_p && (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)) {
2562 		px_ib_intr_dist_en(px_p->px_dip, intr_dist_cpuid(),
2563 		    px_p->px_inos[PX_INTR_HOTPLUG], B_FALSE);
2564 	}
2565 }
2566 
2567 boolean_t
2568 px_lib_is_in_drain_state(px_t *px_p)
2569 {
2570 	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
2571 	caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
2572 	uint64_t drain_status;
2573 
2574 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) {
2575 		drain_status = CSR_BR(csr_base, DRAIN_CONTROL_STATUS, DRAIN);
2576 	} else {
2577 		drain_status = CSR_BR(csr_base, TLU_STATUS, DRAIN);
2578 	}
2579 
2580 	return (drain_status);
2581 }
2582 
2583 pcie_req_id_t
2584 px_lib_get_bdf(px_t *px_p)
2585 {
2586 	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
2587 	caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
2588 	pcie_req_id_t bdf;
2589 
2590 	bdf = CSR_BR(csr_base, DMC_PCI_EXPRESS_CONFIGURATION, REQ_ID);
2591 
2592 	return (bdf);
2593 }
2594