xref: /illumos-gate/usr/src/uts/sun4u/io/px/px_lib4u.c (revision e214b19e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57aadd8d4Skini  * Common Development and Distribution License (the "License").
67aadd8d4Skini  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2289b42a21Sandrew.rutz@sun.com  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/types.h>
267c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
277c478bd9Sstevel@tonic-gate #include <sys/conf.h>
287c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
297c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
30eae2e508Skrishnae #include <sys/sunndi.h>
31f8d2de6bSjchu #include <sys/fm/protocol.h>
32f8d2de6bSjchu #include <sys/fm/util.h>
337c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
347c478bd9Sstevel@tonic-gate #include <sys/disp.h>
357c478bd9Sstevel@tonic-gate #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
377c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
387c478bd9Sstevel@tonic-gate #include <sys/iommutsb.h>
397c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
40f8d2de6bSjchu #include <sys/ivintr.h>
418bc7d88aSet #include <sys/byteorder.h>
42a3c68edcSjchu #include <sys/spl.h>
437c478bd9Sstevel@tonic-gate #include <px_obj.h>
44d4bc0535SKrishna Elango #include <sys/pcie_pwr.h>
4525cf1a30Sjl #include "px_tools_var.h"
467c478bd9Sstevel@tonic-gate #include <px_regs.h>
477c478bd9Sstevel@tonic-gate #include <px_csr.h>
48f8d2de6bSjchu #include <sys/machsystm.h>
497c478bd9Sstevel@tonic-gate #include "px_lib4u.h"
50f8d2de6bSjchu #include "px_err.h"
5125cf1a30Sjl #include "oberon_regs.h"
5226947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #pragma weak jbus_stst_order
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate extern void jbus_stst_order();
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate ulong_t px_mmu_dvma_end = 0xfffffffful;
597c478bd9Sstevel@tonic-gate uint_t px_ranges_phi_mask = 0xfffffffful;
6025cf1a30Sjl uint64_t *px_oberon_ubc_scratch_regs;
61f0a73f04Sschwartz uint64_t px_paddr_mask;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static int px_goto_l23ready(px_t *px_p);
641a887b2eSjchu static int px_goto_l0(px_t *px_p);
651a887b2eSjchu static int px_pre_pwron_check(px_t *px_p);
667e1db6d2Sschwartz static uint32_t px_identity_init(px_t *px_p);
67817a6df8Sjchu static boolean_t px_cpr_callb(void *arg, int code);
6801689544Sjchu static uint_t px_cb_intr(caddr_t arg);
69f8d2de6bSjchu 
700114761dSAlan Adamson, SD OSSD /*
710114761dSAlan Adamson, SD OSSD  * ACKNAK Latency Threshold Table.
720114761dSAlan Adamson, SD OSSD  * See Fire PRM 2.0 section 1.2.12.2, table 1-17.
730114761dSAlan Adamson, SD OSSD  */
740114761dSAlan Adamson, SD OSSD int px_acknak_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE] = {
750114761dSAlan Adamson, SD OSSD 	{0xED,   0x49,  0x43,  0x30},
760114761dSAlan Adamson, SD OSSD 	{0x1A0,  0x76,  0x6B,  0x48},
770114761dSAlan Adamson, SD OSSD 	{0x22F,  0x9A,  0x56,  0x56},
780114761dSAlan Adamson, SD OSSD 	{0x42F,  0x11A, 0x96,  0x96},
790114761dSAlan Adamson, SD OSSD 	{0x82F,  0x21A, 0x116, 0x116},
800114761dSAlan Adamson, SD OSSD 	{0x102F, 0x41A, 0x216, 0x216}
810114761dSAlan Adamson, SD OSSD };
820114761dSAlan Adamson, SD OSSD 
830114761dSAlan Adamson, SD OSSD /*
840114761dSAlan Adamson, SD OSSD  * TxLink Replay Timer Latency Table
850114761dSAlan Adamson, SD OSSD  * See Fire PRM 2.0 sections 1.2.12.3, table 1-18.
860114761dSAlan Adamson, SD OSSD  */
870114761dSAlan Adamson, SD OSSD int px_replay_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE] = {
880114761dSAlan Adamson, SD OSSD 	{0x379,  0x112, 0xFC,  0xB4},
890114761dSAlan Adamson, SD OSSD 	{0x618,  0x1BA, 0x192, 0x10E},
900114761dSAlan Adamson, SD OSSD 	{0x831,  0x242, 0x143, 0x143},
910114761dSAlan Adamson, SD OSSD 	{0xFB1,  0x422, 0x233, 0x233},
920114761dSAlan Adamson, SD OSSD 	{0x1EB0, 0x7E1, 0x412, 0x412},
930114761dSAlan Adamson, SD OSSD 	{0x3CB0, 0xF61, 0x7D2, 0x7D2}
940114761dSAlan Adamson, SD OSSD };
95f8d2de6bSjchu /*
96f8d2de6bSjchu  * px_lib_map_registers
97f8d2de6bSjchu  *
98f8d2de6bSjchu  * This function is called from the attach routine to map the registers
99f8d2de6bSjchu  * accessed by this driver.
100f8d2de6bSjchu  *
101f8d2de6bSjchu  * used by: px_attach()
102f8d2de6bSjchu  *
103f8d2de6bSjchu  * return value: DDI_FAILURE on failure
104f8d2de6bSjchu  */
105f8d2de6bSjchu int
px_lib_map_regs(pxu_t * pxu_p,dev_info_t * dip)106f8d2de6bSjchu px_lib_map_regs(pxu_t *pxu_p, dev_info_t *dip)
107f8d2de6bSjchu {
108f8d2de6bSjchu 	ddi_device_acc_attr_t	attr;
109f8d2de6bSjchu 	px_reg_bank_t		reg_bank = PX_REG_CSR;
110f8d2de6bSjchu 
111f8d2de6bSjchu 	DBG(DBG_ATTACH, dip, "px_lib_map_regs: pxu_p:0x%p, dip 0x%p\n",
112eae2e508Skrishnae 	    pxu_p, dip);
113f8d2de6bSjchu 
114f8d2de6bSjchu 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
115f8d2de6bSjchu 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
116f8d2de6bSjchu 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
117f8d2de6bSjchu 
118f8d2de6bSjchu 	/*
119f8d2de6bSjchu 	 * PCI CSR Base
120f8d2de6bSjchu 	 */
121f8d2de6bSjchu 	if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank],
122f8d2de6bSjchu 	    0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) {
123f8d2de6bSjchu 		goto fail;
124f8d2de6bSjchu 	}
125f8d2de6bSjchu 
126f8d2de6bSjchu 	reg_bank++;
127f8d2de6bSjchu 
128f8d2de6bSjchu 	/*
129f8d2de6bSjchu 	 * XBUS CSR Base
130f8d2de6bSjchu 	 */
131f8d2de6bSjchu 	if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank],
132f8d2de6bSjchu 	    0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) {
133f8d2de6bSjchu 		goto fail;
134f8d2de6bSjchu 	}
135f8d2de6bSjchu 
136f8d2de6bSjchu 	pxu_p->px_address[reg_bank] -= FIRE_CONTROL_STATUS;
137f8d2de6bSjchu 
138f8d2de6bSjchu done:
139f8d2de6bSjchu 	for (; reg_bank >= PX_REG_CSR; reg_bank--) {
140f8d2de6bSjchu 		DBG(DBG_ATTACH, dip, "reg_bank 0x%x address 0x%p\n",
141f8d2de6bSjchu 		    reg_bank, pxu_p->px_address[reg_bank]);
142f8d2de6bSjchu 	}
143f8d2de6bSjchu 
144f8d2de6bSjchu 	return (DDI_SUCCESS);
145f8d2de6bSjchu 
146f8d2de6bSjchu fail:
147f8d2de6bSjchu 	cmn_err(CE_WARN, "%s%d: unable to map reg entry %d\n",
148f8d2de6bSjchu 	    ddi_driver_name(dip), ddi_get_instance(dip), reg_bank);
149f8d2de6bSjchu 
150f8d2de6bSjchu 	for (reg_bank--; reg_bank >= PX_REG_CSR; reg_bank--) {
151f8d2de6bSjchu 		pxu_p->px_address[reg_bank] = NULL;
152f8d2de6bSjchu 		ddi_regs_map_free(&pxu_p->px_ac[reg_bank]);
153f8d2de6bSjchu 	}
154f8d2de6bSjchu 
155f8d2de6bSjchu 	return (DDI_FAILURE);
156f8d2de6bSjchu }
157f8d2de6bSjchu 
158f8d2de6bSjchu /*
159f8d2de6bSjchu  * px_lib_unmap_regs:
160f8d2de6bSjchu  *
161f8d2de6bSjchu  * This routine unmaps the registers mapped by map_px_registers.
162f8d2de6bSjchu  *
163f8d2de6bSjchu  * used by: px_detach(), and error conditions in px_attach()
164f8d2de6bSjchu  *
165f8d2de6bSjchu  * return value: none
166f8d2de6bSjchu  */
167f8d2de6bSjchu void
px_lib_unmap_regs(pxu_t * pxu_p)168f8d2de6bSjchu px_lib_unmap_regs(pxu_t *pxu_p)
169f8d2de6bSjchu {
170f8d2de6bSjchu 	int i;
171f8d2de6bSjchu 
172f8d2de6bSjchu 	for (i = 0; i < PX_REG_MAX; i++) {
173f8d2de6bSjchu 		if (pxu_p->px_ac[i])
174f8d2de6bSjchu 			ddi_regs_map_free(&pxu_p->px_ac[i]);
175f8d2de6bSjchu 	}
176f8d2de6bSjchu }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate int
px_lib_dev_init(dev_info_t * dip,devhandle_t * dev_hdl)1797c478bd9Sstevel@tonic-gate px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl)
1807c478bd9Sstevel@tonic-gate {
18108a74c0dSschwartz 
18208a74c0dSschwartz 	caddr_t			xbc_csr_base, csr_base;
1837c478bd9Sstevel@tonic-gate 	px_dvma_range_prop_t	px_dvma_range;
18408a74c0dSschwartz 	pxu_t			*pxu_p;
18508a74c0dSschwartz 	uint8_t			chip_mask;
18608a74c0dSschwartz 	px_t			*px_p = DIP_TO_STATE(dip);
18708a74c0dSschwartz 	px_chip_type_t		chip_type = px_identity_init(px_p);
1887c478bd9Sstevel@tonic-gate 
1897e1db6d2Sschwartz 	DBG(DBG_ATTACH, dip, "px_lib_dev_init: dip 0x%p", dip);
1907c478bd9Sstevel@tonic-gate 
1917e1db6d2Sschwartz 	if (chip_type == PX_CHIP_UNIDENTIFIED) {
1927e1db6d2Sschwartz 		cmn_err(CE_WARN, "%s%d: Unrecognized Hardware Version\n",
1937e1db6d2Sschwartz 		    NAMEINST(dip));
1947c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate 
19708a74c0dSschwartz 	chip_mask = BITMASK(chip_type);
1987e1db6d2Sschwartz 	px_paddr_mask = (chip_type == PX_CHIP_FIRE) ? MMU_FIRE_PADDR_MASK :
1997e1db6d2Sschwartz 	    MMU_OBERON_PADDR_MASK;
2007e1db6d2Sschwartz 
2017c478bd9Sstevel@tonic-gate 	/*
2027c478bd9Sstevel@tonic-gate 	 * Allocate platform specific structure and link it to
2037c478bd9Sstevel@tonic-gate 	 * the px state structure.
2047c478bd9Sstevel@tonic-gate 	 */
2057c478bd9Sstevel@tonic-gate 	pxu_p = kmem_zalloc(sizeof (pxu_t), KM_SLEEP);
2067e1db6d2Sschwartz 	pxu_p->chip_type = chip_type;
2077c478bd9Sstevel@tonic-gate 	pxu_p->portid  = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2087c478bd9Sstevel@tonic-gate 	    "portid", -1);
2097c478bd9Sstevel@tonic-gate 
210f8d2de6bSjchu 	/* Map in the registers */
211f8d2de6bSjchu 	if (px_lib_map_regs(pxu_p, dip) == DDI_FAILURE) {
212f8d2de6bSjchu 		kmem_free(pxu_p, sizeof (pxu_t));
213f8d2de6bSjchu 
214f8d2de6bSjchu 		return (DDI_FAILURE);
215f8d2de6bSjchu 	}
216f8d2de6bSjchu 
217f8d2de6bSjchu 	xbc_csr_base = (caddr_t)pxu_p->px_address[PX_REG_XBC];
218f8d2de6bSjchu 	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
219f8d2de6bSjchu 
2207c478bd9Sstevel@tonic-gate 	pxu_p->tsb_cookie = iommu_tsb_alloc(pxu_p->portid);
2217c478bd9Sstevel@tonic-gate 	pxu_p->tsb_size = iommu_tsb_cookie_to_size(pxu_p->tsb_cookie);
2227c478bd9Sstevel@tonic-gate 	pxu_p->tsb_vaddr = iommu_tsb_cookie_to_va(pxu_p->tsb_cookie);
2237c478bd9Sstevel@tonic-gate 
22425cf1a30Sjl 	pxu_p->tsb_paddr = va_to_pa(pxu_p->tsb_vaddr);
22525cf1a30Sjl 
2267c478bd9Sstevel@tonic-gate 	/*
2277c478bd9Sstevel@tonic-gate 	 * Create "virtual-dma" property to support child devices
2287c478bd9Sstevel@tonic-gate 	 * needing to know DVMA range.
2297c478bd9Sstevel@tonic-gate 	 */
2307c478bd9Sstevel@tonic-gate 	px_dvma_range.dvma_base = (uint32_t)px_mmu_dvma_end + 1
2317c478bd9Sstevel@tonic-gate 	    - ((pxu_p->tsb_size >> 3) << MMU_PAGE_SHIFT);
2327c478bd9Sstevel@tonic-gate 	px_dvma_range.dvma_len = (uint32_t)
2337c478bd9Sstevel@tonic-gate 	    px_mmu_dvma_end - px_dvma_range.dvma_base + 1;
2347c478bd9Sstevel@tonic-gate 
2351f7be8d9Sdanice 	(void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
2361f7be8d9Sdanice 	    "virtual-dma", (int *)&px_dvma_range,
2371f7be8d9Sdanice 	    sizeof (px_dvma_range_prop_t) / sizeof (int));
2387c478bd9Sstevel@tonic-gate 	/*
2397c478bd9Sstevel@tonic-gate 	 * Initilize all fire hardware specific blocks.
2407c478bd9Sstevel@tonic-gate 	 */
2417c478bd9Sstevel@tonic-gate 	hvio_cb_init(xbc_csr_base, pxu_p);
2427c478bd9Sstevel@tonic-gate 	hvio_ib_init(csr_base, pxu_p);
2437c478bd9Sstevel@tonic-gate 	hvio_pec_init(csr_base, pxu_p);
2447c478bd9Sstevel@tonic-gate 	hvio_mmu_init(csr_base, pxu_p);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	px_p->px_plat_p = (void *)pxu_p;
2477c478bd9Sstevel@tonic-gate 
248f8d2de6bSjchu 	/*
249f8d2de6bSjchu 	 * Initialize all the interrupt handlers
250f8d2de6bSjchu 	 */
25125cf1a30Sjl 	switch (PX_CHIP_TYPE(pxu_p)) {
25225cf1a30Sjl 	case PX_CHIP_OBERON:
253597077b2Sjj 		/*
254597077b2Sjj 		 * Oberon hotplug uses SPARE3 field in ILU Error Log Enable
255597077b2Sjj 		 * register to indicate the status of leaf reset,
256597077b2Sjj 		 * we need to preserve the value of this bit, and keep it in
257597077b2Sjj 		 * px_ilu_log_mask to reflect the state of the bit
258597077b2Sjj 		 */
259597077b2Sjj 		if (CSR_BR(csr_base, ILU_ERROR_LOG_ENABLE, SPARE3))
260597077b2Sjj 			px_ilu_log_mask |= (1ull <<
261597077b2Sjj 			    ILU_ERROR_LOG_ENABLE_SPARE3);
262597077b2Sjj 		else
263597077b2Sjj 			px_ilu_log_mask &= ~(1ull <<
264597077b2Sjj 			    ILU_ERROR_LOG_ENABLE_SPARE3);
26525cf1a30Sjl 
26608a74c0dSschwartz 		px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE);
26725cf1a30Sjl 		break;
26825cf1a30Sjl 
26925cf1a30Sjl 	case PX_CHIP_FIRE:
27008a74c0dSschwartz 		px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE);
27125cf1a30Sjl 		break;
27208a74c0dSschwartz 
27325cf1a30Sjl 	default:
27425cf1a30Sjl 		cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n",
27525cf1a30Sjl 		    ddi_driver_name(dip), ddi_get_instance(dip));
27625cf1a30Sjl 		return (DDI_FAILURE);
27725cf1a30Sjl 	}
278f8d2de6bSjchu 
2797c478bd9Sstevel@tonic-gate 	/* Initilize device handle */
2807c478bd9Sstevel@tonic-gate 	*dev_hdl = (devhandle_t)csr_base;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	DBG(DBG_ATTACH, dip, "px_lib_dev_init: dev_hdl 0x%llx\n", *dev_hdl);
2837c478bd9Sstevel@tonic-gate 
284fc256490SJason Beloro 	/* Sun4u always support fixed interrupt */
285fc256490SJason Beloro 	px_p->px_supp_intr_types |= DDI_INTR_TYPE_FIXED;
286fc256490SJason Beloro 
2877c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate int
px_lib_dev_fini(dev_info_t * dip)2917c478bd9Sstevel@tonic-gate px_lib_dev_fini(dev_info_t *dip)
2927c478bd9Sstevel@tonic-gate {
29308a74c0dSschwartz 	caddr_t			csr_base;
29408a74c0dSschwartz 	uint8_t			chip_mask;
29508a74c0dSschwartz 	px_t			*px_p = DIP_TO_STATE(dip);
29608a74c0dSschwartz 	pxu_t			*pxu_p = (pxu_t *)px_p->px_plat_p;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	DBG(DBG_DETACH, dip, "px_lib_dev_fini: dip 0x%p\n", dip);
2997c478bd9Sstevel@tonic-gate 
300f8d2de6bSjchu 	/*
301f8d2de6bSjchu 	 * Deinitialize all the interrupt handlers
302f8d2de6bSjchu 	 */
30325cf1a30Sjl 	switch (PX_CHIP_TYPE(pxu_p)) {
30425cf1a30Sjl 	case PX_CHIP_OBERON:
30525cf1a30Sjl 	case PX_CHIP_FIRE:
30608a74c0dSschwartz 		chip_mask = BITMASK(PX_CHIP_TYPE(pxu_p));
30708a74c0dSschwartz 		csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
30808a74c0dSschwartz 		px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_DISABLE);
30925cf1a30Sjl 		break;
31008a74c0dSschwartz 
31125cf1a30Sjl 	default:
31225cf1a30Sjl 		cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n",
31325cf1a30Sjl 		    ddi_driver_name(dip), ddi_get_instance(dip));
31425cf1a30Sjl 		return (DDI_FAILURE);
31525cf1a30Sjl 	}
316f8d2de6bSjchu 
3177c478bd9Sstevel@tonic-gate 	iommu_tsb_free(pxu_p->tsb_cookie);
3187c478bd9Sstevel@tonic-gate 
319f8d2de6bSjchu 	px_lib_unmap_regs((pxu_t *)px_p->px_plat_p);
320f8d2de6bSjchu 	kmem_free(px_p->px_plat_p, sizeof (pxu_t));
3217c478bd9Sstevel@tonic-gate 	px_p->px_plat_p = NULL;
3221f7be8d9Sdanice 	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "virtual-dma");
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3287c478bd9Sstevel@tonic-gate int
px_lib_intr_devino_to_sysino(dev_info_t * dip,devino_t devino,sysino_t * sysino)3297c478bd9Sstevel@tonic-gate px_lib_intr_devino_to_sysino(dev_info_t *dip, devino_t devino,
3307c478bd9Sstevel@tonic-gate     sysino_t *sysino)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate 	px_t	*px_p = DIP_TO_STATE(dip);
3337c478bd9Sstevel@tonic-gate 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
3347c478bd9Sstevel@tonic-gate 	uint64_t	ret;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: dip 0x%p "
3377c478bd9Sstevel@tonic-gate 	    "devino 0x%x\n", dip, devino);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if ((ret = hvio_intr_devino_to_sysino(DIP_TO_HANDLE(dip),
3407c478bd9Sstevel@tonic-gate 	    pxu_p, devino, sysino)) != H_EOK) {
3417c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_INT, dip,
3427c478bd9Sstevel@tonic-gate 		    "hvio_intr_devino_to_sysino failed, ret 0x%lx\n", ret);
3437c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: sysino 0x%llx\n",
3477c478bd9Sstevel@tonic-gate 	    *sysino);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3537c478bd9Sstevel@tonic-gate int
px_lib_intr_getvalid(dev_info_t * dip,sysino_t sysino,intr_valid_state_t * intr_valid_state)3547c478bd9Sstevel@tonic-gate px_lib_intr_getvalid(dev_info_t *dip, sysino_t sysino,
3557c478bd9Sstevel@tonic-gate     intr_valid_state_t *intr_valid_state)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	uint64_t	ret;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: dip 0x%p sysino 0x%llx\n",
3607c478bd9Sstevel@tonic-gate 	    dip, sysino);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if ((ret = hvio_intr_getvalid(DIP_TO_HANDLE(dip),
3637c478bd9Sstevel@tonic-gate 	    sysino, intr_valid_state)) != H_EOK) {
3647c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_INT, dip, "hvio_intr_getvalid failed, ret 0x%lx\n",
3657c478bd9Sstevel@tonic-gate 		    ret);
3667c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: intr_valid_state 0x%x\n",
3707c478bd9Sstevel@tonic-gate 	    *intr_valid_state);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3767c478bd9Sstevel@tonic-gate int
px_lib_intr_setvalid(dev_info_t * dip,sysino_t sysino,intr_valid_state_t intr_valid_state)3777c478bd9Sstevel@tonic-gate px_lib_intr_setvalid(dev_info_t *dip, sysino_t sysino,
3787c478bd9Sstevel@tonic-gate     intr_valid_state_t intr_valid_state)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	uint64_t	ret;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_setvalid: dip 0x%p sysino 0x%llx "
3837c478bd9Sstevel@tonic-gate 	    "intr_valid_state 0x%x\n", dip, sysino, intr_valid_state);
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	if ((ret = hvio_intr_setvalid(DIP_TO_HANDLE(dip),
3867c478bd9Sstevel@tonic-gate 	    sysino, intr_valid_state)) != H_EOK) {
3877c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_INT, dip, "hvio_intr_setvalid failed, ret 0x%lx\n",
3887c478bd9Sstevel@tonic-gate 		    ret);
3897c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3967c478bd9Sstevel@tonic-gate int
px_lib_intr_getstate(dev_info_t * dip,sysino_t sysino,intr_state_t * intr_state)3977c478bd9Sstevel@tonic-gate px_lib_intr_getstate(dev_info_t *dip, sysino_t sysino,
3987c478bd9Sstevel@tonic-gate     intr_state_t *intr_state)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	uint64_t	ret;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: dip 0x%p sysino 0x%llx\n",
4037c478bd9Sstevel@tonic-gate 	    dip, sysino);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	if ((ret = hvio_intr_getstate(DIP_TO_HANDLE(dip),
4067c478bd9Sstevel@tonic-gate 	    sysino, intr_state)) != H_EOK) {
4077c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_INT, dip, "hvio_intr_getstate failed, ret 0x%lx\n",
4087c478bd9Sstevel@tonic-gate 		    ret);
4097c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: intr_state 0x%x\n",
4137c478bd9Sstevel@tonic-gate 	    *intr_state);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4197c478bd9Sstevel@tonic-gate int
px_lib_intr_setstate(dev_info_t * dip,sysino_t sysino,intr_state_t intr_state)4207c478bd9Sstevel@tonic-gate px_lib_intr_setstate(dev_info_t *dip, sysino_t sysino,
4217c478bd9Sstevel@tonic-gate     intr_state_t intr_state)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	uint64_t	ret;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_setstate: dip 0x%p sysino 0x%llx "
4267c478bd9Sstevel@tonic-gate 	    "intr_state 0x%x\n", dip, sysino, intr_state);
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	if ((ret = hvio_intr_setstate(DIP_TO_HANDLE(dip),
4297c478bd9Sstevel@tonic-gate 	    sysino, intr_state)) != H_EOK) {
4307c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_INT, dip, "hvio_intr_setstate failed, ret 0x%lx\n",
4317c478bd9Sstevel@tonic-gate 		    ret);
4327c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4397c478bd9Sstevel@tonic-gate int
px_lib_intr_gettarget(dev_info_t * dip,sysino_t sysino,cpuid_t * cpuid)4407c478bd9Sstevel@tonic-gate px_lib_intr_gettarget(dev_info_t *dip, sysino_t sysino, cpuid_t *cpuid)
4417c478bd9Sstevel@tonic-gate {
44225cf1a30Sjl 	px_t		*px_p = DIP_TO_STATE(dip);
44325cf1a30Sjl 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
4447c478bd9Sstevel@tonic-gate 	uint64_t	ret;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: dip 0x%p sysino 0x%llx\n",
4477c478bd9Sstevel@tonic-gate 	    dip, sysino);
4487c478bd9Sstevel@tonic-gate 
44925cf1a30Sjl 	if ((ret = hvio_intr_gettarget(DIP_TO_HANDLE(dip), pxu_p,
4507c478bd9Sstevel@tonic-gate 	    sysino, cpuid)) != H_EOK) {
4517c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_INT, dip, "hvio_intr_gettarget failed, ret 0x%lx\n",
4527c478bd9Sstevel@tonic-gate 		    ret);
4537c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: cpuid 0x%x\n", cpuid);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4627c478bd9Sstevel@tonic-gate int
px_lib_intr_settarget(dev_info_t * dip,sysino_t sysino,cpuid_t cpuid)4637c478bd9Sstevel@tonic-gate px_lib_intr_settarget(dev_info_t *dip, sysino_t sysino, cpuid_t cpuid)
4647c478bd9Sstevel@tonic-gate {
46525cf1a30Sjl 	px_t		*px_p = DIP_TO_STATE(dip);
46625cf1a30Sjl 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
4677c478bd9Sstevel@tonic-gate 	uint64_t	ret;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_settarget: dip 0x%p sysino 0x%llx "
4707c478bd9Sstevel@tonic-gate 	    "cpuid 0x%x\n", dip, sysino, cpuid);
4717c478bd9Sstevel@tonic-gate 
47225cf1a30Sjl 	if ((ret = hvio_intr_settarget(DIP_TO_HANDLE(dip), pxu_p,
4737c478bd9Sstevel@tonic-gate 	    sysino, cpuid)) != H_EOK) {
4747c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_INT, dip, "hvio_intr_settarget failed, ret 0x%lx\n",
4757c478bd9Sstevel@tonic-gate 		    ret);
4767c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4837c478bd9Sstevel@tonic-gate int
px_lib_intr_reset(dev_info_t * dip)4847c478bd9Sstevel@tonic-gate px_lib_intr_reset(dev_info_t *dip)
4857c478bd9Sstevel@tonic-gate {
4867c478bd9Sstevel@tonic-gate 	devino_t	ino;
4877c478bd9Sstevel@tonic-gate 	sysino_t	sysino;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_INT, dip, "px_lib_intr_reset: dip 0x%p\n", dip);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	/* Reset all Interrupts */
4927c478bd9Sstevel@tonic-gate 	for (ino = 0; ino < INTERRUPT_MAPPING_ENTRIES; ino++) {
4937c478bd9Sstevel@tonic-gate 		if (px_lib_intr_devino_to_sysino(dip, ino,
4947c478bd9Sstevel@tonic-gate 		    &sysino) != DDI_SUCCESS)
4957c478bd9Sstevel@tonic-gate 			return (BF_FATAL);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 		if (px_lib_intr_setstate(dip, sysino,
4987c478bd9Sstevel@tonic-gate 		    INTR_IDLE_STATE) != DDI_SUCCESS)
4997c478bd9Sstevel@tonic-gate 			return (BF_FATAL);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	return (BF_NONE);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5067c478bd9Sstevel@tonic-gate int
px_lib_iommu_map(dev_info_t * dip,tsbid_t tsbid,pages_t pages,io_attributes_t attr,void * addr,size_t pfn_index,int flags)5077c478bd9Sstevel@tonic-gate px_lib_iommu_map(dev_info_t *dip, tsbid_t tsbid, pages_t pages,
50844bb982bSgovinda     io_attributes_t attr, void *addr, size_t pfn_index, int flags)
5097c478bd9Sstevel@tonic-gate {
5107c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
5117c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
5127c478bd9Sstevel@tonic-gate 	uint64_t	ret;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_map: dip 0x%p tsbid 0x%llx "
515ef2504f2SDaniel Ice 	    "pages 0x%x attr 0x%llx addr 0x%p pfn_index 0x%llx flags 0x%x\n",
51644bb982bSgovinda 	    dip, tsbid, pages, attr, addr, pfn_index, flags);
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	if ((ret = hvio_iommu_map(px_p->px_dev_hdl, pxu_p, tsbid, pages,
51944bb982bSgovinda 	    attr, addr, pfn_index, flags)) != H_EOK) {
5207c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_DMA, dip,
5217c478bd9Sstevel@tonic-gate 		    "px_lib_iommu_map failed, ret 0x%lx\n", ret);
5227c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5297c478bd9Sstevel@tonic-gate int
px_lib_iommu_demap(dev_info_t * dip,tsbid_t tsbid,pages_t pages)5307c478bd9Sstevel@tonic-gate px_lib_iommu_demap(dev_info_t *dip, tsbid_t tsbid, pages_t pages)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
5337c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
5347c478bd9Sstevel@tonic-gate 	uint64_t	ret;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_demap: dip 0x%p tsbid 0x%llx "
5377c478bd9Sstevel@tonic-gate 	    "pages 0x%x\n", dip, tsbid, pages);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	if ((ret = hvio_iommu_demap(px_p->px_dev_hdl, pxu_p, tsbid, pages))
5407c478bd9Sstevel@tonic-gate 	    != H_EOK) {
5417c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_DMA, dip,
5427c478bd9Sstevel@tonic-gate 		    "px_lib_iommu_demap failed, ret 0x%lx\n", ret);
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5517c478bd9Sstevel@tonic-gate int
px_lib_iommu_getmap(dev_info_t * dip,tsbid_t tsbid,io_attributes_t * attr_p,r_addr_t * r_addr_p)55244bb982bSgovinda px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, io_attributes_t *attr_p,
55344bb982bSgovinda     r_addr_t *r_addr_p)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate 	px_t	*px_p = DIP_TO_STATE(dip);
5567c478bd9Sstevel@tonic-gate 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
5577c478bd9Sstevel@tonic-gate 	uint64_t	ret;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: dip 0x%p tsbid 0x%llx\n",
5607c478bd9Sstevel@tonic-gate 	    dip, tsbid);
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	if ((ret = hvio_iommu_getmap(DIP_TO_HANDLE(dip), pxu_p, tsbid,
56344bb982bSgovinda 	    attr_p, r_addr_p)) != H_EOK) {
5647c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_DMA, dip,
5657c478bd9Sstevel@tonic-gate 		    "hvio_iommu_getmap failed, ret 0x%lx\n", ret);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 		return ((ret == H_ENOMAP) ? DDI_DMA_NOMAPPING:DDI_FAILURE);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
570ef2504f2SDaniel Ice 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: attr 0x%llx "
571ef2504f2SDaniel Ice 	    "r_addr 0x%llx\n", *attr_p, *r_addr_p);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
57689b42a21Sandrew.rutz@sun.com int
px_lib_iommu_detach(px_t * px_p)57789b42a21Sandrew.rutz@sun.com px_lib_iommu_detach(px_t *px_p)
57889b42a21Sandrew.rutz@sun.com {
57989b42a21Sandrew.rutz@sun.com 	/*
58089b42a21Sandrew.rutz@sun.com 	 * Deallocate DVMA addr space that was reserved for OBP TTE's
58189b42a21Sandrew.rutz@sun.com 	 * during Attach.
58289b42a21Sandrew.rutz@sun.com 	 */
58389b42a21Sandrew.rutz@sun.com 	hvio_obptsb_detach(px_p);
58489b42a21Sandrew.rutz@sun.com 
58589b42a21Sandrew.rutz@sun.com 	return (DDI_SUCCESS);
58689b42a21Sandrew.rutz@sun.com }
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate /*
5897c478bd9Sstevel@tonic-gate  * Checks dma attributes against system bypass ranges
5907c478bd9Sstevel@tonic-gate  * The bypass range is determined by the hardware. Return them so the
5917c478bd9Sstevel@tonic-gate  * common code can do generic checking against them.
5927c478bd9Sstevel@tonic-gate  */
5937c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5947c478bd9Sstevel@tonic-gate int
px_lib_dma_bypass_rngchk(dev_info_t * dip,ddi_dma_attr_t * attr_p,uint64_t * lo_p,uint64_t * hi_p)59525cf1a30Sjl px_lib_dma_bypass_rngchk(dev_info_t *dip, ddi_dma_attr_t *attr_p,
59625cf1a30Sjl     uint64_t *lo_p, uint64_t *hi_p)
5977c478bd9Sstevel@tonic-gate {
59825cf1a30Sjl 	px_t	*px_p = DIP_TO_STATE(dip);
59925cf1a30Sjl 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
60025cf1a30Sjl 
60125cf1a30Sjl 	*lo_p = hvio_get_bypass_base(pxu_p);
60225cf1a30Sjl 	*hi_p = hvio_get_bypass_end(pxu_p);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6097c478bd9Sstevel@tonic-gate int
px_lib_iommu_getbypass(dev_info_t * dip,r_addr_t ra,io_attributes_t attr,io_addr_t * io_addr_p)61044bb982bSgovinda px_lib_iommu_getbypass(dev_info_t *dip, r_addr_t ra, io_attributes_t attr,
61144bb982bSgovinda     io_addr_t *io_addr_p)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate 	uint64_t	ret;
61425cf1a30Sjl 	px_t	*px_p = DIP_TO_STATE(dip);
61525cf1a30Sjl 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: dip 0x%p ra 0x%llx "
618ef2504f2SDaniel Ice 	    "attr 0x%llx\n", dip, ra, attr);
6197c478bd9Sstevel@tonic-gate 
62025cf1a30Sjl 	if ((ret = hvio_iommu_getbypass(DIP_TO_HANDLE(dip), pxu_p, ra,
62125cf1a30Sjl 	    attr, io_addr_p)) != H_EOK) {
6227c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_DMA, dip,
6237c478bd9Sstevel@tonic-gate 		    "hvio_iommu_getbypass failed, ret 0x%lx\n", ret);
6247c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: io_addr 0x%llx\n",
6287c478bd9Sstevel@tonic-gate 	    *io_addr_p);
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
633a616a11eSLida.Horn /*
634a616a11eSLida.Horn  * Returns any needed IO address bit(s) for relaxed ordering in IOMMU
635a616a11eSLida.Horn  * bypass mode.
636a616a11eSLida.Horn  */
637a616a11eSLida.Horn uint64_t
px_lib_ro_bypass(dev_info_t * dip,io_attributes_t attr,uint64_t ioaddr)638a616a11eSLida.Horn px_lib_ro_bypass(dev_info_t *dip, io_attributes_t attr, uint64_t ioaddr)
639a616a11eSLida.Horn {
640a616a11eSLida.Horn 	px_t	*px_p = DIP_TO_STATE(dip);
641a616a11eSLida.Horn 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
642a616a11eSLida.Horn 
643a616a11eSLida.Horn 	if ((PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) && (attr & PCI_MAP_ATTR_RO))
644a616a11eSLida.Horn 		return (MMU_OBERON_BYPASS_RO | ioaddr);
645a616a11eSLida.Horn 	else
646a616a11eSLida.Horn 		return (ioaddr);
647a616a11eSLida.Horn }
648a616a11eSLida.Horn 
6497c478bd9Sstevel@tonic-gate /*
6507c478bd9Sstevel@tonic-gate  * bus dma sync entry point.
6517c478bd9Sstevel@tonic-gate  */
6527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6537c478bd9Sstevel@tonic-gate int
px_lib_dma_sync(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,off_t off,size_t len,uint_t cache_flags)6547c478bd9Sstevel@tonic-gate px_lib_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
65544bb982bSgovinda     off_t off, size_t len, uint_t cache_flags)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle;
65825cf1a30Sjl 	px_t	*px_p = DIP_TO_STATE(dip);
65925cf1a30Sjl 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_DMA, dip, "px_lib_dma_sync: dip 0x%p rdip 0x%p "
6627c478bd9Sstevel@tonic-gate 	    "handle 0x%llx off 0x%x len 0x%x flags 0x%x\n",
6637c478bd9Sstevel@tonic-gate 	    dip, rdip, handle, off, len, cache_flags);
6647c478bd9Sstevel@tonic-gate 
66525cf1a30Sjl 	/*
66625cf1a30Sjl 	 * No flush needed for Oberon
66725cf1a30Sjl 	 */
66825cf1a30Sjl 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON)
66925cf1a30Sjl 		return (DDI_SUCCESS);
67025cf1a30Sjl 
6717c478bd9Sstevel@tonic-gate 	/*
6727c478bd9Sstevel@tonic-gate 	 * jbus_stst_order is found only in certain cpu modules.
6737c478bd9Sstevel@tonic-gate 	 * Just return success if not present.
6747c478bd9Sstevel@tonic-gate 	 */
6757c478bd9Sstevel@tonic-gate 	if (&jbus_stst_order == NULL)
6767c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6777c478bd9Sstevel@tonic-gate 
67836fe4a92Segillett 	if (!(mp->dmai_flags & PX_DMAI_FLAGS_INUSE)) {
679f8d2de6bSjchu 		cmn_err(CE_WARN, "%s%d: Unbound dma handle %p.",
680f8d2de6bSjchu 		    ddi_driver_name(rdip), ddi_get_instance(rdip), (void *)mp);
681f8d2de6bSjchu 
6827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 
68536fe4a92Segillett 	if (mp->dmai_flags & PX_DMAI_FLAGS_NOSYNC)
6867c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	/*
6897c478bd9Sstevel@tonic-gate 	 * No flush needed when sending data from memory to device.
6907c478bd9Sstevel@tonic-gate 	 * Nothing to do to "sync" memory to what device would already see.
6917c478bd9Sstevel@tonic-gate 	 */
6927c478bd9Sstevel@tonic-gate 	if (!(mp->dmai_rflags & DDI_DMA_READ) ||
6937c478bd9Sstevel@tonic-gate 	    ((cache_flags & PX_DMA_SYNC_DDI_FLAGS) == DDI_DMA_SYNC_FORDEV))
6947c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	/*
6977c478bd9Sstevel@tonic-gate 	 * Perform necessary cpu workaround to ensure jbus ordering.
6987c478bd9Sstevel@tonic-gate 	 * CPU's internal "invalidate FIFOs" are flushed.
6997c478bd9Sstevel@tonic-gate 	 */
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	kpreempt_disable();
7027c478bd9Sstevel@tonic-gate 	jbus_stst_order();
7037c478bd9Sstevel@tonic-gate 	kpreempt_enable();
7047c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate /*
7087c478bd9Sstevel@tonic-gate  * MSIQ Functions:
7097c478bd9Sstevel@tonic-gate  */
7107c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7117c478bd9Sstevel@tonic-gate int
px_lib_msiq_init(dev_info_t * dip)7127c478bd9Sstevel@tonic-gate px_lib_msiq_init(dev_info_t *dip)
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
7157c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
7167c478bd9Sstevel@tonic-gate 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
7177c478bd9Sstevel@tonic-gate 	px_dvma_addr_t	pg_index;
718348fdf9eSAlan Adamson, SD OSSD 	size_t		q_sz = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
7197c478bd9Sstevel@tonic-gate 	size_t		size;
720348fdf9eSAlan Adamson, SD OSSD 	int		i, ret;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_init: dip 0x%p\n", dip);
7237c478bd9Sstevel@tonic-gate 
724348fdf9eSAlan Adamson, SD OSSD 	/* must aligned on q_sz (happens to be !!! page) boundary */
725348fdf9eSAlan Adamson, SD OSSD 	ASSERT(q_sz == 8 * 1024);
726348fdf9eSAlan Adamson, SD OSSD 
7277c478bd9Sstevel@tonic-gate 	/*
7287c478bd9Sstevel@tonic-gate 	 * Map the EQ memory into the Fire MMU (has to be 512KB aligned)
7297c478bd9Sstevel@tonic-gate 	 * and then initialize the base address register.
7307c478bd9Sstevel@tonic-gate 	 *
7317c478bd9Sstevel@tonic-gate 	 * Allocate entries from Fire IOMMU so that the resulting address
7327c478bd9Sstevel@tonic-gate 	 * is properly aligned.  Calculate the index of the first allocated
7337c478bd9Sstevel@tonic-gate 	 * entry.  Note: The size of the mapping is assumed to be a multiple
7347c478bd9Sstevel@tonic-gate 	 * of the page size.
7357c478bd9Sstevel@tonic-gate 	 */
736348fdf9eSAlan Adamson, SD OSSD 	size = msiq_state_p->msiq_cnt * q_sz;
737348fdf9eSAlan Adamson, SD OSSD 
738348fdf9eSAlan Adamson, SD OSSD 	msiq_state_p->msiq_buf_p = kmem_zalloc(size, KM_SLEEP);
739348fdf9eSAlan Adamson, SD OSSD 
740348fdf9eSAlan Adamson, SD OSSD 	for (i = 0; i < msiq_state_p->msiq_cnt; i++)
741348fdf9eSAlan Adamson, SD OSSD 		msiq_state_p->msiq_p[i].msiq_base_p = (msiqhead_t *)
742348fdf9eSAlan Adamson, SD OSSD 		    ((caddr_t)msiq_state_p->msiq_buf_p + (i * q_sz));
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	pxu_p->msiq_mapped_p = vmem_xalloc(px_p->px_mmu_p->mmu_dvma_map,
7457c478bd9Sstevel@tonic-gate 	    size, (512 * 1024), 0, 0, NULL, NULL, VM_NOSLEEP | VM_BESTFIT);
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	if (pxu_p->msiq_mapped_p == NULL)
7487c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p,
7517c478bd9Sstevel@tonic-gate 	    MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p));
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	if ((ret = px_lib_iommu_map(px_p->px_dip, PCI_TSBID(0, pg_index),
75495003185Segillett 	    MMU_BTOP(size), PCI_MAP_ATTR_WRITE, msiq_state_p->msiq_buf_p,
75595003185Segillett 	    0, MMU_MAP_BUF)) != DDI_SUCCESS) {
7567c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
75756de8cb5Sanbui 		    "px_lib_msiq_init: px_lib_iommu_map failed, "
75856de8cb5Sanbui 		    "ret 0x%lx\n", ret);
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		(void) px_lib_msiq_fini(dip);
7617c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate 
764d8d130aeSanbui 	if ((ret = hvio_msiq_init(DIP_TO_HANDLE(dip),
765d8d130aeSanbui 	    pxu_p)) != H_EOK) {
766d8d130aeSanbui 		DBG(DBG_LIB_MSIQ, dip,
767d8d130aeSanbui 		    "hvio_msiq_init failed, ret 0x%lx\n", ret);
768d8d130aeSanbui 
769d8d130aeSanbui 		(void) px_lib_msiq_fini(dip);
770d8d130aeSanbui 		return (DDI_FAILURE);
771d8d130aeSanbui 	}
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7777c478bd9Sstevel@tonic-gate int
px_lib_msiq_fini(dev_info_t * dip)7787c478bd9Sstevel@tonic-gate px_lib_msiq_fini(dev_info_t *dip)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
7817c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
7827c478bd9Sstevel@tonic-gate 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
7837c478bd9Sstevel@tonic-gate 	px_dvma_addr_t	pg_index;
7847c478bd9Sstevel@tonic-gate 	size_t		size;
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_fini: dip 0x%p\n", dip);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	/*
7897c478bd9Sstevel@tonic-gate 	 * Unmap and free the EQ memory that had been mapped
7907c478bd9Sstevel@tonic-gate 	 * into the Fire IOMMU.
7917c478bd9Sstevel@tonic-gate 	 */
7927c478bd9Sstevel@tonic-gate 	size = msiq_state_p->msiq_cnt *
7937c478bd9Sstevel@tonic-gate 	    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p,
7967c478bd9Sstevel@tonic-gate 	    MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p));
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	(void) px_lib_iommu_demap(px_p->px_dip,
7997c478bd9Sstevel@tonic-gate 	    PCI_TSBID(0, pg_index), MMU_BTOP(size));
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	/* Free the entries from the Fire MMU */
8027c478bd9Sstevel@tonic-gate 	vmem_xfree(px_p->px_mmu_p->mmu_dvma_map,
8037c478bd9Sstevel@tonic-gate 	    (void *)pxu_p->msiq_mapped_p, size);
8047c478bd9Sstevel@tonic-gate 
805348fdf9eSAlan Adamson, SD OSSD 	kmem_free(msiq_state_p->msiq_buf_p, msiq_state_p->msiq_cnt *
806348fdf9eSAlan Adamson, SD OSSD 	    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t));
807348fdf9eSAlan Adamson, SD OSSD 
8087c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8127c478bd9Sstevel@tonic-gate int
px_lib_msiq_info(dev_info_t * dip,msiqid_t msiq_id,r_addr_t * ra_p,uint_t * msiq_rec_cnt_p)8137c478bd9Sstevel@tonic-gate px_lib_msiq_info(dev_info_t *dip, msiqid_t msiq_id, r_addr_t *ra_p,
8147c478bd9Sstevel@tonic-gate     uint_t *msiq_rec_cnt_p)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
8177c478bd9Sstevel@tonic-gate 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
8187c478bd9Sstevel@tonic-gate 	size_t		msiq_size;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: dip 0x%p msiq_id 0x%x\n",
8217c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
82495003185Segillett 	ra_p = (r_addr_t *)((caddr_t)msiq_state_p->msiq_buf_p +
82595003185Segillett 	    (msiq_id * msiq_size));
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	*msiq_rec_cnt_p = msiq_state_p->msiq_rec_cnt;
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: ra_p 0x%p msiq_rec_cnt 0x%x\n",
8307c478bd9Sstevel@tonic-gate 	    ra_p, *msiq_rec_cnt_p);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8367c478bd9Sstevel@tonic-gate int
px_lib_msiq_getvalid(dev_info_t * dip,msiqid_t msiq_id,pci_msiq_valid_state_t * msiq_valid_state)8377c478bd9Sstevel@tonic-gate px_lib_msiq_getvalid(dev_info_t *dip, msiqid_t msiq_id,
8387c478bd9Sstevel@tonic-gate     pci_msiq_valid_state_t *msiq_valid_state)
8397c478bd9Sstevel@tonic-gate {
8407c478bd9Sstevel@tonic-gate 	uint64_t	ret;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: dip 0x%p msiq_id 0x%x\n",
8437c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_getvalid(DIP_TO_HANDLE(dip),
8467c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_valid_state)) != H_EOK) {
8477c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
8487c478bd9Sstevel@tonic-gate 		    "hvio_msiq_getvalid failed, ret 0x%lx\n", ret);
8497c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8507c478bd9Sstevel@tonic-gate 	}
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: msiq_valid_state 0x%x\n",
8537c478bd9Sstevel@tonic-gate 	    *msiq_valid_state);
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8597c478bd9Sstevel@tonic-gate int
px_lib_msiq_setvalid(dev_info_t * dip,msiqid_t msiq_id,pci_msiq_valid_state_t msiq_valid_state)8607c478bd9Sstevel@tonic-gate px_lib_msiq_setvalid(dev_info_t *dip, msiqid_t msiq_id,
8617c478bd9Sstevel@tonic-gate     pci_msiq_valid_state_t msiq_valid_state)
8627c478bd9Sstevel@tonic-gate {
8637c478bd9Sstevel@tonic-gate 	uint64_t	ret;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setvalid: dip 0x%p msiq_id 0x%x "
8667c478bd9Sstevel@tonic-gate 	    "msiq_valid_state 0x%x\n", dip, msiq_id, msiq_valid_state);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_setvalid(DIP_TO_HANDLE(dip),
8697c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_valid_state)) != H_EOK) {
8707c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
8717c478bd9Sstevel@tonic-gate 		    "hvio_msiq_setvalid failed, ret 0x%lx\n", ret);
8727c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8797c478bd9Sstevel@tonic-gate int
px_lib_msiq_getstate(dev_info_t * dip,msiqid_t msiq_id,pci_msiq_state_t * msiq_state)8807c478bd9Sstevel@tonic-gate px_lib_msiq_getstate(dev_info_t *dip, msiqid_t msiq_id,
8817c478bd9Sstevel@tonic-gate     pci_msiq_state_t *msiq_state)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate 	uint64_t	ret;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: dip 0x%p msiq_id 0x%x\n",
8867c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_getstate(DIP_TO_HANDLE(dip),
8897c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_state)) != H_EOK) {
8907c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
8917c478bd9Sstevel@tonic-gate 		    "hvio_msiq_getstate failed, ret 0x%lx\n", ret);
8927c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8937c478bd9Sstevel@tonic-gate 	}
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: msiq_state 0x%x\n",
8967c478bd9Sstevel@tonic-gate 	    *msiq_state);
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9027c478bd9Sstevel@tonic-gate int
px_lib_msiq_setstate(dev_info_t * dip,msiqid_t msiq_id,pci_msiq_state_t msiq_state)9037c478bd9Sstevel@tonic-gate px_lib_msiq_setstate(dev_info_t *dip, msiqid_t msiq_id,
9047c478bd9Sstevel@tonic-gate     pci_msiq_state_t msiq_state)
9057c478bd9Sstevel@tonic-gate {
9067c478bd9Sstevel@tonic-gate 	uint64_t	ret;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setstate: dip 0x%p msiq_id 0x%x "
9097c478bd9Sstevel@tonic-gate 	    "msiq_state 0x%x\n", dip, msiq_id, msiq_state);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_setstate(DIP_TO_HANDLE(dip),
9127c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_state)) != H_EOK) {
9137c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
9147c478bd9Sstevel@tonic-gate 		    "hvio_msiq_setstate failed, ret 0x%lx\n", ret);
9157c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9167c478bd9Sstevel@tonic-gate 	}
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9197c478bd9Sstevel@tonic-gate }
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9227c478bd9Sstevel@tonic-gate int
px_lib_msiq_gethead(dev_info_t * dip,msiqid_t msiq_id,msiqhead_t * msiq_head)9237c478bd9Sstevel@tonic-gate px_lib_msiq_gethead(dev_info_t *dip, msiqid_t msiq_id,
9247c478bd9Sstevel@tonic-gate     msiqhead_t *msiq_head)
9257c478bd9Sstevel@tonic-gate {
9267c478bd9Sstevel@tonic-gate 	uint64_t	ret;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: dip 0x%p msiq_id 0x%x\n",
9297c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_gethead(DIP_TO_HANDLE(dip),
9327c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_head)) != H_EOK) {
9337c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
9347c478bd9Sstevel@tonic-gate 		    "hvio_msiq_gethead failed, ret 0x%lx\n", ret);
9357c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: msiq_head 0x%x\n",
9397c478bd9Sstevel@tonic-gate 	    *msiq_head);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9457c478bd9Sstevel@tonic-gate int
px_lib_msiq_sethead(dev_info_t * dip,msiqid_t msiq_id,msiqhead_t msiq_head)9467c478bd9Sstevel@tonic-gate px_lib_msiq_sethead(dev_info_t *dip, msiqid_t msiq_id,
9477c478bd9Sstevel@tonic-gate     msiqhead_t msiq_head)
9487c478bd9Sstevel@tonic-gate {
9497c478bd9Sstevel@tonic-gate 	uint64_t	ret;
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_sethead: dip 0x%p msiq_id 0x%x "
9527c478bd9Sstevel@tonic-gate 	    "msiq_head 0x%x\n", dip, msiq_id, msiq_head);
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_sethead(DIP_TO_HANDLE(dip),
9557c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_head)) != H_EOK) {
9567c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
9577c478bd9Sstevel@tonic-gate 		    "hvio_msiq_sethead failed, ret 0x%lx\n", ret);
9587c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9657c478bd9Sstevel@tonic-gate int
px_lib_msiq_gettail(dev_info_t * dip,msiqid_t msiq_id,msiqtail_t * msiq_tail)9667c478bd9Sstevel@tonic-gate px_lib_msiq_gettail(dev_info_t *dip, msiqid_t msiq_id,
9677c478bd9Sstevel@tonic-gate     msiqtail_t *msiq_tail)
9687c478bd9Sstevel@tonic-gate {
9697c478bd9Sstevel@tonic-gate 	uint64_t	ret;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: dip 0x%p msiq_id 0x%x\n",
9727c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_gettail(DIP_TO_HANDLE(dip),
9757c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_tail)) != H_EOK) {
9767c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
9777c478bd9Sstevel@tonic-gate 		    "hvio_msiq_gettail failed, ret 0x%lx\n", ret);
9787c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: msiq_tail 0x%x\n",
9827c478bd9Sstevel@tonic-gate 	    *msiq_tail);
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9887c478bd9Sstevel@tonic-gate void
px_lib_get_msiq_rec(dev_info_t * dip,msiqhead_t * msiq_head_p,msiq_rec_t * msiq_rec_p)989023ccc1eSegillett px_lib_get_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p,
990023ccc1eSegillett     msiq_rec_t *msiq_rec_p)
9917c478bd9Sstevel@tonic-gate {
992023ccc1eSegillett 	eq_rec_t	*eq_rec_p = (eq_rec_t *)msiq_head_p;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p eq_rec_p 0x%p\n",
9957c478bd9Sstevel@tonic-gate 	    dip, eq_rec_p);
9967c478bd9Sstevel@tonic-gate 
9973ee8f295Smg 	if (!eq_rec_p->eq_rec_fmt_type) {
9983ee8f295Smg 		/* Set msiq_rec_type to zero */
9993ee8f295Smg 		msiq_rec_p->msiq_rec_type = 0;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		return;
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: EQ RECORD, "
10057c478bd9Sstevel@tonic-gate 	    "eq_rec_rid 0x%llx eq_rec_fmt_type 0x%llx "
10067c478bd9Sstevel@tonic-gate 	    "eq_rec_len 0x%llx eq_rec_addr0 0x%llx "
10077c478bd9Sstevel@tonic-gate 	    "eq_rec_addr1 0x%llx eq_rec_data0 0x%llx "
10087c478bd9Sstevel@tonic-gate 	    "eq_rec_data1 0x%llx\n", eq_rec_p->eq_rec_rid,
10097c478bd9Sstevel@tonic-gate 	    eq_rec_p->eq_rec_fmt_type, eq_rec_p->eq_rec_len,
10107c478bd9Sstevel@tonic-gate 	    eq_rec_p->eq_rec_addr0, eq_rec_p->eq_rec_addr1,
10117c478bd9Sstevel@tonic-gate 	    eq_rec_p->eq_rec_data0, eq_rec_p->eq_rec_data1);
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	/*
10147c478bd9Sstevel@tonic-gate 	 * Only upper 4 bits of eq_rec_fmt_type is used
10157c478bd9Sstevel@tonic-gate 	 * to identify the EQ record type.
10167c478bd9Sstevel@tonic-gate 	 */
10177c478bd9Sstevel@tonic-gate 	switch (eq_rec_p->eq_rec_fmt_type >> 3) {
10187c478bd9Sstevel@tonic-gate 	case EQ_REC_MSI32:
10197c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_type = MSI32_REC;
10207c478bd9Sstevel@tonic-gate 
10217510e228Sess 		msiq_rec_p->msiq_rec_data.msi.msi_data =
10227510e228Sess 		    eq_rec_p->eq_rec_data0;
10237c478bd9Sstevel@tonic-gate 		break;
10247c478bd9Sstevel@tonic-gate 	case EQ_REC_MSI64:
10257c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_type = MSI64_REC;
10267c478bd9Sstevel@tonic-gate 
10277510e228Sess 		msiq_rec_p->msiq_rec_data.msi.msi_data =
10287510e228Sess 		    eq_rec_p->eq_rec_data0;
10297c478bd9Sstevel@tonic-gate 		break;
10307c478bd9Sstevel@tonic-gate 	case EQ_REC_MSG:
10317c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_type = MSG_REC;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_data.msg.msg_route =
10347c478bd9Sstevel@tonic-gate 		    eq_rec_p->eq_rec_fmt_type & 7;
10357c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_data.msg.msg_targ = eq_rec_p->eq_rec_rid;
10367c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_data.msg.msg_code = eq_rec_p->eq_rec_data0;
10377c478bd9Sstevel@tonic-gate 		break;
10387c478bd9Sstevel@tonic-gate 	default:
10397c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: px_lib_get_msiq_rec: "
1040b40cec45Skrishnae 		    "0x%x is an unknown EQ record type",
10417c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip),
1042b40cec45Skrishnae 		    (int)eq_rec_p->eq_rec_fmt_type);
10437c478bd9Sstevel@tonic-gate 		break;
10447c478bd9Sstevel@tonic-gate 	}
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	msiq_rec_p->msiq_rec_rid = eq_rec_p->eq_rec_rid;
10477c478bd9Sstevel@tonic-gate 	msiq_rec_p->msiq_rec_msi_addr = ((eq_rec_p->eq_rec_addr1 << 16) |
10487c478bd9Sstevel@tonic-gate 	    (eq_rec_p->eq_rec_addr0 << 2));
1049b0fc0e77Sgovinda }
10507c478bd9Sstevel@tonic-gate 
1051b0fc0e77Sgovinda /*ARGSUSED*/
1052b0fc0e77Sgovinda void
px_lib_clr_msiq_rec(dev_info_t * dip,msiqhead_t * msiq_head_p)1053b0fc0e77Sgovinda px_lib_clr_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p)
1054b0fc0e77Sgovinda {
1055b0fc0e77Sgovinda 	eq_rec_t	*eq_rec_p = (eq_rec_t *)msiq_head_p;
1056b0fc0e77Sgovinda 
1057b0fc0e77Sgovinda 	DBG(DBG_LIB_MSIQ, dip, "px_lib_clr_msiq_rec: dip 0x%p eq_rec_p 0x%p\n",
1058b0fc0e77Sgovinda 	    dip, eq_rec_p);
1059b0fc0e77Sgovinda 
1060b0fc0e77Sgovinda 	if (eq_rec_p->eq_rec_fmt_type) {
1061b0fc0e77Sgovinda 		/* Zero out eq_rec_fmt_type field */
1062b0fc0e77Sgovinda 		eq_rec_p->eq_rec_fmt_type = 0;
1063b0fc0e77Sgovinda 	}
10647c478bd9Sstevel@tonic-gate }
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate /*
10677c478bd9Sstevel@tonic-gate  * MSI Functions:
10687c478bd9Sstevel@tonic-gate  */
10697c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10707c478bd9Sstevel@tonic-gate int
px_lib_msi_init(dev_info_t * dip)10717c478bd9Sstevel@tonic-gate px_lib_msi_init(dev_info_t *dip)
10727c478bd9Sstevel@tonic-gate {
10737c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
10747c478bd9Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
10757c478bd9Sstevel@tonic-gate 	uint64_t	ret;
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_init: dip 0x%p\n", dip);
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_init(DIP_TO_HANDLE(dip),
10807c478bd9Sstevel@tonic-gate 	    msi_state_p->msi_addr32, msi_state_p->msi_addr64)) != H_EOK) {
10817c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip, "px_lib_msi_init failed, ret 0x%lx\n",
10827c478bd9Sstevel@tonic-gate 		    ret);
10837c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10847c478bd9Sstevel@tonic-gate 	}
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10907c478bd9Sstevel@tonic-gate int
px_lib_msi_getmsiq(dev_info_t * dip,msinum_t msi_num,msiqid_t * msiq_id)10917c478bd9Sstevel@tonic-gate px_lib_msi_getmsiq(dev_info_t *dip, msinum_t msi_num,
10927c478bd9Sstevel@tonic-gate     msiqid_t *msiq_id)
10937c478bd9Sstevel@tonic-gate {
10947c478bd9Sstevel@tonic-gate 	uint64_t	ret;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: dip 0x%p msi_num 0x%x\n",
10977c478bd9Sstevel@tonic-gate 	    dip, msi_num);
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_getmsiq(DIP_TO_HANDLE(dip),
11007c478bd9Sstevel@tonic-gate 	    msi_num, msiq_id)) != H_EOK) {
11017c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11027c478bd9Sstevel@tonic-gate 		    "hvio_msi_getmsiq failed, ret 0x%lx\n", ret);
11037c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: msiq_id 0x%x\n",
11077c478bd9Sstevel@tonic-gate 	    *msiq_id);
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11107c478bd9Sstevel@tonic-gate }
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11137c478bd9Sstevel@tonic-gate int
px_lib_msi_setmsiq(dev_info_t * dip,msinum_t msi_num,msiqid_t msiq_id,msi_type_t msitype)11147c478bd9Sstevel@tonic-gate px_lib_msi_setmsiq(dev_info_t *dip, msinum_t msi_num,
11157c478bd9Sstevel@tonic-gate     msiqid_t msiq_id, msi_type_t msitype)
11167c478bd9Sstevel@tonic-gate {
11177c478bd9Sstevel@tonic-gate 	uint64_t	ret;
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setmsiq: dip 0x%p msi_num 0x%x "
11207c478bd9Sstevel@tonic-gate 	    "msq_id 0x%x\n", dip, msi_num, msiq_id);
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_setmsiq(DIP_TO_HANDLE(dip),
11237c478bd9Sstevel@tonic-gate 	    msi_num, msiq_id)) != H_EOK) {
11247c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11257c478bd9Sstevel@tonic-gate 		    "hvio_msi_setmsiq failed, ret 0x%lx\n", ret);
11267c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11337c478bd9Sstevel@tonic-gate int
px_lib_msi_getvalid(dev_info_t * dip,msinum_t msi_num,pci_msi_valid_state_t * msi_valid_state)11347c478bd9Sstevel@tonic-gate px_lib_msi_getvalid(dev_info_t *dip, msinum_t msi_num,
11357c478bd9Sstevel@tonic-gate     pci_msi_valid_state_t *msi_valid_state)
11367c478bd9Sstevel@tonic-gate {
11377c478bd9Sstevel@tonic-gate 	uint64_t	ret;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: dip 0x%p msi_num 0x%x\n",
11407c478bd9Sstevel@tonic-gate 	    dip, msi_num);
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_getvalid(DIP_TO_HANDLE(dip),
11437c478bd9Sstevel@tonic-gate 	    msi_num, msi_valid_state)) != H_EOK) {
11447c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11457c478bd9Sstevel@tonic-gate 		    "hvio_msi_getvalid failed, ret 0x%lx\n", ret);
11467c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11477c478bd9Sstevel@tonic-gate 	}
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: msiq_id 0x%x\n",
11507c478bd9Sstevel@tonic-gate 	    *msi_valid_state);
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11567c478bd9Sstevel@tonic-gate int
px_lib_msi_setvalid(dev_info_t * dip,msinum_t msi_num,pci_msi_valid_state_t msi_valid_state)11577c478bd9Sstevel@tonic-gate px_lib_msi_setvalid(dev_info_t *dip, msinum_t msi_num,
11587c478bd9Sstevel@tonic-gate     pci_msi_valid_state_t msi_valid_state)
11597c478bd9Sstevel@tonic-gate {
11607c478bd9Sstevel@tonic-gate 	uint64_t	ret;
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setvalid: dip 0x%p msi_num 0x%x "
11637c478bd9Sstevel@tonic-gate 	    "msi_valid_state 0x%x\n", dip, msi_num, msi_valid_state);
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_setvalid(DIP_TO_HANDLE(dip),
11667c478bd9Sstevel@tonic-gate 	    msi_num, msi_valid_state)) != H_EOK) {
11677c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11687c478bd9Sstevel@tonic-gate 		    "hvio_msi_setvalid failed, ret 0x%lx\n", ret);
11697c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11707c478bd9Sstevel@tonic-gate 	}
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11737c478bd9Sstevel@tonic-gate }
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11767c478bd9Sstevel@tonic-gate int
px_lib_msi_getstate(dev_info_t * dip,msinum_t msi_num,pci_msi_state_t * msi_state)11777c478bd9Sstevel@tonic-gate px_lib_msi_getstate(dev_info_t *dip, msinum_t msi_num,
11787c478bd9Sstevel@tonic-gate     pci_msi_state_t *msi_state)
11797c478bd9Sstevel@tonic-gate {
11807c478bd9Sstevel@tonic-gate 	uint64_t	ret;
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: dip 0x%p msi_num 0x%x\n",
11837c478bd9Sstevel@tonic-gate 	    dip, msi_num);
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_getstate(DIP_TO_HANDLE(dip),
11867c478bd9Sstevel@tonic-gate 	    msi_num, msi_state)) != H_EOK) {
11877c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11887c478bd9Sstevel@tonic-gate 		    "hvio_msi_getstate failed, ret 0x%lx\n", ret);
11897c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11907c478bd9Sstevel@tonic-gate 	}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: msi_state 0x%x\n",
11937c478bd9Sstevel@tonic-gate 	    *msi_state);
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11967c478bd9Sstevel@tonic-gate }
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11997c478bd9Sstevel@tonic-gate int
px_lib_msi_setstate(dev_info_t * dip,msinum_t msi_num,pci_msi_state_t msi_state)12007c478bd9Sstevel@tonic-gate px_lib_msi_setstate(dev_info_t *dip, msinum_t msi_num,
12017c478bd9Sstevel@tonic-gate     pci_msi_state_t msi_state)
12027c478bd9Sstevel@tonic-gate {
12037c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setstate: dip 0x%p msi_num 0x%x "
12067c478bd9Sstevel@tonic-gate 	    "msi_state 0x%x\n", dip, msi_num, msi_state);
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_setstate(DIP_TO_HANDLE(dip),
12097c478bd9Sstevel@tonic-gate 	    msi_num, msi_state)) != H_EOK) {
12107c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
12117c478bd9Sstevel@tonic-gate 		    "hvio_msi_setstate failed, ret 0x%lx\n", ret);
12127c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate /*
12197c478bd9Sstevel@tonic-gate  * MSG Functions:
12207c478bd9Sstevel@tonic-gate  */
12217c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12227c478bd9Sstevel@tonic-gate int
px_lib_msg_getmsiq(dev_info_t * dip,pcie_msg_type_t msg_type,msiqid_t * msiq_id)12237c478bd9Sstevel@tonic-gate px_lib_msg_getmsiq(dev_info_t *dip, pcie_msg_type_t msg_type,
12247c478bd9Sstevel@tonic-gate     msiqid_t *msiq_id)
12257c478bd9Sstevel@tonic-gate {
12267c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_getmsiq: dip 0x%p msg_type 0x%x\n",
12297c478bd9Sstevel@tonic-gate 	    dip, msg_type);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msg_getmsiq(DIP_TO_HANDLE(dip),
12327c478bd9Sstevel@tonic-gate 	    msg_type, msiq_id)) != H_EOK) {
12337c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSG, dip,
12347c478bd9Sstevel@tonic-gate 		    "hvio_msg_getmsiq failed, ret 0x%lx\n", ret);
12357c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msg_getmsiq: msiq_id 0x%x\n",
12397c478bd9Sstevel@tonic-gate 	    *msiq_id);
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12457c478bd9Sstevel@tonic-gate int
px_lib_msg_setmsiq(dev_info_t * dip,pcie_msg_type_t msg_type,msiqid_t msiq_id)12467c478bd9Sstevel@tonic-gate px_lib_msg_setmsiq(dev_info_t *dip, pcie_msg_type_t msg_type,
12477c478bd9Sstevel@tonic-gate     msiqid_t msiq_id)
12487c478bd9Sstevel@tonic-gate {
12497c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSG, dip, "px_lib_msi_setstate: dip 0x%p msg_type 0x%x "
12527c478bd9Sstevel@tonic-gate 	    "msiq_id 0x%x\n", dip, msg_type, msiq_id);
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msg_setmsiq(DIP_TO_HANDLE(dip),
12557c478bd9Sstevel@tonic-gate 	    msg_type, msiq_id)) != H_EOK) {
12567c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSG, dip,
12577c478bd9Sstevel@tonic-gate 		    "hvio_msg_setmsiq failed, ret 0x%lx\n", ret);
12587c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12597c478bd9Sstevel@tonic-gate 	}
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12657c478bd9Sstevel@tonic-gate int
px_lib_msg_getvalid(dev_info_t * dip,pcie_msg_type_t msg_type,pcie_msg_valid_state_t * msg_valid_state)12667c478bd9Sstevel@tonic-gate px_lib_msg_getvalid(dev_info_t *dip, pcie_msg_type_t msg_type,
12677c478bd9Sstevel@tonic-gate     pcie_msg_valid_state_t *msg_valid_state)
12687c478bd9Sstevel@tonic-gate {
12697c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_getvalid: dip 0x%p msg_type 0x%x\n",
12727c478bd9Sstevel@tonic-gate 	    dip, msg_type);
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msg_getvalid(DIP_TO_HANDLE(dip), msg_type,
12757c478bd9Sstevel@tonic-gate 	    msg_valid_state)) != H_EOK) {
12767c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSG, dip,
12777c478bd9Sstevel@tonic-gate 		    "hvio_msg_getvalid failed, ret 0x%lx\n", ret);
12787c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12797c478bd9Sstevel@tonic-gate 	}
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msg_getvalid: msg_valid_state 0x%x\n",
12827c478bd9Sstevel@tonic-gate 	    *msg_valid_state);
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12857c478bd9Sstevel@tonic-gate }
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12887c478bd9Sstevel@tonic-gate int
px_lib_msg_setvalid(dev_info_t * dip,pcie_msg_type_t msg_type,pcie_msg_valid_state_t msg_valid_state)12897c478bd9Sstevel@tonic-gate px_lib_msg_setvalid(dev_info_t *dip, pcie_msg_type_t msg_type,
12907c478bd9Sstevel@tonic-gate     pcie_msg_valid_state_t msg_valid_state)
12917c478bd9Sstevel@tonic-gate {
12927c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_setvalid: dip 0x%p msg_type 0x%x "
12957c478bd9Sstevel@tonic-gate 	    "msg_valid_state 0x%x\n", dip, msg_type, msg_valid_state);
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msg_setvalid(DIP_TO_HANDLE(dip), msg_type,
12987c478bd9Sstevel@tonic-gate 	    msg_valid_state)) != H_EOK) {
12997c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSG, dip,
13007c478bd9Sstevel@tonic-gate 		    "hvio_msg_setvalid failed, ret 0x%lx\n", ret);
13017c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13027c478bd9Sstevel@tonic-gate 	}
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
13057c478bd9Sstevel@tonic-gate }
13067c478bd9Sstevel@tonic-gate 
1307fc256490SJason Beloro /*ARGSUSED*/
1308fc256490SJason Beloro void
px_panic_domain(px_t * px_p,pcie_req_id_t bdf)1309fc256490SJason Beloro px_panic_domain(px_t *px_p, pcie_req_id_t bdf)
1310fc256490SJason Beloro {
1311fc256490SJason Beloro }
1312fc256490SJason Beloro 
13137c478bd9Sstevel@tonic-gate /*
13147c478bd9Sstevel@tonic-gate  * Suspend/Resume Functions:
13157c478bd9Sstevel@tonic-gate  * Currently unsupported by hypervisor
13167c478bd9Sstevel@tonic-gate  */
13177c478bd9Sstevel@tonic-gate int
px_lib_suspend(dev_info_t * dip)13187c478bd9Sstevel@tonic-gate px_lib_suspend(dev_info_t *dip)
13197c478bd9Sstevel@tonic-gate {
13207c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
13217c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
132201689544Sjchu 	px_cb_t		*cb_p = PX2CB(px_p);
13237c478bd9Sstevel@tonic-gate 	devhandle_t	dev_hdl, xbus_dev_hdl;
132401689544Sjchu 	uint64_t	ret = H_EOK;
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	DBG(DBG_DETACH, dip, "px_lib_suspend: dip 0x%p\n", dip);
13277c478bd9Sstevel@tonic-gate 
1328f8d2de6bSjchu 	dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR];
1329f8d2de6bSjchu 	xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC];
13307c478bd9Sstevel@tonic-gate 
133101689544Sjchu 	if ((ret = hvio_suspend(dev_hdl, pxu_p)) != H_EOK)
133201689544Sjchu 		goto fail;
133301689544Sjchu 
133401689544Sjchu 	if (--cb_p->attachcnt == 0) {
133501689544Sjchu 		ret = hvio_cb_suspend(xbus_dev_hdl, pxu_p);
133601689544Sjchu 		if (ret != H_EOK)
133701689544Sjchu 			cb_p->attachcnt++;
13387c478bd9Sstevel@tonic-gate 	}
1339bf8fc234Set 	pxu_p->cpr_flag = PX_ENTERED_CPR;
13407c478bd9Sstevel@tonic-gate 
134101689544Sjchu fail:
13427c478bd9Sstevel@tonic-gate 	return ((ret != H_EOK) ? DDI_FAILURE: DDI_SUCCESS);
13437c478bd9Sstevel@tonic-gate }
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate void
px_lib_resume(dev_info_t * dip)13467c478bd9Sstevel@tonic-gate px_lib_resume(dev_info_t *dip)
13477c478bd9Sstevel@tonic-gate {
13487c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
13497c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
135001689544Sjchu 	px_cb_t		*cb_p = PX2CB(px_p);
13517c478bd9Sstevel@tonic-gate 	devhandle_t	dev_hdl, xbus_dev_hdl;
13527c478bd9Sstevel@tonic-gate 	devino_t	pec_ino = px_p->px_inos[PX_INTR_PEC];
13537c478bd9Sstevel@tonic-gate 	devino_t	xbc_ino = px_p->px_inos[PX_INTR_XBC];
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	DBG(DBG_ATTACH, dip, "px_lib_resume: dip 0x%p\n", dip);
13567c478bd9Sstevel@tonic-gate 
1357f8d2de6bSjchu 	dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR];
1358f8d2de6bSjchu 	xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC];
13597c478bd9Sstevel@tonic-gate 
136001689544Sjchu 	if (++cb_p->attachcnt == 1)
13617c478bd9Sstevel@tonic-gate 		hvio_cb_resume(dev_hdl, xbus_dev_hdl, xbc_ino, pxu_p);
13627c478bd9Sstevel@tonic-gate 
136301689544Sjchu 	hvio_resume(dev_hdl, pec_ino, pxu_p);
13647c478bd9Sstevel@tonic-gate }
13657c478bd9Sstevel@tonic-gate 
136625cf1a30Sjl /*
136725cf1a30Sjl  * Generate a unique Oberon UBC ID based on the Logicial System Board and
136825cf1a30Sjl  * the IO Channel from the portid property field.
136925cf1a30Sjl  */
137025cf1a30Sjl static uint64_t
oberon_get_ubc_id(dev_info_t * dip)137125cf1a30Sjl oberon_get_ubc_id(dev_info_t *dip)
137225cf1a30Sjl {
137325cf1a30Sjl 	px_t	*px_p = DIP_TO_STATE(dip);
137425cf1a30Sjl 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
137525cf1a30Sjl 	uint64_t	ubc_id;
137625cf1a30Sjl 
137725cf1a30Sjl 	/*
137825cf1a30Sjl 	 * Generate a unique 6 bit UBC ID using the 2 IO_Channel#[1:0] bits and
137925cf1a30Sjl 	 * the 4 LSB_ID[3:0] bits from the Oberon's portid property.
138025cf1a30Sjl 	 */
138125cf1a30Sjl 	ubc_id = (((pxu_p->portid >> OBERON_PORT_ID_IOC) &
138225cf1a30Sjl 	    OBERON_PORT_ID_IOC_MASK) | (((pxu_p->portid >>
138325cf1a30Sjl 	    OBERON_PORT_ID_LSB) & OBERON_PORT_ID_LSB_MASK)
138425cf1a30Sjl 	    << OBERON_UBC_ID_LSB));
138525cf1a30Sjl 
138625cf1a30Sjl 	return (ubc_id);
138725cf1a30Sjl }
138825cf1a30Sjl 
138925cf1a30Sjl /*
139025cf1a30Sjl  * Oberon does not have a UBC scratch register, so alloc an array of scratch
139125cf1a30Sjl  * registers when needed and use a unique UBC ID as an index. This code
139225cf1a30Sjl  * can be simplified if we use a pre-allocated array. They are currently
139325cf1a30Sjl  * being dynamically allocated because it's only needed by the Oberon.
139425cf1a30Sjl  */
139525cf1a30Sjl static void
oberon_set_cb(dev_info_t * dip,uint64_t val)139625cf1a30Sjl oberon_set_cb(dev_info_t *dip, uint64_t val)
139725cf1a30Sjl {
139825cf1a30Sjl 	uint64_t	ubc_id;
139925cf1a30Sjl 
140025cf1a30Sjl 	if (px_oberon_ubc_scratch_regs == NULL)
140125cf1a30Sjl 		px_oberon_ubc_scratch_regs =
140225cf1a30Sjl 		    (uint64_t *)kmem_zalloc(sizeof (uint64_t)*
140325cf1a30Sjl 		    OBERON_UBC_ID_MAX, KM_SLEEP);
140425cf1a30Sjl 
140525cf1a30Sjl 	ubc_id = oberon_get_ubc_id(dip);
140625cf1a30Sjl 
140725cf1a30Sjl 	px_oberon_ubc_scratch_regs[ubc_id] = val;
140825cf1a30Sjl 
140925cf1a30Sjl 	/*
141025cf1a30Sjl 	 * Check if any scratch registers are still in use. If all scratch
141125cf1a30Sjl 	 * registers are currently set to zero, then deallocate the scratch
141225cf1a30Sjl 	 * register array.
141325cf1a30Sjl 	 */
141425cf1a30Sjl 	for (ubc_id = 0; ubc_id < OBERON_UBC_ID_MAX; ubc_id++) {
1415*e214b19eSToomas Soome 		if (px_oberon_ubc_scratch_regs[ubc_id] != 0)
141625cf1a30Sjl 			return;
141725cf1a30Sjl 	}
141825cf1a30Sjl 
141925cf1a30Sjl 	/*
142025cf1a30Sjl 	 * All scratch registers are set to zero so deallocate the scratch
142125cf1a30Sjl 	 * register array and set the pointer to NULL.
142225cf1a30Sjl 	 */
142325cf1a30Sjl 	kmem_free(px_oberon_ubc_scratch_regs,
142425cf1a30Sjl 	    (sizeof (uint64_t)*OBERON_UBC_ID_MAX));
142525cf1a30Sjl 
142625cf1a30Sjl 	px_oberon_ubc_scratch_regs = NULL;
142725cf1a30Sjl }
142825cf1a30Sjl 
142925cf1a30Sjl /*
143025cf1a30Sjl  * Oberon does not have a UBC scratch register, so use an allocated array of
143125cf1a30Sjl  * scratch registers and use the unique UBC ID as an index into that array.
143225cf1a30Sjl  */
143325cf1a30Sjl static uint64_t
oberon_get_cb(dev_info_t * dip)143425cf1a30Sjl oberon_get_cb(dev_info_t *dip)
143525cf1a30Sjl {
143625cf1a30Sjl 	uint64_t	ubc_id;
143725cf1a30Sjl 
143825cf1a30Sjl 	if (px_oberon_ubc_scratch_regs == NULL)
143925cf1a30Sjl 		return (0);
144025cf1a30Sjl 
144125cf1a30Sjl 	ubc_id = oberon_get_ubc_id(dip);
144225cf1a30Sjl 
144325cf1a30Sjl 	return (px_oberon_ubc_scratch_regs[ubc_id]);
144425cf1a30Sjl }
144525cf1a30Sjl 
144625cf1a30Sjl /*
144725cf1a30Sjl  * Misc Functions:
144825cf1a30Sjl  * Currently unsupported by hypervisor
144925cf1a30Sjl  */
145025cf1a30Sjl static uint64_t
px_get_cb(dev_info_t * dip)145125cf1a30Sjl px_get_cb(dev_info_t *dip)
145225cf1a30Sjl {
145325cf1a30Sjl 	px_t	*px_p = DIP_TO_STATE(dip);
145425cf1a30Sjl 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
145525cf1a30Sjl 
145625cf1a30Sjl 	/*
145725cf1a30Sjl 	 * Oberon does not currently have Scratchpad registers.
145825cf1a30Sjl 	 */
145925cf1a30Sjl 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON)
146025cf1a30Sjl 		return (oberon_get_cb(dip));
146125cf1a30Sjl 
146225cf1a30Sjl 	return (CSR_XR((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1));
146325cf1a30Sjl }
146425cf1a30Sjl 
146525cf1a30Sjl static void
px_set_cb(dev_info_t * dip,uint64_t val)146625cf1a30Sjl px_set_cb(dev_info_t *dip, uint64_t val)
146725cf1a30Sjl {
146825cf1a30Sjl 	px_t	*px_p = DIP_TO_STATE(dip);
146925cf1a30Sjl 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
147025cf1a30Sjl 
147125cf1a30Sjl 	/*
147225cf1a30Sjl 	 * Oberon does not currently have Scratchpad registers.
147325cf1a30Sjl 	 */
147425cf1a30Sjl 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) {
147525cf1a30Sjl 		oberon_set_cb(dip, val);
147625cf1a30Sjl 		return;
147725cf1a30Sjl 	}
147825cf1a30Sjl 
147925cf1a30Sjl 	CSR_XS((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1, val);
148025cf1a30Sjl }
148125cf1a30Sjl 
14827c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14837c478bd9Sstevel@tonic-gate int
px_lib_map_vconfig(dev_info_t * dip,ddi_map_req_t * mp,pci_config_offset_t off,pci_regspec_t * rp,caddr_t * addrp)14847c478bd9Sstevel@tonic-gate px_lib_map_vconfig(dev_info_t *dip,
14857c478bd9Sstevel@tonic-gate 	ddi_map_req_t *mp, pci_config_offset_t off,
14867c478bd9Sstevel@tonic-gate 		pci_regspec_t *rp, caddr_t *addrp)
14877c478bd9Sstevel@tonic-gate {
14887c478bd9Sstevel@tonic-gate 	/*
14897c478bd9Sstevel@tonic-gate 	 * No special config space access services in this layer.
14907c478bd9Sstevel@tonic-gate 	 */
14917c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
14927c478bd9Sstevel@tonic-gate }
14937c478bd9Sstevel@tonic-gate 
14944fbb58f6Sjchu void
px_lib_map_attr_check(ddi_map_req_t * mp)14954fbb58f6Sjchu px_lib_map_attr_check(ddi_map_req_t *mp)
14964fbb58f6Sjchu {
14974fbb58f6Sjchu 	ddi_acc_hdl_t *hp = mp->map_handlep;
14984fbb58f6Sjchu 
14994fbb58f6Sjchu 	/* fire does not accept byte masks from PIO store merge */
15004fbb58f6Sjchu 	if (hp->ah_acc.devacc_attr_dataorder == DDI_STORECACHING_OK_ACC)
15014fbb58f6Sjchu 		hp->ah_acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15024fbb58f6Sjchu }
15034fbb58f6Sjchu 
1504bf8fc234Set /* This function is called only by poke, caut put and pxtool poke. */
150569cd775fSschwartz void
px_lib_clr_errs(px_t * px_p,dev_info_t * rdip,uint64_t addr)1506bf8fc234Set px_lib_clr_errs(px_t *px_p, dev_info_t *rdip, uint64_t addr)
1507f8d2de6bSjchu {
150869cd775fSschwartz 	px_pec_t	*pec_p = px_p->px_pec_p;
1509f8d2de6bSjchu 	dev_info_t	*rpdip = px_p->px_dip;
1510bf8fc234Set 	int		rc_err, fab_err, i;
1511f8d2de6bSjchu 	int		acctype = pec_p->pec_safeacc_type;
1512f8d2de6bSjchu 	ddi_fm_error_t	derr;
151326947304SEvan Yan 	pci_ranges_t	*ranges_p;
1514bf8fc234Set 	int		range_len;
1515bf8fc234Set 	uint32_t	addr_high, addr_low;
1516c85864d8SKrishna Elango 	pcie_req_id_t	bdf = PCIE_INVALID_BDF;
1517f8d2de6bSjchu 
1518f8d2de6bSjchu 	/* Create the derr */
1519f8d2de6bSjchu 	bzero(&derr, sizeof (ddi_fm_error_t));
1520f8d2de6bSjchu 	derr.fme_version = DDI_FME_VERSION;
1521f8d2de6bSjchu 	derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
1522f8d2de6bSjchu 	derr.fme_flag = acctype;
1523f8d2de6bSjchu 
1524f8d2de6bSjchu 	if (acctype == DDI_FM_ERR_EXPECTED) {
1525f8d2de6bSjchu 		derr.fme_status = DDI_FM_NONFATAL;
1526f8d2de6bSjchu 		ndi_fm_acc_err_set(pec_p->pec_acc_hdl, &derr);
1527f8d2de6bSjchu 	}
1528f8d2de6bSjchu 
1529eae2e508Skrishnae 	if (px_fm_enter(px_p) != DDI_SUCCESS)
1530eae2e508Skrishnae 		return;
1531f8d2de6bSjchu 
1532f8d2de6bSjchu 	/* send ereport/handle/clear fire registers */
1533bf8fc234Set 	rc_err = px_err_cmn_intr(px_p, &derr, PX_LIB_CALL, PX_FM_BLOCK_ALL);
1534bf8fc234Set 
1535bf8fc234Set 	/* Figure out if this is a cfg or mem32 access */
1536bf8fc234Set 	addr_high = (uint32_t)(addr >> 32);
1537bf8fc234Set 	addr_low = (uint32_t)addr;
153826947304SEvan Yan 	range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
1539bf8fc234Set 	i = 0;
1540bf8fc234Set 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
1541bf8fc234Set 		if (ranges_p->parent_high == addr_high) {
1542bf8fc234Set 			switch (ranges_p->child_high & PCI_ADDR_MASK) {
1543bf8fc234Set 			case PCI_ADDR_CONFIG:
1544bf8fc234Set 				bdf = (pcie_req_id_t)(addr_low >> 12);
1545bf8fc234Set 				addr_low = 0;
1546bf8fc234Set 				break;
1547bf8fc234Set 			case PCI_ADDR_MEM32:
1548bf8fc234Set 				if (rdip)
1549eae2e508Skrishnae 					bdf = PCI_GET_BDF(rdip);
1550bf8fc234Set 				else
1551c85864d8SKrishna Elango 					bdf = PCIE_INVALID_BDF;
1552bf8fc234Set 				break;
1553bf8fc234Set 			}
1554bf8fc234Set 			break;
1555bf8fc234Set 		}
1556bf8fc234Set 	}
15573d9c56a1Set 
1558*e214b19eSToomas Soome 	(void) px_rp_en_q(px_p, bdf, addr_low, 0);
15593d9c56a1Set 
1560e51949e6Sdduvall 	/*
1561bf8fc234Set 	 * XXX - Current code scans the fabric for all px_tool accesses.
1562bf8fc234Set 	 * In future, do not scan fabric for px_tool access to IO Root Nexus
1563e51949e6Sdduvall 	 */
1564eae2e508Skrishnae 	fab_err = px_scan_fabric(px_p, rpdip, &derr);
1565bf8fc234Set 
1566eae2e508Skrishnae 	px_err_panic(rc_err, PX_RC, fab_err, B_TRUE);
1567eae2e508Skrishnae 	px_fm_exit(px_p);
1568eae2e508Skrishnae 	px_err_panic(rc_err, PX_RC, fab_err, B_FALSE);
1569f8d2de6bSjchu }
1570f8d2de6bSjchu 
15717c478bd9Sstevel@tonic-gate #ifdef  DEBUG
15727c478bd9Sstevel@tonic-gate int	px_peekfault_cnt = 0;
15737c478bd9Sstevel@tonic-gate int	px_pokefault_cnt = 0;
15747c478bd9Sstevel@tonic-gate #endif  /* DEBUG */
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15777c478bd9Sstevel@tonic-gate static int
px_lib_do_poke(dev_info_t * dip,dev_info_t * rdip,peekpoke_ctlops_t * in_args)15787c478bd9Sstevel@tonic-gate px_lib_do_poke(dev_info_t *dip, dev_info_t *rdip,
15797c478bd9Sstevel@tonic-gate     peekpoke_ctlops_t *in_args)
15807c478bd9Sstevel@tonic-gate {
15817c478bd9Sstevel@tonic-gate 	px_t *px_p = DIP_TO_STATE(dip);
15827c478bd9Sstevel@tonic-gate 	px_pec_t *pec_p = px_p->px_pec_p;
15837c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
15847c478bd9Sstevel@tonic-gate 	on_trap_data_t otd;
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	mutex_enter(&pec_p->pec_pokefault_mutex);
15877c478bd9Sstevel@tonic-gate 	pec_p->pec_ontrap_data = &otd;
1588f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_POKE;
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	/* Set up protected environment. */
15917c478bd9Sstevel@tonic-gate 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
15927c478bd9Sstevel@tonic-gate 		uintptr_t tramp = otd.ot_trampoline;
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = (uintptr_t)&poke_fault;
15957c478bd9Sstevel@tonic-gate 		err = do_poke(in_args->size, (void *)in_args->dev_addr,
15967c478bd9Sstevel@tonic-gate 		    (void *)in_args->host_addr);
15977c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = tramp;
15987c478bd9Sstevel@tonic-gate 	} else
15997c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
16007c478bd9Sstevel@tonic-gate 
1601bf8fc234Set 	px_lib_clr_errs(px_p, rdip, in_args->dev_addr);
1602f8d2de6bSjchu 
16037c478bd9Sstevel@tonic-gate 	if (otd.ot_trap & OT_DATA_ACCESS)
16047c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	/* Take down protected environment. */
16077c478bd9Sstevel@tonic-gate 	no_trap();
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	pec_p->pec_ontrap_data = NULL;
1610f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
16117c478bd9Sstevel@tonic-gate 	mutex_exit(&pec_p->pec_pokefault_mutex);
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate #ifdef  DEBUG
16147c478bd9Sstevel@tonic-gate 	if (err == DDI_FAILURE)
16157c478bd9Sstevel@tonic-gate 		px_pokefault_cnt++;
16167c478bd9Sstevel@tonic-gate #endif
16177c478bd9Sstevel@tonic-gate 	return (err);
16187c478bd9Sstevel@tonic-gate }
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16217c478bd9Sstevel@tonic-gate static int
px_lib_do_caut_put(dev_info_t * dip,dev_info_t * rdip,peekpoke_ctlops_t * cautacc_ctlops_arg)16227c478bd9Sstevel@tonic-gate px_lib_do_caut_put(dev_info_t *dip, dev_info_t *rdip,
16237c478bd9Sstevel@tonic-gate     peekpoke_ctlops_t *cautacc_ctlops_arg)
16247c478bd9Sstevel@tonic-gate {
16257c478bd9Sstevel@tonic-gate 	size_t size = cautacc_ctlops_arg->size;
16267c478bd9Sstevel@tonic-gate 	uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr;
16277c478bd9Sstevel@tonic-gate 	uintptr_t host_addr = cautacc_ctlops_arg->host_addr;
16287c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle;
16297c478bd9Sstevel@tonic-gate 	size_t repcount = cautacc_ctlops_arg->repcount;
16307c478bd9Sstevel@tonic-gate 	uint_t flags = cautacc_ctlops_arg->flags;
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	px_t *px_p = DIP_TO_STATE(dip);
16337c478bd9Sstevel@tonic-gate 	px_pec_t *pec_p = px_p->px_pec_p;
16347c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
16357c478bd9Sstevel@tonic-gate 
1636f8d2de6bSjchu 	/*
1637f8d2de6bSjchu 	 * Note that i_ndi_busop_access_enter ends up grabbing the pokefault
1638f8d2de6bSjchu 	 * mutex.
1639f8d2de6bSjchu 	 */
16407c478bd9Sstevel@tonic-gate 	i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
16417c478bd9Sstevel@tonic-gate 
1642f8d2de6bSjchu 	pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap;
1643f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED;
1644f8d2de6bSjchu 	hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED;
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate 	if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) {
16477c478bd9Sstevel@tonic-gate 		for (; repcount; repcount--) {
16487c478bd9Sstevel@tonic-gate 			switch (size) {
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 			case sizeof (uint8_t):
16517c478bd9Sstevel@tonic-gate 				i_ddi_put8(hp, (uint8_t *)dev_addr,
16527c478bd9Sstevel@tonic-gate 				    *(uint8_t *)host_addr);
16537c478bd9Sstevel@tonic-gate 				break;
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 			case sizeof (uint16_t):
16567c478bd9Sstevel@tonic-gate 				i_ddi_put16(hp, (uint16_t *)dev_addr,
16577c478bd9Sstevel@tonic-gate 				    *(uint16_t *)host_addr);
16587c478bd9Sstevel@tonic-gate 				break;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 			case sizeof (uint32_t):
16617c478bd9Sstevel@tonic-gate 				i_ddi_put32(hp, (uint32_t *)dev_addr,
16627c478bd9Sstevel@tonic-gate 				    *(uint32_t *)host_addr);
16637c478bd9Sstevel@tonic-gate 				break;
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 			case sizeof (uint64_t):
16667c478bd9Sstevel@tonic-gate 				i_ddi_put64(hp, (uint64_t *)dev_addr,
16677c478bd9Sstevel@tonic-gate 				    *(uint64_t *)host_addr);
16687c478bd9Sstevel@tonic-gate 				break;
16697c478bd9Sstevel@tonic-gate 			}
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 			host_addr += size;
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 			if (flags == DDI_DEV_AUTOINCR)
16747c478bd9Sstevel@tonic-gate 				dev_addr += size;
16757c478bd9Sstevel@tonic-gate 
1676bf8fc234Set 			px_lib_clr_errs(px_p, rdip, dev_addr);
1677f8d2de6bSjchu 
16787c478bd9Sstevel@tonic-gate 			if (pec_p->pec_ontrap_data->ot_trap & OT_DATA_ACCESS) {
16797c478bd9Sstevel@tonic-gate 				err = DDI_FAILURE;
16807c478bd9Sstevel@tonic-gate #ifdef  DEBUG
16817c478bd9Sstevel@tonic-gate 				px_pokefault_cnt++;
16827c478bd9Sstevel@tonic-gate #endif
16837c478bd9Sstevel@tonic-gate 				break;
16847c478bd9Sstevel@tonic-gate 			}
16857c478bd9Sstevel@tonic-gate 		}
16867c478bd9Sstevel@tonic-gate 	}
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	i_ddi_notrap((ddi_acc_handle_t)hp);
16897c478bd9Sstevel@tonic-gate 	pec_p->pec_ontrap_data = NULL;
1690f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
16917c478bd9Sstevel@tonic-gate 	i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
16927c478bd9Sstevel@tonic-gate 	hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED;
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	return (err);
16957c478bd9Sstevel@tonic-gate }
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate int
px_lib_ctlops_poke(dev_info_t * dip,dev_info_t * rdip,peekpoke_ctlops_t * in_args)16997c478bd9Sstevel@tonic-gate px_lib_ctlops_poke(dev_info_t *dip, dev_info_t *rdip,
17007c478bd9Sstevel@tonic-gate     peekpoke_ctlops_t *in_args)
17017c478bd9Sstevel@tonic-gate {
17027c478bd9Sstevel@tonic-gate 	return (in_args->handle ? px_lib_do_caut_put(dip, rdip, in_args) :
17037c478bd9Sstevel@tonic-gate 	    px_lib_do_poke(dip, rdip, in_args));
17047c478bd9Sstevel@tonic-gate }
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17087c478bd9Sstevel@tonic-gate static int
px_lib_do_peek(dev_info_t * dip,peekpoke_ctlops_t * in_args)17097c478bd9Sstevel@tonic-gate px_lib_do_peek(dev_info_t *dip, peekpoke_ctlops_t *in_args)
17107c478bd9Sstevel@tonic-gate {
1711f8d2de6bSjchu 	px_t *px_p = DIP_TO_STATE(dip);
1712f8d2de6bSjchu 	px_pec_t *pec_p = px_p->px_pec_p;
17137c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
17147c478bd9Sstevel@tonic-gate 	on_trap_data_t otd;
17157c478bd9Sstevel@tonic-gate 
1716f8d2de6bSjchu 	mutex_enter(&pec_p->pec_pokefault_mutex);
1717fc256490SJason Beloro 	if (px_fm_enter(px_p) != DDI_SUCCESS) {
1718fc256490SJason Beloro 		mutex_exit(&pec_p->pec_pokefault_mutex);
1719eae2e508Skrishnae 		return (DDI_FAILURE);
1720fc256490SJason Beloro 	}
1721f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK;
1722eae2e508Skrishnae 	px_fm_exit(px_p);
1723f8d2de6bSjchu 
17247c478bd9Sstevel@tonic-gate 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
17257c478bd9Sstevel@tonic-gate 		uintptr_t tramp = otd.ot_trampoline;
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = (uintptr_t)&peek_fault;
17287c478bd9Sstevel@tonic-gate 		err = do_peek(in_args->size, (void *)in_args->dev_addr,
17297c478bd9Sstevel@tonic-gate 		    (void *)in_args->host_addr);
17307c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = tramp;
17317c478bd9Sstevel@tonic-gate 	} else
17327c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	no_trap();
1735f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1736f8d2de6bSjchu 	mutex_exit(&pec_p->pec_pokefault_mutex);
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate #ifdef  DEBUG
17397c478bd9Sstevel@tonic-gate 	if (err == DDI_FAILURE)
17407c478bd9Sstevel@tonic-gate 		px_peekfault_cnt++;
17417c478bd9Sstevel@tonic-gate #endif
17427c478bd9Sstevel@tonic-gate 	return (err);
17437c478bd9Sstevel@tonic-gate }
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate static int
px_lib_do_caut_get(dev_info_t * dip,peekpoke_ctlops_t * cautacc_ctlops_arg)17477c478bd9Sstevel@tonic-gate px_lib_do_caut_get(dev_info_t *dip, peekpoke_ctlops_t *cautacc_ctlops_arg)
17487c478bd9Sstevel@tonic-gate {
17497c478bd9Sstevel@tonic-gate 	size_t size = cautacc_ctlops_arg->size;
17507c478bd9Sstevel@tonic-gate 	uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr;
17517c478bd9Sstevel@tonic-gate 	uintptr_t host_addr = cautacc_ctlops_arg->host_addr;
17527c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle;
17537c478bd9Sstevel@tonic-gate 	size_t repcount = cautacc_ctlops_arg->repcount;
17547c478bd9Sstevel@tonic-gate 	uint_t flags = cautacc_ctlops_arg->flags;
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	px_t *px_p = DIP_TO_STATE(dip);
17577c478bd9Sstevel@tonic-gate 	px_pec_t *pec_p = px_p->px_pec_p;
17587c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
17597c478bd9Sstevel@tonic-gate 
1760f8d2de6bSjchu 	/*
1761f8d2de6bSjchu 	 * Note that i_ndi_busop_access_enter ends up grabbing the pokefault
1762f8d2de6bSjchu 	 * mutex.
1763f8d2de6bSjchu 	 */
17647c478bd9Sstevel@tonic-gate 	i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
17657c478bd9Sstevel@tonic-gate 
1766f8d2de6bSjchu 	pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap;
1767f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED;
1768f8d2de6bSjchu 	hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED;
1769f8d2de6bSjchu 
17707c478bd9Sstevel@tonic-gate 	if (repcount == 1) {
17717c478bd9Sstevel@tonic-gate 		if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) {
17727c478bd9Sstevel@tonic-gate 			i_ddi_caut_get(size, (void *)dev_addr,
17737c478bd9Sstevel@tonic-gate 			    (void *)host_addr);
17747c478bd9Sstevel@tonic-gate 		} else {
17757c478bd9Sstevel@tonic-gate 			int i;
17767c478bd9Sstevel@tonic-gate 			uint8_t *ff_addr = (uint8_t *)host_addr;
17777c478bd9Sstevel@tonic-gate 			for (i = 0; i < size; i++)
17787c478bd9Sstevel@tonic-gate 				*ff_addr++ = 0xff;
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 			err = DDI_FAILURE;
17817c478bd9Sstevel@tonic-gate #ifdef  DEBUG
17827c478bd9Sstevel@tonic-gate 			px_peekfault_cnt++;
17837c478bd9Sstevel@tonic-gate #endif
17847c478bd9Sstevel@tonic-gate 		}
17857c478bd9Sstevel@tonic-gate 	} else {
17867c478bd9Sstevel@tonic-gate 		if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) {
17877c478bd9Sstevel@tonic-gate 			for (; repcount; repcount--) {
17887c478bd9Sstevel@tonic-gate 				i_ddi_caut_get(size, (void *)dev_addr,
17897c478bd9Sstevel@tonic-gate 				    (void *)host_addr);
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 				host_addr += size;
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 				if (flags == DDI_DEV_AUTOINCR)
17947c478bd9Sstevel@tonic-gate 					dev_addr += size;
17957c478bd9Sstevel@tonic-gate 			}
17967c478bd9Sstevel@tonic-gate 		} else {
17977c478bd9Sstevel@tonic-gate 			err = DDI_FAILURE;
17987c478bd9Sstevel@tonic-gate #ifdef  DEBUG
17997c478bd9Sstevel@tonic-gate 			px_peekfault_cnt++;
18007c478bd9Sstevel@tonic-gate #endif
18017c478bd9Sstevel@tonic-gate 		}
18027c478bd9Sstevel@tonic-gate 	}
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate 	i_ddi_notrap((ddi_acc_handle_t)hp);
18057c478bd9Sstevel@tonic-gate 	pec_p->pec_ontrap_data = NULL;
1806f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
18077c478bd9Sstevel@tonic-gate 	i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
18087c478bd9Sstevel@tonic-gate 	hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED;
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	return (err);
18117c478bd9Sstevel@tonic-gate }
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
18147c478bd9Sstevel@tonic-gate int
px_lib_ctlops_peek(dev_info_t * dip,dev_info_t * rdip,peekpoke_ctlops_t * in_args,void * result)18157c478bd9Sstevel@tonic-gate px_lib_ctlops_peek(dev_info_t *dip, dev_info_t *rdip,
18167c478bd9Sstevel@tonic-gate     peekpoke_ctlops_t *in_args, void *result)
18177c478bd9Sstevel@tonic-gate {
18187c478bd9Sstevel@tonic-gate 	result = (void *)in_args->host_addr;
18197c478bd9Sstevel@tonic-gate 	return (in_args->handle ? px_lib_do_caut_get(dip, in_args) :
18207c478bd9Sstevel@tonic-gate 	    px_lib_do_peek(dip, in_args));
18217c478bd9Sstevel@tonic-gate }
18221a887b2eSjchu 
18237c478bd9Sstevel@tonic-gate /*
18247c478bd9Sstevel@tonic-gate  * implements PPM interface
18257c478bd9Sstevel@tonic-gate  */
18267c478bd9Sstevel@tonic-gate int
px_lib_pmctl(int cmd,px_t * px_p)18277c478bd9Sstevel@tonic-gate px_lib_pmctl(int cmd, px_t *px_p)
18287c478bd9Sstevel@tonic-gate {
18297c478bd9Sstevel@tonic-gate 	ASSERT((cmd & ~PPMREQ_MASK) == PPMREQ);
18307c478bd9Sstevel@tonic-gate 	switch (cmd) {
18317c478bd9Sstevel@tonic-gate 	case PPMREQ_PRE_PWR_OFF:
18327c478bd9Sstevel@tonic-gate 		/*
18337c478bd9Sstevel@tonic-gate 		 * Currently there is no device power management for
18347c478bd9Sstevel@tonic-gate 		 * the root complex (fire). When there is we need to make
18357c478bd9Sstevel@tonic-gate 		 * sure that it is at full power before trying to send the
18367c478bd9Sstevel@tonic-gate 		 * PME_Turn_Off message.
18377c478bd9Sstevel@tonic-gate 		 */
18387c478bd9Sstevel@tonic-gate 		DBG(DBG_PWR, px_p->px_dip,
18397c478bd9Sstevel@tonic-gate 		    "ioctl: request to send PME_Turn_Off\n");
18407c478bd9Sstevel@tonic-gate 		return (px_goto_l23ready(px_p));
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	case PPMREQ_PRE_PWR_ON:
18431a887b2eSjchu 		DBG(DBG_PWR, px_p->px_dip, "ioctl: PRE_PWR_ON request\n");
18441a887b2eSjchu 		return (px_pre_pwron_check(px_p));
18451a887b2eSjchu 
18467c478bd9Sstevel@tonic-gate 	case PPMREQ_POST_PWR_ON:
18471a887b2eSjchu 		DBG(DBG_PWR, px_p->px_dip, "ioctl: POST_PWR_ON request\n");
18481a887b2eSjchu 		return (px_goto_l0(px_p));
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 	default:
18517c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
18527c478bd9Sstevel@tonic-gate 	}
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate /*
18567c478bd9Sstevel@tonic-gate  * sends PME_Turn_Off message to put the link in L2/L3 ready state.
18577c478bd9Sstevel@tonic-gate  * called by px_ioctl.
18587c478bd9Sstevel@tonic-gate  * returns DDI_SUCCESS or DDI_FAILURE
18597c478bd9Sstevel@tonic-gate  * 1. Wait for link to be in L1 state (link status reg)
18607c478bd9Sstevel@tonic-gate  * 2. write to PME_Turn_off reg to boradcast
18617c478bd9Sstevel@tonic-gate  * 3. set timeout
18627c478bd9Sstevel@tonic-gate  * 4. If timeout, return failure.
18637c478bd9Sstevel@tonic-gate  * 5. If PM_TO_Ack, wait till link is in L2/L3 ready
18647c478bd9Sstevel@tonic-gate  */
18657c478bd9Sstevel@tonic-gate static int
px_goto_l23ready(px_t * px_p)18667c478bd9Sstevel@tonic-gate px_goto_l23ready(px_t *px_p)
18677c478bd9Sstevel@tonic-gate {
18687c478bd9Sstevel@tonic-gate 	pcie_pwr_t	*pwr_p;
1869f8d2de6bSjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
1870f8d2de6bSjchu 	caddr_t	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
18717c478bd9Sstevel@tonic-gate 	int		ret = DDI_SUCCESS;
18727c478bd9Sstevel@tonic-gate 	clock_t		end, timeleft;
18731a887b2eSjchu 	int		mutex_held = 1;
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	/* If no PM info, return failure */
1876*e214b19eSToomas Soome 	if (PCIE_PMINFO(px_p->px_dip) == NULL ||
1877*e214b19eSToomas Soome 	    (pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip)) == NULL)
18787c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 	mutex_enter(&pwr_p->pwr_lock);
18811a887b2eSjchu 	mutex_enter(&px_p->px_l23ready_lock);
18827c478bd9Sstevel@tonic-gate 	/* Clear the PME_To_ACK receieved flag */
18831a887b2eSjchu 	px_p->px_pm_flags &= ~PX_PMETOACK_RECVD;
18843ee8f295Smg 	/*
18853ee8f295Smg 	 * When P25 is the downstream device, after receiving
18863ee8f295Smg 	 * PME_To_ACK, fire will go to Detect state, which causes
18873ee8f295Smg 	 * the link down event. Inform FMA that this is expected.
18883ee8f295Smg 	 * In case of all other cards complaint with the pci express
18893ee8f295Smg 	 * spec, this will happen when the power is re-applied. FMA
18903ee8f295Smg 	 * code will clear this flag after one instance of LDN. Since
18913ee8f295Smg 	 * there will not be a LDN event for the spec compliant cards,
18923ee8f295Smg 	 * we need to clear the flag after receiving PME_To_ACK.
18933ee8f295Smg 	 */
18943ee8f295Smg 	px_p->px_pm_flags |= PX_LDN_EXPECTED;
18957c478bd9Sstevel@tonic-gate 	if (px_send_pme_turnoff(csr_base) != DDI_SUCCESS) {
18967c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
18977c478bd9Sstevel@tonic-gate 		goto l23ready_done;
18987c478bd9Sstevel@tonic-gate 	}
18991a887b2eSjchu 	px_p->px_pm_flags |= PX_PME_TURNOFF_PENDING;
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	end = ddi_get_lbolt() + drv_usectohz(px_pme_to_ack_timeout);
19021a887b2eSjchu 	while (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) {
19031a887b2eSjchu 		timeleft = cv_timedwait(&px_p->px_l23ready_cv,
19041a887b2eSjchu 		    &px_p->px_l23ready_lock, end);
19057c478bd9Sstevel@tonic-gate 		/*
19067c478bd9Sstevel@tonic-gate 		 * if cv_timedwait returns -1, it is either
19077c478bd9Sstevel@tonic-gate 		 * 1) timed out or
19087c478bd9Sstevel@tonic-gate 		 * 2) there was a pre-mature wakeup but by the time
19097c478bd9Sstevel@tonic-gate 		 * cv_timedwait is called again end < lbolt i.e.
19107c478bd9Sstevel@tonic-gate 		 * end is in the past.
19117c478bd9Sstevel@tonic-gate 		 * 3) By the time we make first cv_timedwait call,
19127c478bd9Sstevel@tonic-gate 		 * end < lbolt is true.
19137c478bd9Sstevel@tonic-gate 		 */
19147c478bd9Sstevel@tonic-gate 		if (timeleft == -1)
19157c478bd9Sstevel@tonic-gate 			break;
19167c478bd9Sstevel@tonic-gate 	}
19171a887b2eSjchu 	if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) {
19187c478bd9Sstevel@tonic-gate 		/*
19197c478bd9Sstevel@tonic-gate 		 * Either timedout or interrupt didn't get a
19207c478bd9Sstevel@tonic-gate 		 * chance to grab the mutex and set the flag.
19217c478bd9Sstevel@tonic-gate 		 * release the mutex and delay for sometime.
19227c478bd9Sstevel@tonic-gate 		 * This will 1) give a chance for interrupt to
19237c478bd9Sstevel@tonic-gate 		 * set the flag 2) creates a delay between two
19247c478bd9Sstevel@tonic-gate 		 * consequetive requests.
19257c478bd9Sstevel@tonic-gate 		 */
19261a887b2eSjchu 		mutex_exit(&px_p->px_l23ready_lock);
1927f9721e07Sjchu 		delay(drv_usectohz(50 * PX_MSEC_TO_USEC));
19281a887b2eSjchu 		mutex_held = 0;
19291a887b2eSjchu 		if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) {
19307c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
19317c478bd9Sstevel@tonic-gate 			DBG(DBG_PWR, px_p->px_dip, " Timed out while waiting"
19327c478bd9Sstevel@tonic-gate 			    " for PME_TO_ACK\n");
19337c478bd9Sstevel@tonic-gate 		}
19347c478bd9Sstevel@tonic-gate 	}
19353ee8f295Smg 	px_p->px_pm_flags &=
19363ee8f295Smg 	    ~(PX_PME_TURNOFF_PENDING | PX_PMETOACK_RECVD | PX_LDN_EXPECTED);
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate l23ready_done:
19391a887b2eSjchu 	if (mutex_held)
19401a887b2eSjchu 		mutex_exit(&px_p->px_l23ready_lock);
19411a887b2eSjchu 	/*
19421a887b2eSjchu 	 * Wait till link is in L1 idle, if sending PME_Turn_Off
19431a887b2eSjchu 	 * was succesful.
19441a887b2eSjchu 	 */
19451a887b2eSjchu 	if (ret == DDI_SUCCESS) {
19461a887b2eSjchu 		if (px_link_wait4l1idle(csr_base) != DDI_SUCCESS) {
19471a887b2eSjchu 			DBG(DBG_PWR, px_p->px_dip, " Link is not at L1"
19483ee8f295Smg 			    " even though we received PME_To_ACK.\n");
19493ee8f295Smg 			/*
19503ee8f295Smg 			 * Workaround for hardware bug with P25.
19513ee8f295Smg 			 * Due to a hardware bug with P25, link state
19523ee8f295Smg 			 * will be Detect state rather than L1 after
19533ee8f295Smg 			 * link is transitioned to L23Ready state. Since
19543ee8f295Smg 			 * we don't know whether link is L23ready state
19553ee8f295Smg 			 * without Fire's state being L1_idle, we delay
19563ee8f295Smg 			 * here just to make sure that we wait till link
19573ee8f295Smg 			 * is transitioned to L23Ready state.
19583ee8f295Smg 			 */
1959f9721e07Sjchu 			delay(drv_usectohz(100 * PX_MSEC_TO_USEC));
19603ee8f295Smg 		}
19613ee8f295Smg 		pwr_p->pwr_link_lvl = PM_LEVEL_L3;
19621a887b2eSjchu 
19631a887b2eSjchu 	}
19641a887b2eSjchu 	mutex_exit(&pwr_p->pwr_lock);
19651a887b2eSjchu 	return (ret);
19661a887b2eSjchu }
19671a887b2eSjchu 
19681a887b2eSjchu /*
19691a887b2eSjchu  * Message interrupt handler intended to be shared for both
19701a887b2eSjchu  * PME and PME_TO_ACK msg handling, currently only handles
19711a887b2eSjchu  * PME_To_ACK message.
19721a887b2eSjchu  */
19731a887b2eSjchu uint_t
px_pmeq_intr(caddr_t arg)19741a887b2eSjchu px_pmeq_intr(caddr_t arg)
19751a887b2eSjchu {
19761a887b2eSjchu 	px_t	*px_p = (px_t *)arg;
19771a887b2eSjchu 
19783ee8f295Smg 	DBG(DBG_PWR, px_p->px_dip, " PME_To_ACK received \n");
19791a887b2eSjchu 	mutex_enter(&px_p->px_l23ready_lock);
19801a887b2eSjchu 	cv_broadcast(&px_p->px_l23ready_cv);
19811a887b2eSjchu 	if (px_p->px_pm_flags & PX_PME_TURNOFF_PENDING) {
19821a887b2eSjchu 		px_p->px_pm_flags |= PX_PMETOACK_RECVD;
19831a887b2eSjchu 	} else {
19841a887b2eSjchu 		/*
19851a887b2eSjchu 		 * This maybe the second ack received. If so then,
19861a887b2eSjchu 		 * we should be receiving it during wait4L1 stage.
19871a887b2eSjchu 		 */
19881a887b2eSjchu 		px_p->px_pmetoack_ignored++;
19891a887b2eSjchu 	}
19901a887b2eSjchu 	mutex_exit(&px_p->px_l23ready_lock);
19911a887b2eSjchu 	return (DDI_INTR_CLAIMED);
19921a887b2eSjchu }
19931a887b2eSjchu 
19941a887b2eSjchu static int
px_pre_pwron_check(px_t * px_p)19951a887b2eSjchu px_pre_pwron_check(px_t *px_p)
19961a887b2eSjchu {
19971a887b2eSjchu 	pcie_pwr_t	*pwr_p;
19981a887b2eSjchu 
19991a887b2eSjchu 	/* If no PM info, return failure */
2000*e214b19eSToomas Soome 	if (PCIE_PMINFO(px_p->px_dip) == NULL ||
2001*e214b19eSToomas Soome 	    (pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip)) == NULL)
20021a887b2eSjchu 		return (DDI_FAILURE);
20031a887b2eSjchu 
20043ee8f295Smg 	/*
20053ee8f295Smg 	 * For the spec compliant downstream cards link down
20063ee8f295Smg 	 * is expected when the device is powered on.
20073ee8f295Smg 	 */
20083ee8f295Smg 	px_p->px_pm_flags |= PX_LDN_EXPECTED;
20091a887b2eSjchu 	return (pwr_p->pwr_link_lvl == PM_LEVEL_L3 ? DDI_SUCCESS : DDI_FAILURE);
20101a887b2eSjchu }
20111a887b2eSjchu 
20121a887b2eSjchu static int
px_goto_l0(px_t * px_p)20131a887b2eSjchu px_goto_l0(px_t *px_p)
20141a887b2eSjchu {
20151a887b2eSjchu 	pcie_pwr_t	*pwr_p;
20161a887b2eSjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
20171a887b2eSjchu 	caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
20181a887b2eSjchu 	int		ret = DDI_SUCCESS;
2019f9721e07Sjchu 	uint64_t	time_spent = 0;
20201a887b2eSjchu 
20211a887b2eSjchu 	/* If no PM info, return failure */
2022*e214b19eSToomas Soome 	if (PCIE_PMINFO(px_p->px_dip) == NULL ||
2023*e214b19eSToomas Soome 	    (pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip)) == NULL)
20241a887b2eSjchu 		return (DDI_FAILURE);
20251a887b2eSjchu 
20261a887b2eSjchu 	mutex_enter(&pwr_p->pwr_lock);
20273ee8f295Smg 	/*
2028f9721e07Sjchu 	 * The following link retrain activity will cause LDN and LUP event.
2029f9721e07Sjchu 	 * Receiving LDN prior to receiving LUP is expected, not an error in
2030f9721e07Sjchu 	 * this case.  Receiving LUP indicates link is fully up to support
2031f9721e07Sjchu 	 * powering up down stream device, and of course any further LDN and
2032f9721e07Sjchu 	 * LUP outside this context will be error.
20333ee8f295Smg 	 */
2034f9721e07Sjchu 	px_p->px_lup_pending = 1;
20351a887b2eSjchu 	if (px_link_retrain(csr_base) != DDI_SUCCESS) {
20361a887b2eSjchu 		ret = DDI_FAILURE;
20371a887b2eSjchu 		goto l0_done;
20381a887b2eSjchu 	}
20391a887b2eSjchu 
2040f9721e07Sjchu 	/* LUP event takes the order of 15ms amount of time to occur */
2041f9721e07Sjchu 	for (; px_p->px_lup_pending && (time_spent < px_lup_poll_to);
2042f9721e07Sjchu 	    time_spent += px_lup_poll_interval)
2043f9721e07Sjchu 		drv_usecwait(px_lup_poll_interval);
2044f9721e07Sjchu 	if (px_p->px_lup_pending)
2045f9721e07Sjchu 		ret = DDI_FAILURE;
20461a887b2eSjchu l0_done:
20473ee8f295Smg 	px_enable_detect_quiet(csr_base);
20481a887b2eSjchu 	if (ret == DDI_SUCCESS)
20493ee8f295Smg 		pwr_p->pwr_link_lvl = PM_LEVEL_L0;
20507c478bd9Sstevel@tonic-gate 	mutex_exit(&pwr_p->pwr_lock);
20517c478bd9Sstevel@tonic-gate 	return (ret);
20527c478bd9Sstevel@tonic-gate }
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate /*
20557c478bd9Sstevel@tonic-gate  * Extract the drivers binding name to identify which chip we're binding to.
20567c478bd9Sstevel@tonic-gate  * Whenever a new bus bridge is created, the driver alias entry should be
20577c478bd9Sstevel@tonic-gate  * added here to identify the device if needed.  If a device isn't added,
20587c478bd9Sstevel@tonic-gate  * the identity defaults to PX_CHIP_UNIDENTIFIED.
20597c478bd9Sstevel@tonic-gate  */
20607c478bd9Sstevel@tonic-gate static uint32_t
px_identity_init(px_t * px_p)20617e1db6d2Sschwartz px_identity_init(px_t *px_p)
20627c478bd9Sstevel@tonic-gate {
20637c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = px_p->px_dip;
20647c478bd9Sstevel@tonic-gate 	char		*name = ddi_binding_name(dip);
20657c478bd9Sstevel@tonic-gate 	uint32_t	revision = 0;
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	revision = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
20687c478bd9Sstevel@tonic-gate 	    "module-revision#", 0);
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 	/* Check for Fire driver binding name */
20717e1db6d2Sschwartz 	if (strcmp(name, "pciex108e,80f0") == 0) {
20727e1db6d2Sschwartz 		DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: "
20737e1db6d2Sschwartz 		    "(FIRE), module-revision %d\n", NAMEINST(dip),
20747e1db6d2Sschwartz 		    revision);
20757c478bd9Sstevel@tonic-gate 
20767e1db6d2Sschwartz 		return ((revision >= FIRE_MOD_REV_20) ?
20777e1db6d2Sschwartz 		    PX_CHIP_FIRE : PX_CHIP_UNIDENTIFIED);
20787c478bd9Sstevel@tonic-gate 	}
20797c478bd9Sstevel@tonic-gate 
208025cf1a30Sjl 	/* Check for Oberon driver binding name */
208125cf1a30Sjl 	if (strcmp(name, "pciex108e,80f8") == 0) {
20827e1db6d2Sschwartz 		DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: "
20837e1db6d2Sschwartz 		    "(OBERON), module-revision %d\n", NAMEINST(dip),
20847e1db6d2Sschwartz 		    revision);
208525cf1a30Sjl 
20867e1db6d2Sschwartz 		return (PX_CHIP_OBERON);
208725cf1a30Sjl 	}
208825cf1a30Sjl 
20897c478bd9Sstevel@tonic-gate 	DBG(DBG_ATTACH, dip, "%s%d: Unknown PCI Express Host bridge %s %x\n",
20907c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), name, revision);
20917c478bd9Sstevel@tonic-gate 
20927c478bd9Sstevel@tonic-gate 	return (PX_CHIP_UNIDENTIFIED);
20937c478bd9Sstevel@tonic-gate }
2094f8d2de6bSjchu 
2095f8d2de6bSjchu int
px_err_add_intr(px_fault_t * px_fault_p)2096f8d2de6bSjchu px_err_add_intr(px_fault_t *px_fault_p)
2097f8d2de6bSjchu {
2098f8d2de6bSjchu 	dev_info_t	*dip = px_fault_p->px_fh_dip;
2099f8d2de6bSjchu 	px_t		*px_p = DIP_TO_STATE(dip);
2100f8d2de6bSjchu 
2101f8d2de6bSjchu 	VERIFY(add_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL,
2102b0fc0e77Sgovinda 	    (intrfunc)px_fault_p->px_err_func, (caddr_t)px_fault_p,
2103b0fc0e77Sgovinda 	    NULL, NULL) == 0);
2104f8d2de6bSjchu 
2105f8d2de6bSjchu 	px_ib_intr_enable(px_p, intr_dist_cpuid(), px_fault_p->px_intr_ino);
2106f8d2de6bSjchu 
2107f8d2de6bSjchu 	return (DDI_SUCCESS);
2108f8d2de6bSjchu }
2109f8d2de6bSjchu 
2110f8d2de6bSjchu void
px_err_rem_intr(px_fault_t * px_fault_p)2111f8d2de6bSjchu px_err_rem_intr(px_fault_t *px_fault_p)
2112f8d2de6bSjchu {
2113f8d2de6bSjchu 	dev_info_t	*dip = px_fault_p->px_fh_dip;
2114f8d2de6bSjchu 	px_t		*px_p = DIP_TO_STATE(dip);
2115f8d2de6bSjchu 
2116f8d2de6bSjchu 	px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino,
2117eae2e508Skrishnae 	    IB_INTR_WAIT);
21189c75c6bfSgovinda 
2119b0fc0e77Sgovinda 	VERIFY(rem_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL) == 0);
2120f8d2de6bSjchu }
2121f8d2de6bSjchu 
2122a3c68edcSjchu /*
2123a3c68edcSjchu  * px_cb_intr_redist() - sun4u only, CB interrupt redistribution
2124a3c68edcSjchu  */
2125a3c68edcSjchu void
px_cb_intr_redist(void * arg)2126a3c68edcSjchu px_cb_intr_redist(void *arg)
2127a3c68edcSjchu {
2128a3c68edcSjchu 	px_cb_t		*cb_p = (px_cb_t *)arg;
2129a3c68edcSjchu 	px_cb_list_t	*pxl;
2130a3c68edcSjchu 	px_t		*pxp = NULL;
2131a3c68edcSjchu 	px_fault_t	*f_p = NULL;
2132a3c68edcSjchu 	uint32_t	new_cpuid;
2133a3c68edcSjchu 	intr_valid_state_t	enabled = 0;
2134a3c68edcSjchu 
2135a3c68edcSjchu 	mutex_enter(&cb_p->cb_mutex);
2136a3c68edcSjchu 
2137a3c68edcSjchu 	pxl = cb_p->pxl;
2138*e214b19eSToomas Soome 	if (pxl == NULL)
2139a3c68edcSjchu 		goto cb_done;
2140a3c68edcSjchu 
2141a3c68edcSjchu 	pxp = pxl->pxp;
2142a3c68edcSjchu 	f_p = &pxp->px_cb_fault;
2143a3c68edcSjchu 	for (; pxl && (f_p->px_fh_sysino != cb_p->sysino); ) {
2144a3c68edcSjchu 		pxl = pxl->next;
2145a3c68edcSjchu 		pxp = pxl->pxp;
2146a3c68edcSjchu 		f_p = &pxp->px_cb_fault;
2147a3c68edcSjchu 	}
2148a3c68edcSjchu 	if (pxl == NULL)
2149a3c68edcSjchu 		goto cb_done;
2150a3c68edcSjchu 
2151a3c68edcSjchu 	new_cpuid =  intr_dist_cpuid();
2152a3c68edcSjchu 	if (new_cpuid == cb_p->cpuid)
2153a3c68edcSjchu 		goto cb_done;
2154a3c68edcSjchu 
2155a3c68edcSjchu 	if ((px_lib_intr_getvalid(pxp->px_dip, f_p->px_fh_sysino, &enabled)
2156a3c68edcSjchu 	    != DDI_SUCCESS) || !enabled) {
2157a3c68edcSjchu 		DBG(DBG_IB, pxp->px_dip, "px_cb_intr_redist: CB not enabled, "
2158a3c68edcSjchu 		    "sysino(0x%x)\n", f_p->px_fh_sysino);
2159a3c68edcSjchu 		goto cb_done;
2160a3c68edcSjchu 	}
2161a3c68edcSjchu 
2162a3c68edcSjchu 	PX_INTR_DISABLE(pxp->px_dip, f_p->px_fh_sysino);
2163a3c68edcSjchu 
2164a3c68edcSjchu 	cb_p->cpuid = new_cpuid;
2165a3c68edcSjchu 	cb_p->sysino = f_p->px_fh_sysino;
2166a3c68edcSjchu 	PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid);
2167a3c68edcSjchu 
2168a3c68edcSjchu cb_done:
2169a3c68edcSjchu 	mutex_exit(&cb_p->cb_mutex);
2170a3c68edcSjchu }
2171a3c68edcSjchu 
217201689544Sjchu /*
217301689544Sjchu  * px_cb_add_intr() - Called from attach(9E) to create CB if not yet
217401689544Sjchu  * created, to add CB interrupt vector always, but enable only once.
217501689544Sjchu  */
217601689544Sjchu int
px_cb_add_intr(px_fault_t * fault_p)217701689544Sjchu px_cb_add_intr(px_fault_t *fault_p)
217801689544Sjchu {
217901689544Sjchu 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip);
218001689544Sjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
218125cf1a30Sjl 	px_cb_t		*cb_p = (px_cb_t *)px_get_cb(fault_p->px_fh_dip);
218201689544Sjchu 	px_cb_list_t	*pxl, *pxl_new;
2183a3c68edcSjchu 	boolean_t	is_proxy = B_FALSE;
218401689544Sjchu 
2185a3c68edcSjchu 	/* create cb */
218601689544Sjchu 	if (cb_p == NULL) {
218701689544Sjchu 		cb_p = kmem_zalloc(sizeof (px_cb_t), KM_SLEEP);
2188a3c68edcSjchu 
2189a3c68edcSjchu 		mutex_init(&cb_p->cb_mutex, NULL, MUTEX_DRIVER,
2190a3c68edcSjchu 		    (void *) ipltospl(FM_ERR_PIL));
2191a3c68edcSjchu 
219201689544Sjchu 		cb_p->px_cb_func = px_cb_intr;
219301689544Sjchu 		pxu_p->px_cb_p = cb_p;
219425cf1a30Sjl 		px_set_cb(fault_p->px_fh_dip, (uint64_t)cb_p);
219508a74c0dSschwartz 
219608a74c0dSschwartz 		/* px_lib_dev_init allows only FIRE and OBERON */
219708a74c0dSschwartz 		px_err_reg_enable(
219808a74c0dSschwartz 		    (pxu_p->chip_type == PX_CHIP_FIRE) ?
2199eae2e508Skrishnae 		    PX_ERR_JBC : PX_ERR_UBC,
220008a74c0dSschwartz 		    pxu_p->px_address[PX_REG_XBC]);
220101689544Sjchu 	} else
220201689544Sjchu 		pxu_p->px_cb_p = cb_p;
220301689544Sjchu 
2204a3c68edcSjchu 	/* register cb interrupt */
220501689544Sjchu 	VERIFY(add_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL,
2206b0fc0e77Sgovinda 	    (intrfunc)cb_p->px_cb_func, (caddr_t)cb_p, NULL, NULL) == 0);
220701689544Sjchu 
220801689544Sjchu 
2209a3c68edcSjchu 	/* update cb list */
2210a3c68edcSjchu 	mutex_enter(&cb_p->cb_mutex);
2211a3c68edcSjchu 	if (cb_p->pxl == NULL) {
2212a3c68edcSjchu 		is_proxy = B_TRUE;
221301689544Sjchu 		pxl = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP);
221401689544Sjchu 		pxl->pxp = px_p;
221501689544Sjchu 		cb_p->pxl = pxl;
221601689544Sjchu 		cb_p->sysino = fault_p->px_fh_sysino;
2217a3c68edcSjchu 		cb_p->cpuid = intr_dist_cpuid();
221801689544Sjchu 	} else {
221901689544Sjchu 		/*
222001689544Sjchu 		 * Find the last pxl or
2221a3c68edcSjchu 		 * stop short at encountering a redundent entry, or
222201689544Sjchu 		 * both.
222301689544Sjchu 		 */
222401689544Sjchu 		pxl = cb_p->pxl;
2225eae2e508Skrishnae 		for (; !(pxl->pxp == px_p) && pxl->next; pxl = pxl->next) {};
2226a3c68edcSjchu 		ASSERT(pxl->pxp != px_p);
222701689544Sjchu 
222801689544Sjchu 		/* add to linked list */
222901689544Sjchu 		pxl_new = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP);
223001689544Sjchu 		pxl_new->pxp = px_p;
223101689544Sjchu 		pxl->next = pxl_new;
223201689544Sjchu 	}
223301689544Sjchu 	cb_p->attachcnt++;
223401689544Sjchu 	mutex_exit(&cb_p->cb_mutex);
223501689544Sjchu 
2236a3c68edcSjchu 	if (is_proxy) {
2237a3c68edcSjchu 		/* add to interrupt redistribution list */
2238a3c68edcSjchu 		intr_dist_add(px_cb_intr_redist, cb_p);
2239a3c68edcSjchu 
2240a3c68edcSjchu 		/* enable cb hw interrupt */
2241a3c68edcSjchu 		px_ib_intr_enable(px_p, cb_p->cpuid, fault_p->px_intr_ino);
2242a3c68edcSjchu 	}
2243a3c68edcSjchu 
224401689544Sjchu 	return (DDI_SUCCESS);
224501689544Sjchu }
224601689544Sjchu 
224701689544Sjchu /*
224801689544Sjchu  * px_cb_rem_intr() - Called from detach(9E) to remove its CB
224901689544Sjchu  * interrupt vector, to shift proxy to the next available px,
225001689544Sjchu  * or disable CB interrupt when itself is the last.
225101689544Sjchu  */
225201689544Sjchu void
px_cb_rem_intr(px_fault_t * fault_p)225301689544Sjchu px_cb_rem_intr(px_fault_t *fault_p)
225401689544Sjchu {
225501689544Sjchu 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip), *pxp;
225601689544Sjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
225701689544Sjchu 	px_cb_t		*cb_p = PX2CB(px_p);
225801689544Sjchu 	px_cb_list_t	*pxl, *prev;
225901689544Sjchu 	px_fault_t	*f_p;
226001689544Sjchu 
226101689544Sjchu 	ASSERT(cb_p->pxl);
226201689544Sjchu 
2263a3c68edcSjchu 	/* find and remove this px, and update cb list */
226401689544Sjchu 	mutex_enter(&cb_p->cb_mutex);
226501689544Sjchu 
226601689544Sjchu 	pxl = cb_p->pxl;
226701689544Sjchu 	if (pxl->pxp == px_p) {
226801689544Sjchu 		cb_p->pxl = pxl->next;
226901689544Sjchu 	} else {
227001689544Sjchu 		prev = pxl;
227101689544Sjchu 		pxl = pxl->next;
2272eae2e508Skrishnae 		for (; pxl && (pxl->pxp != px_p); prev = pxl, pxl = pxl->next) {
2273eae2e508Skrishnae 		};
2274*e214b19eSToomas Soome 		if (pxl == NULL) {
227501689544Sjchu 			cmn_err(CE_WARN, "px_cb_rem_intr: can't find px_p 0x%p "
22767389e29fSjchu 			    "in registered CB list.", (void *)px_p);
2277a3c68edcSjchu 			mutex_exit(&cb_p->cb_mutex);
227801689544Sjchu 			return;
227901689544Sjchu 		}
228001689544Sjchu 		prev->next = pxl->next;
228101689544Sjchu 	}
2282a3c68edcSjchu 	pxu_p->px_cb_p = NULL;
2283a3c68edcSjchu 	cb_p->attachcnt--;
228401689544Sjchu 	kmem_free(pxl, sizeof (px_cb_list_t));
2285a3c68edcSjchu 	mutex_exit(&cb_p->cb_mutex);
228601689544Sjchu 
2287a3c68edcSjchu 	/* disable cb hw interrupt */
2288a3c68edcSjchu 	if (fault_p->px_fh_sysino == cb_p->sysino)
228901689544Sjchu 		px_ib_intr_disable(px_p->px_ib_p, fault_p->px_intr_ino,
229001689544Sjchu 		    IB_INTR_WAIT);
229101689544Sjchu 
2292a3c68edcSjchu 	/* if last px, remove from interrupt redistribution list */
2293a3c68edcSjchu 	if (cb_p->pxl == NULL)
2294a3c68edcSjchu 		intr_dist_rem(px_cb_intr_redist, cb_p);
2295a3c68edcSjchu 
2296a3c68edcSjchu 	/* de-register interrupt */
2297a3c68edcSjchu 	VERIFY(rem_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL) == 0);
2298a3c68edcSjchu 
2299a3c68edcSjchu 	/* if not last px, assign next px to manage cb */
2300a3c68edcSjchu 	mutex_enter(&cb_p->cb_mutex);
2301a3c68edcSjchu 	if (cb_p->pxl) {
2302a3c68edcSjchu 		if (fault_p->px_fh_sysino == cb_p->sysino) {
230301689544Sjchu 			pxp = cb_p->pxl->pxp;
230401689544Sjchu 			f_p = &pxp->px_cb_fault;
230501689544Sjchu 			cb_p->sysino = f_p->px_fh_sysino;
230601689544Sjchu 
230701689544Sjchu 			PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid);
23087389e29fSjchu 			(void) px_lib_intr_setstate(pxp->px_dip, cb_p->sysino,
230901689544Sjchu 			    INTR_IDLE_STATE);
231001689544Sjchu 		}
231101689544Sjchu 		mutex_exit(&cb_p->cb_mutex);
231201689544Sjchu 		return;
231301689544Sjchu 	}
2314a3c68edcSjchu 
2315a3c68edcSjchu 	/* clean up after the last px */
231601689544Sjchu 	mutex_exit(&cb_p->cb_mutex);
231701689544Sjchu 
231808a74c0dSschwartz 	/* px_lib_dev_init allows only FIRE and OBERON */
231908a74c0dSschwartz 	px_err_reg_disable(
232008a74c0dSschwartz 	    (pxu_p->chip_type == PX_CHIP_FIRE) ? PX_ERR_JBC : PX_ERR_UBC,
232108a74c0dSschwartz 	    pxu_p->px_address[PX_REG_XBC]);
232208a74c0dSschwartz 
232301689544Sjchu 	mutex_destroy(&cb_p->cb_mutex);
232425cf1a30Sjl 	px_set_cb(fault_p->px_fh_dip, 0ull);
232501689544Sjchu 	kmem_free(cb_p, sizeof (px_cb_t));
232601689544Sjchu }
232701689544Sjchu 
232801689544Sjchu /*
232901689544Sjchu  * px_cb_intr() - sun4u only,  CB interrupt dispatcher
233001689544Sjchu  */
233101689544Sjchu uint_t
px_cb_intr(caddr_t arg)233201689544Sjchu px_cb_intr(caddr_t arg)
233301689544Sjchu {
233401689544Sjchu 	px_cb_t		*cb_p = (px_cb_t *)arg;
2335a3c68edcSjchu 	px_t		*pxp;
2336a3c68edcSjchu 	px_fault_t	*f_p;
2337a3c68edcSjchu 	int		ret;
233868ac2337Sjl 
233901689544Sjchu 	mutex_enter(&cb_p->cb_mutex);
234001689544Sjchu 
2341*e214b19eSToomas Soome 	if (cb_p->pxl == NULL) {
234201689544Sjchu 		mutex_exit(&cb_p->cb_mutex);
2343a3c68edcSjchu 		return (DDI_INTR_UNCLAIMED);
234401689544Sjchu 	}
234501689544Sjchu 
2346a3c68edcSjchu 	pxp = cb_p->pxl->pxp;
2347a3c68edcSjchu 	f_p = &pxp->px_cb_fault;
2348a3c68edcSjchu 
2349a3c68edcSjchu 	ret = f_p->px_err_func((caddr_t)f_p);
235001689544Sjchu 
235101689544Sjchu 	mutex_exit(&cb_p->cb_mutex);
2352a3c68edcSjchu 	return (ret);
235301689544Sjchu }
235401689544Sjchu 
2355a3c68edcSjchu #ifdef	FMA
2356f8d2de6bSjchu void
px_fill_rc_status(px_fault_t * px_fault_p,pciex_rc_error_regs_t * rc_status)2357f8d2de6bSjchu px_fill_rc_status(px_fault_t *px_fault_p, pciex_rc_error_regs_t *rc_status)
2358f8d2de6bSjchu {
2359f8d2de6bSjchu 	/* populate the rc_status by reading the registers - TBD */
2360f8d2de6bSjchu }
2361f8d2de6bSjchu #endif /* FMA */
23628bc7d88aSet 
2363817a6df8Sjchu /*
2364817a6df8Sjchu  * cpr callback
2365817a6df8Sjchu  *
2366817a6df8Sjchu  * disable fabric error msg interrupt prior to suspending
2367817a6df8Sjchu  * all device drivers; re-enable fabric error msg interrupt
2368817a6df8Sjchu  * after all devices are resumed.
2369817a6df8Sjchu  */
2370817a6df8Sjchu static boolean_t
px_cpr_callb(void * arg,int code)2371817a6df8Sjchu px_cpr_callb(void *arg, int code)
2372817a6df8Sjchu {
2373817a6df8Sjchu 	px_t		*px_p = (px_t *)arg;
2374817a6df8Sjchu 	px_ib_t		*ib_p = px_p->px_ib_p;
2375817a6df8Sjchu 	px_pec_t	*pec_p = px_p->px_pec_p;
2376817a6df8Sjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
2377817a6df8Sjchu 	caddr_t		csr_base;
2378817a6df8Sjchu 	devino_t	ce_ino, nf_ino, f_ino;
2379b0fc0e77Sgovinda 	px_ino_t	*ce_ino_p, *nf_ino_p, *f_ino_p;
2380817a6df8Sjchu 	uint64_t	imu_log_enable, imu_intr_enable;
2381817a6df8Sjchu 	uint64_t	imu_log_mask, imu_intr_mask;
2382817a6df8Sjchu 
2383817a6df8Sjchu 	ce_ino = px_msiqid_to_devino(px_p, pec_p->pec_corr_msg_msiq_id);
2384817a6df8Sjchu 	nf_ino = px_msiqid_to_devino(px_p, pec_p->pec_non_fatal_msg_msiq_id);
2385817a6df8Sjchu 	f_ino = px_msiqid_to_devino(px_p, pec_p->pec_fatal_msg_msiq_id);
2386817a6df8Sjchu 	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
2387817a6df8Sjchu 
2388817a6df8Sjchu 	imu_log_enable = CSR_XR(csr_base, IMU_ERROR_LOG_ENABLE);
2389817a6df8Sjchu 	imu_intr_enable = CSR_XR(csr_base, IMU_INTERRUPT_ENABLE);
2390817a6df8Sjchu 
2391817a6df8Sjchu 	imu_log_mask = BITMASK(IMU_ERROR_LOG_ENABLE_FATAL_MES_NOT_EN_LOG_EN) |
2392817a6df8Sjchu 	    BITMASK(IMU_ERROR_LOG_ENABLE_NONFATAL_MES_NOT_EN_LOG_EN) |
2393817a6df8Sjchu 	    BITMASK(IMU_ERROR_LOG_ENABLE_COR_MES_NOT_EN_LOG_EN);
2394817a6df8Sjchu 
2395817a6df8Sjchu 	imu_intr_mask =
2396817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_S_INT_EN) |
2397817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_S_INT_EN) |
2398817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_S_INT_EN) |
2399817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_P_INT_EN) |
2400817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_P_INT_EN) |
2401817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_P_INT_EN);
2402817a6df8Sjchu 
2403817a6df8Sjchu 	switch (code) {
2404817a6df8Sjchu 	case CB_CODE_CPR_CHKPT:
2405817a6df8Sjchu 		/* disable imu rbne on corr/nonfatal/fatal errors */
2406817a6df8Sjchu 		CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE,
2407817a6df8Sjchu 		    imu_log_enable & (~imu_log_mask));
2408817a6df8Sjchu 
2409817a6df8Sjchu 		CSR_XS(csr_base, IMU_INTERRUPT_ENABLE,
2410817a6df8Sjchu 		    imu_intr_enable & (~imu_intr_mask));
2411817a6df8Sjchu 
2412817a6df8Sjchu 		/* disable CORR intr mapping */
2413817a6df8Sjchu 		px_ib_intr_disable(ib_p, ce_ino, IB_INTR_NOWAIT);
2414817a6df8Sjchu 
2415817a6df8Sjchu 		/* disable NON FATAL intr mapping */
2416817a6df8Sjchu 		px_ib_intr_disable(ib_p, nf_ino, IB_INTR_NOWAIT);
2417817a6df8Sjchu 
2418817a6df8Sjchu 		/* disable FATAL intr mapping */
2419817a6df8Sjchu 		px_ib_intr_disable(ib_p, f_ino, IB_INTR_NOWAIT);
2420817a6df8Sjchu 
2421817a6df8Sjchu 		break;
2422817a6df8Sjchu 
2423817a6df8Sjchu 	case CB_CODE_CPR_RESUME:
2424bf8fc234Set 		pxu_p->cpr_flag = PX_NOT_CPR;
2425817a6df8Sjchu 		mutex_enter(&ib_p->ib_ino_lst_mutex);
2426817a6df8Sjchu 
2427817a6df8Sjchu 		ce_ino_p = px_ib_locate_ino(ib_p, ce_ino);
2428817a6df8Sjchu 		nf_ino_p = px_ib_locate_ino(ib_p, nf_ino);
2429817a6df8Sjchu 		f_ino_p = px_ib_locate_ino(ib_p, f_ino);
2430817a6df8Sjchu 
2431817a6df8Sjchu 		/* enable CORR intr mapping */
2432817a6df8Sjchu 		if (ce_ino_p)
2433817a6df8Sjchu 			px_ib_intr_enable(px_p, ce_ino_p->ino_cpuid, ce_ino);
2434817a6df8Sjchu 		else
2435817a6df8Sjchu 			cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to "
2436817a6df8Sjchu 			    "reenable PCIe Correctable msg intr.\n");
2437817a6df8Sjchu 
2438817a6df8Sjchu 		/* enable NON FATAL intr mapping */
2439817a6df8Sjchu 		if (nf_ino_p)
2440817a6df8Sjchu 			px_ib_intr_enable(px_p, nf_ino_p->ino_cpuid, nf_ino);
2441817a6df8Sjchu 		else
2442817a6df8Sjchu 			cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to "
2443817a6df8Sjchu 			    "reenable PCIe Non Fatal msg intr.\n");
2444817a6df8Sjchu 
2445817a6df8Sjchu 		/* enable FATAL intr mapping */
2446817a6df8Sjchu 		if (f_ino_p)
2447817a6df8Sjchu 			px_ib_intr_enable(px_p, f_ino_p->ino_cpuid, f_ino);
2448817a6df8Sjchu 		else
2449817a6df8Sjchu 			cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to "
2450817a6df8Sjchu 			    "reenable PCIe Fatal msg intr.\n");
2451817a6df8Sjchu 
2452817a6df8Sjchu 		mutex_exit(&ib_p->ib_ino_lst_mutex);
2453817a6df8Sjchu 
2454817a6df8Sjchu 		/* enable corr/nonfatal/fatal not enable error */
2455817a6df8Sjchu 		CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE, (imu_log_enable |
2456817a6df8Sjchu 		    (imu_log_mask & px_imu_log_mask)));
2457817a6df8Sjchu 		CSR_XS(csr_base, IMU_INTERRUPT_ENABLE, (imu_intr_enable |
2458817a6df8Sjchu 		    (imu_intr_mask & px_imu_intr_mask)));
2459817a6df8Sjchu 
2460817a6df8Sjchu 		break;
2461817a6df8Sjchu 	}
2462817a6df8Sjchu 
2463817a6df8Sjchu 	return (B_TRUE);
2464817a6df8Sjchu }
2465817a6df8Sjchu 
246625cf1a30Sjl uint64_t
px_get_rng_parent_hi_mask(px_t * px_p)2467d3533785Sschwartz px_get_rng_parent_hi_mask(px_t *px_p)
246825cf1a30Sjl {
246925cf1a30Sjl 	pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p;
2470d3533785Sschwartz 	uint64_t mask;
247125cf1a30Sjl 
247225cf1a30Sjl 	switch (PX_CHIP_TYPE(pxu_p)) {
247325cf1a30Sjl 	case PX_CHIP_OBERON:
247425cf1a30Sjl 		mask = OBERON_RANGE_PROP_MASK;
247525cf1a30Sjl 		break;
247625cf1a30Sjl 	case PX_CHIP_FIRE:
2477d3533785Sschwartz 		mask = PX_RANGE_PROP_MASK;
247825cf1a30Sjl 		break;
247925cf1a30Sjl 	default:
2480d3533785Sschwartz 		mask = PX_RANGE_PROP_MASK;
248125cf1a30Sjl 	}
2482d3533785Sschwartz 
2483d3533785Sschwartz 	return (mask);
2484d3533785Sschwartz }
2485d3533785Sschwartz 
2486d3533785Sschwartz /*
2487d3533785Sschwartz  * fetch chip's range propery's value
2488d3533785Sschwartz  */
2489d3533785Sschwartz uint64_t
px_get_range_prop(px_t * px_p,pci_ranges_t * rp,int bank)249026947304SEvan Yan px_get_range_prop(px_t *px_p, pci_ranges_t *rp, int bank)
2491d3533785Sschwartz {
2492d3533785Sschwartz 	uint64_t mask, range_prop;
2493d3533785Sschwartz 
2494d3533785Sschwartz 	mask = px_get_rng_parent_hi_mask(px_p);
249525cf1a30Sjl 	range_prop = (((uint64_t)(rp[bank].parent_high & mask)) << 32) |
2496eae2e508Skrishnae 	    rp[bank].parent_low;
249725cf1a30Sjl 
249825cf1a30Sjl 	return (range_prop);
249925cf1a30Sjl }
250025cf1a30Sjl 
2501c0da6274SZhi-Jun Robin Fu /*
2502c0da6274SZhi-Jun Robin Fu  * fetch the config space base addr of the root complex
2503c0da6274SZhi-Jun Robin Fu  * note this depends on px structure being initialized
2504c0da6274SZhi-Jun Robin Fu  */
2505c0da6274SZhi-Jun Robin Fu uint64_t
px_lib_get_cfgacc_base(dev_info_t * dip)2506c0da6274SZhi-Jun Robin Fu px_lib_get_cfgacc_base(dev_info_t *dip)
2507c0da6274SZhi-Jun Robin Fu {
2508c0da6274SZhi-Jun Robin Fu 	int		instance = DIP_TO_INST(dip);
2509c0da6274SZhi-Jun Robin Fu 	px_t		*px_p = INST_TO_STATE(instance);
2510c0da6274SZhi-Jun Robin Fu 	pci_ranges_t	*rp = px_p->px_ranges_p;
2511c0da6274SZhi-Jun Robin Fu 	int		bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
2512c0da6274SZhi-Jun Robin Fu 
2513c0da6274SZhi-Jun Robin Fu 	/* Get Fire's Physical Base Address */
2514c0da6274SZhi-Jun Robin Fu 	return (px_get_range_prop(px_p, rp, bank));
2515c0da6274SZhi-Jun Robin Fu }
2516c0da6274SZhi-Jun Robin Fu 
2517817a6df8Sjchu /*
2518817a6df8Sjchu  * add cpr callback
2519817a6df8Sjchu  */
2520817a6df8Sjchu void
px_cpr_add_callb(px_t * px_p)2521817a6df8Sjchu px_cpr_add_callb(px_t *px_p)
2522817a6df8Sjchu {
2523817a6df8Sjchu 	px_p->px_cprcb_id = callb_add(px_cpr_callb, (void *)px_p,
2524eae2e508Skrishnae 	    CB_CL_CPR_POST_USER, "px_cpr");
2525817a6df8Sjchu }
2526817a6df8Sjchu 
2527817a6df8Sjchu /*
2528817a6df8Sjchu  * remove cpr callback
2529817a6df8Sjchu  */
2530817a6df8Sjchu void
px_cpr_rem_callb(px_t * px_p)2531817a6df8Sjchu px_cpr_rem_callb(px_t *px_p)
2532817a6df8Sjchu {
2533817a6df8Sjchu 	(void) callb_delete(px_p->px_cprcb_id);
2534817a6df8Sjchu }
2535b65731f1Skini 
2536b65731f1Skini /*ARGSUSED*/
253725cf1a30Sjl static uint_t
px_hp_intr(caddr_t arg1,caddr_t arg2)253825cf1a30Sjl px_hp_intr(caddr_t arg1, caddr_t arg2)
253925cf1a30Sjl {
254026947304SEvan Yan 	px_t		*px_p = (px_t *)arg1;
254126947304SEvan Yan 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
254226947304SEvan Yan 	int		rval;
254325cf1a30Sjl 
254426947304SEvan Yan 	rval = pcie_intr(px_p->px_dip);
254525cf1a30Sjl 
254625cf1a30Sjl #ifdef  DEBUG
254725cf1a30Sjl 	if (rval == DDI_INTR_UNCLAIMED)
2548eae2e508Skrishnae 		cmn_err(CE_WARN, "%s%d: UNCLAIMED intr\n",
2549eae2e508Skrishnae 		    ddi_driver_name(px_p->px_dip),
2550eae2e508Skrishnae 		    ddi_get_instance(px_p->px_dip));
255125cf1a30Sjl #endif
255225cf1a30Sjl 
25530d5b93d9Sgovinda 	/* Set the interrupt state to idle */
25540d5b93d9Sgovinda 	if (px_lib_intr_setstate(px_p->px_dip,
25550d5b93d9Sgovinda 	    pxu_p->hp_sysino, INTR_IDLE_STATE) != DDI_SUCCESS)
25560d5b93d9Sgovinda 		return (DDI_INTR_UNCLAIMED);
25570d5b93d9Sgovinda 
255825cf1a30Sjl 	return (rval);
255925cf1a30Sjl }
256025cf1a30Sjl 
2561b65731f1Skini int
px_lib_hotplug_init(dev_info_t * dip,void * arg)2562b65731f1Skini px_lib_hotplug_init(dev_info_t *dip, void *arg)
2563b65731f1Skini {
256425cf1a30Sjl 	px_t	*px_p = DIP_TO_STATE(dip);
25650d5b93d9Sgovinda 	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
256625cf1a30Sjl 	uint64_t ret;
256725cf1a30Sjl 
256826947304SEvan Yan 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
256926947304SEvan Yan 	    "hotplug-capable") == 0)
257026947304SEvan Yan 		return (DDI_FAILURE);
257126947304SEvan Yan 
257225cf1a30Sjl 	if ((ret = hvio_hotplug_init(dip, arg)) == DDI_SUCCESS) {
257325cf1a30Sjl 		if (px_lib_intr_devino_to_sysino(px_p->px_dip,
25740d5b93d9Sgovinda 		    px_p->px_inos[PX_INTR_HOTPLUG], &pxu_p->hp_sysino) !=
257525cf1a30Sjl 		    DDI_SUCCESS) {
257625cf1a30Sjl #ifdef	DEBUG
257725cf1a30Sjl 			cmn_err(CE_WARN, "%s%d: devino_to_sysino fails\n",
257825cf1a30Sjl 			    ddi_driver_name(px_p->px_dip),
257925cf1a30Sjl 			    ddi_get_instance(px_p->px_dip));
258025cf1a30Sjl #endif
258125cf1a30Sjl 			return (DDI_FAILURE);
258225cf1a30Sjl 		}
258325cf1a30Sjl 
258426947304SEvan Yan 		VERIFY(add_ivintr(pxu_p->hp_sysino, PCIE_INTR_PRI,
2585b0fc0e77Sgovinda 		    (intrfunc)px_hp_intr, (caddr_t)px_p, NULL, NULL) == 0);
2586ab4471cdSscarter 
2587ab4471cdSscarter 		px_ib_intr_enable(px_p, intr_dist_cpuid(),
2588ab4471cdSscarter 		    px_p->px_inos[PX_INTR_HOTPLUG]);
258925cf1a30Sjl 	}
259025cf1a30Sjl 
259125cf1a30Sjl 	return (ret);
2592b65731f1Skini }
2593b65731f1Skini 
2594b65731f1Skini void
px_lib_hotplug_uninit(dev_info_t * dip)2595b65731f1Skini px_lib_hotplug_uninit(dev_info_t *dip)
2596b65731f1Skini {
259725cf1a30Sjl 	if (hvio_hotplug_uninit(dip) == DDI_SUCCESS) {
259825cf1a30Sjl 		px_t	*px_p = DIP_TO_STATE(dip);
25990d5b93d9Sgovinda 		pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
260025cf1a30Sjl 
2601ab4471cdSscarter 		px_ib_intr_disable(px_p->px_ib_p,
2602ab4471cdSscarter 		    px_p->px_inos[PX_INTR_HOTPLUG], IB_INTR_WAIT);
2603ab4471cdSscarter 
260426947304SEvan Yan 		VERIFY(rem_ivintr(pxu_p->hp_sysino, PCIE_INTR_PRI) == 0);
260525cf1a30Sjl 	}
2606b65731f1Skini }
2607d60bae31Sdwoods 
2608ab4471cdSscarter /*
2609ab4471cdSscarter  * px_hp_intr_redist() - sun4u only, HP interrupt redistribution
2610ab4471cdSscarter  */
2611ab4471cdSscarter void
px_hp_intr_redist(px_t * px_p)2612ab4471cdSscarter px_hp_intr_redist(px_t *px_p)
2613ab4471cdSscarter {
261426947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(px_p->px_dip);
261526947304SEvan Yan 
261626947304SEvan Yan 	if (px_p && PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
2617ab4471cdSscarter 		px_ib_intr_dist_en(px_p->px_dip, intr_dist_cpuid(),
2618ab4471cdSscarter 		    px_p->px_inos[PX_INTR_HOTPLUG], B_FALSE);
2619ab4471cdSscarter 	}
2620ab4471cdSscarter }
2621ab4471cdSscarter 
2622d60bae31Sdwoods boolean_t
px_lib_is_in_drain_state(px_t * px_p)2623d60bae31Sdwoods px_lib_is_in_drain_state(px_t *px_p)
2624d60bae31Sdwoods {
2625d60bae31Sdwoods 	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
2626d60bae31Sdwoods 	caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
2627d60bae31Sdwoods 	uint64_t drain_status;
2628d60bae31Sdwoods 
2629d60bae31Sdwoods 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) {
2630d60bae31Sdwoods 		drain_status = CSR_BR(csr_base, DRAIN_CONTROL_STATUS, DRAIN);
2631d60bae31Sdwoods 	} else {
2632d60bae31Sdwoods 		drain_status = CSR_BR(csr_base, TLU_STATUS, DRAIN);
2633d60bae31Sdwoods 	}
2634d60bae31Sdwoods 
2635d60bae31Sdwoods 	return (drain_status);
2636d60bae31Sdwoods }
26377ea9b230Set 
26387ea9b230Set pcie_req_id_t
px_lib_get_bdf(px_t * px_p)26397ea9b230Set px_lib_get_bdf(px_t *px_p)
26407ea9b230Set {
26417ea9b230Set 	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
26427ea9b230Set 	caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
26437ea9b230Set 	pcie_req_id_t bdf;
26447ea9b230Set 
26457ea9b230Set 	bdf = CSR_BR(csr_base, DMC_PCI_EXPRESS_CONFIGURATION, REQ_ID);
26467ea9b230Set 
26477ea9b230Set 	return (bdf);
26487ea9b230Set }
26490114761dSAlan Adamson, SD OSSD 
26500114761dSAlan Adamson, SD OSSD /*ARGSUSED*/
26510114761dSAlan Adamson, SD OSSD int
px_lib_get_root_complex_mps(px_t * px_p,dev_info_t * dip,int * mps)26520114761dSAlan Adamson, SD OSSD px_lib_get_root_complex_mps(px_t *px_p, dev_info_t *dip, int *mps)
26530114761dSAlan Adamson, SD OSSD {
26540114761dSAlan Adamson, SD OSSD 	pxu_t	*pxu_p;
26550114761dSAlan Adamson, SD OSSD 	caddr_t csr_base;
26560114761dSAlan Adamson, SD OSSD 
26570114761dSAlan Adamson, SD OSSD 	pxu_p = (pxu_t *)px_p->px_plat_p;
26580114761dSAlan Adamson, SD OSSD 
26590114761dSAlan Adamson, SD OSSD 	if (pxu_p == NULL)
26600114761dSAlan Adamson, SD OSSD 		return (DDI_FAILURE);
26610114761dSAlan Adamson, SD OSSD 
26620114761dSAlan Adamson, SD OSSD 	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
26630114761dSAlan Adamson, SD OSSD 
26640114761dSAlan Adamson, SD OSSD 
26650114761dSAlan Adamson, SD OSSD 	*mps = CSR_XR(csr_base, TLU_DEVICE_CAPABILITIES) &
26660114761dSAlan Adamson, SD OSSD 	    TLU_DEVICE_CAPABILITIES_MPS_MASK;
26670114761dSAlan Adamson, SD OSSD 
26680114761dSAlan Adamson, SD OSSD 	return (DDI_SUCCESS);
26690114761dSAlan Adamson, SD OSSD }
26700114761dSAlan Adamson, SD OSSD 
26710114761dSAlan Adamson, SD OSSD /*ARGSUSED*/
26720114761dSAlan Adamson, SD OSSD int
px_lib_set_root_complex_mps(px_t * px_p,dev_info_t * dip,int mps)26730114761dSAlan Adamson, SD OSSD px_lib_set_root_complex_mps(px_t *px_p,  dev_info_t *dip, int mps)
26740114761dSAlan Adamson, SD OSSD {
26750114761dSAlan Adamson, SD OSSD 	pxu_t	*pxu_p;
26760114761dSAlan Adamson, SD OSSD 	caddr_t csr_base;
26770114761dSAlan Adamson, SD OSSD 	uint64_t dev_ctrl;
26780114761dSAlan Adamson, SD OSSD 	int link_width, val;
26790114761dSAlan Adamson, SD OSSD 	px_chip_type_t chip_type = px_identity_init(px_p);
26800114761dSAlan Adamson, SD OSSD 
26810114761dSAlan Adamson, SD OSSD 	pxu_p = (pxu_t *)px_p->px_plat_p;
26820114761dSAlan Adamson, SD OSSD 
26830114761dSAlan Adamson, SD OSSD 	if (pxu_p == NULL)
26840114761dSAlan Adamson, SD OSSD 		return (DDI_FAILURE);
26850114761dSAlan Adamson, SD OSSD 
26860114761dSAlan Adamson, SD OSSD 	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
26870114761dSAlan Adamson, SD OSSD 
26880114761dSAlan Adamson, SD OSSD 	dev_ctrl = CSR_XR(csr_base, TLU_DEVICE_CONTROL);
26890114761dSAlan Adamson, SD OSSD 	dev_ctrl |= (mps << TLU_DEVICE_CONTROL_MPS);
26900114761dSAlan Adamson, SD OSSD 
26910114761dSAlan Adamson, SD OSSD 	CSR_XS(csr_base, TLU_DEVICE_CONTROL, dev_ctrl);
26920114761dSAlan Adamson, SD OSSD 
26930114761dSAlan Adamson, SD OSSD 	link_width = CSR_FR(csr_base, TLU_LINK_STATUS, WIDTH);
26940114761dSAlan Adamson, SD OSSD 
26950114761dSAlan Adamson, SD OSSD 	/*
26960114761dSAlan Adamson, SD OSSD 	 * Convert link_width to match timer array configuration.
26970114761dSAlan Adamson, SD OSSD 	 */
26980114761dSAlan Adamson, SD OSSD 	switch (link_width) {
26990114761dSAlan Adamson, SD OSSD 	case 1:
27000114761dSAlan Adamson, SD OSSD 		link_width = 0;
27010114761dSAlan Adamson, SD OSSD 		break;
27020114761dSAlan Adamson, SD OSSD 	case 4:
27030114761dSAlan Adamson, SD OSSD 		link_width = 1;
27040114761dSAlan Adamson, SD OSSD 		break;
27050114761dSAlan Adamson, SD OSSD 	case 8:
27060114761dSAlan Adamson, SD OSSD 		link_width = 2;
27070114761dSAlan Adamson, SD OSSD 		break;
27080114761dSAlan Adamson, SD OSSD 	case 16:
27090114761dSAlan Adamson, SD OSSD 		link_width = 3;
27100114761dSAlan Adamson, SD OSSD 		break;
27110114761dSAlan Adamson, SD OSSD 	default:
27120114761dSAlan Adamson, SD OSSD 		link_width = 0;
27130114761dSAlan Adamson, SD OSSD 	}
27140114761dSAlan Adamson, SD OSSD 
27150114761dSAlan Adamson, SD OSSD 	val = px_replay_timer_table[mps][link_width];
27160114761dSAlan Adamson, SD OSSD 	CSR_XS(csr_base, LPU_TXLINK_REPLAY_TIMER_THRESHOLD, val);
27170114761dSAlan Adamson, SD OSSD 
27180114761dSAlan Adamson, SD OSSD 	if (chip_type == PX_CHIP_OBERON)
27190114761dSAlan Adamson, SD OSSD 		return (DDI_SUCCESS);
27200114761dSAlan Adamson, SD OSSD 
27210114761dSAlan Adamson, SD OSSD 	val = px_acknak_timer_table[mps][link_width];
27220114761dSAlan Adamson, SD OSSD 	CSR_XS(csr_base, LPU_TXLINK_FREQUENT_NAK_LATENCY_TIMER_THRESHOLD, val);
27230114761dSAlan Adamson, SD OSSD 
27240114761dSAlan Adamson, SD OSSD 	return (DDI_SUCCESS);
27250114761dSAlan Adamson, SD OSSD }
2726fc256490SJason Beloro 
2727fc256490SJason Beloro /*ARGSUSED*/
2728fc256490SJason Beloro int
px_lib_fabric_sync(dev_info_t * dip)2729fc256490SJason Beloro px_lib_fabric_sync(dev_info_t *dip)
2730fc256490SJason Beloro {
2731fc256490SJason Beloro 	/* an no-op on sun4u platform */
2732fc256490SJason Beloro 	return (DDI_SUCCESS);
2733fc256490SJason Beloro }
2734