xref: /titanic_51/usr/src/uts/sun4u/io/px/px_lib4u.c (revision 89b42a211fa7d3527b9615260f495d22e430c5c5)
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 /*
22*89b42a21Sandrew.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>
418bc7d88aSet142600 #include <sys/byteorder.h>
42a3c68edcSjchu #include <sys/spl.h>
437c478bd9Sstevel@tonic-gate #include <px_obj.h>
44d4bc0535SKrishna Elango #include <sys/pcie_pwr.h>
4525cf1a30Sjl139090 #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"
5125cf1a30Sjl139090 #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;
6025cf1a30Sjl139090 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 
70f8d2de6bSjchu /*
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 };
950114761dSAlan Adamson, SD OSSD /*
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
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",
112f8d2de6bSjchu 	    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
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
1797c478bd9Sstevel@tonic-gate px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl)
1807c478bd9Sstevel@tonic-gate {
18108a74c0dSschwartz 
182f8d2de6bSjchu 	caddr_t			xbc_csr_base, csr_base;
1837c478bd9Sstevel@tonic-gate 	px_dvma_range_prop_t	px_dvma_range;
1847c478bd9Sstevel@tonic-gate 	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 
22425cf1a30Sjl139090 	pxu_p->tsb_paddr = va_to_pa(pxu_p->tsb_vaddr);
22525cf1a30Sjl139090 
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 	 */
25125cf1a30Sjl139090 	switch (PX_CHIP_TYPE(pxu_p)) {
25225cf1a30Sjl139090 	case PX_CHIP_OBERON:
253597077b2Sjj156685 		/*
254597077b2Sjj156685 		 * Oberon hotplug uses SPARE3 field in ILU Error Log Enable
255597077b2Sjj156685 		 * register to indicate the status of leaf reset,
256597077b2Sjj156685 		 * we need to preserve the value of this bit, and keep it in
257597077b2Sjj156685 		 * px_ilu_log_mask to reflect the state of the bit
258597077b2Sjj156685 		 */
259597077b2Sjj156685 		if (CSR_BR(csr_base, ILU_ERROR_LOG_ENABLE, SPARE3))
260597077b2Sjj156685 			px_ilu_log_mask |= (1ull <<
261597077b2Sjj156685 			    ILU_ERROR_LOG_ENABLE_SPARE3);
262597077b2Sjj156685 		else
263597077b2Sjj156685 			px_ilu_log_mask &= ~(1ull <<
264597077b2Sjj156685 			    ILU_ERROR_LOG_ENABLE_SPARE3);
26525cf1a30Sjl139090 
26608a74c0dSschwartz 		px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE);
26725cf1a30Sjl139090 		break;
26825cf1a30Sjl139090 
26925cf1a30Sjl139090 	case PX_CHIP_FIRE:
27008a74c0dSschwartz 		px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE);
27125cf1a30Sjl139090 		break;
27208a74c0dSschwartz 
27325cf1a30Sjl139090 	default:
27425cf1a30Sjl139090 		cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n",
27525cf1a30Sjl139090 		    ddi_driver_name(dip), ddi_get_instance(dip));
27625cf1a30Sjl139090 		return (DDI_FAILURE);
27725cf1a30Sjl139090 	}
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
2917c478bd9Sstevel@tonic-gate px_lib_dev_fini(dev_info_t *dip)
2927c478bd9Sstevel@tonic-gate {
29308a74c0dSschwartz 	caddr_t			csr_base;
29408a74c0dSschwartz 	uint8_t			chip_mask;
2957c478bd9Sstevel@tonic-gate 	px_t			*px_p = DIP_TO_STATE(dip);
2967c478bd9Sstevel@tonic-gate 	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 	 */
30325cf1a30Sjl139090 	switch (PX_CHIP_TYPE(pxu_p)) {
30425cf1a30Sjl139090 	case PX_CHIP_OBERON:
30525cf1a30Sjl139090 	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);
30925cf1a30Sjl139090 		break;
31008a74c0dSschwartz 
31125cf1a30Sjl139090 	default:
31225cf1a30Sjl139090 		cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n",
31325cf1a30Sjl139090 		    ddi_driver_name(dip), ddi_get_instance(dip));
31425cf1a30Sjl139090 		return (DDI_FAILURE);
31525cf1a30Sjl139090 	}
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
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
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
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
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
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
4407c478bd9Sstevel@tonic-gate px_lib_intr_gettarget(dev_info_t *dip, sysino_t sysino, cpuid_t *cpuid)
4417c478bd9Sstevel@tonic-gate {
44225cf1a30Sjl139090 	px_t		*px_p = DIP_TO_STATE(dip);
44325cf1a30Sjl139090 	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 
44925cf1a30Sjl139090 	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
4637c478bd9Sstevel@tonic-gate px_lib_intr_settarget(dev_info_t *dip, sysino_t sysino, cpuid_t cpuid)
4647c478bd9Sstevel@tonic-gate {
46525cf1a30Sjl139090 	px_t		*px_p = DIP_TO_STATE(dip);
46625cf1a30Sjl139090 	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 
47225cf1a30Sjl139090 	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
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
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
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
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 
576*89b42a21Sandrew.rutz@sun.com int
577*89b42a21Sandrew.rutz@sun.com px_lib_iommu_detach(px_t *px_p)
578*89b42a21Sandrew.rutz@sun.com {
579*89b42a21Sandrew.rutz@sun.com 	/*
580*89b42a21Sandrew.rutz@sun.com 	 * Deallocate DVMA addr space that was reserved for OBP TTE's
581*89b42a21Sandrew.rutz@sun.com 	 * during Attach.
582*89b42a21Sandrew.rutz@sun.com 	 */
583*89b42a21Sandrew.rutz@sun.com 	hvio_obptsb_detach(px_p);
584*89b42a21Sandrew.rutz@sun.com 
585*89b42a21Sandrew.rutz@sun.com 	return (DDI_SUCCESS);
586*89b42a21Sandrew.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
59525cf1a30Sjl139090 px_lib_dma_bypass_rngchk(dev_info_t *dip, ddi_dma_attr_t *attr_p,
59625cf1a30Sjl139090     uint64_t *lo_p, uint64_t *hi_p)
5977c478bd9Sstevel@tonic-gate {
59825cf1a30Sjl139090 	px_t	*px_p = DIP_TO_STATE(dip);
59925cf1a30Sjl139090 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
60025cf1a30Sjl139090 
60125cf1a30Sjl139090 	*lo_p = hvio_get_bypass_base(pxu_p);
60225cf1a30Sjl139090 	*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
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;
61425cf1a30Sjl139090 	px_t	*px_p = DIP_TO_STATE(dip);
61525cf1a30Sjl139090 	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 
62025cf1a30Sjl139090 	if ((ret = hvio_iommu_getbypass(DIP_TO_HANDLE(dip), pxu_p, ra,
62125cf1a30Sjl139090 	    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 
6337c478bd9Sstevel@tonic-gate /*
634a616a11eSLida.Horn  * Returns any needed IO address bit(s) for relaxed ordering in IOMMU
635a616a11eSLida.Horn  * bypass mode.
636a616a11eSLida.Horn  */
637a616a11eSLida.Horn uint64_t
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 
649a616a11eSLida.Horn /*
6507c478bd9Sstevel@tonic-gate  * bus dma sync entry point.
6517c478bd9Sstevel@tonic-gate  */
6527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6537c478bd9Sstevel@tonic-gate int
6547c478bd9Sstevel@tonic-gate px_lib_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
6557c478bd9Sstevel@tonic-gate     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;
65825cf1a30Sjl139090 	px_t	*px_p = DIP_TO_STATE(dip);
65925cf1a30Sjl139090 	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 
6657c478bd9Sstevel@tonic-gate 	/*
66625cf1a30Sjl139090 	 * No flush needed for Oberon
66725cf1a30Sjl139090 	 */
66825cf1a30Sjl139090 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON)
66925cf1a30Sjl139090 		return (DDI_SUCCESS);
67025cf1a30Sjl139090 
67125cf1a30Sjl139090 	/*
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 #if !defined(lint)
7027c478bd9Sstevel@tonic-gate 	kpreempt_disable();
7037c478bd9Sstevel@tonic-gate #endif
7047c478bd9Sstevel@tonic-gate 	jbus_stst_order();
7057c478bd9Sstevel@tonic-gate #if !defined(lint)
7067c478bd9Sstevel@tonic-gate 	kpreempt_enable();
7077c478bd9Sstevel@tonic-gate #endif
7087c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate /*
7127c478bd9Sstevel@tonic-gate  * MSIQ Functions:
7137c478bd9Sstevel@tonic-gate  */
7147c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7157c478bd9Sstevel@tonic-gate int
7167c478bd9Sstevel@tonic-gate px_lib_msiq_init(dev_info_t *dip)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
7197c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
7207c478bd9Sstevel@tonic-gate 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
7217c478bd9Sstevel@tonic-gate 	px_dvma_addr_t	pg_index;
722348fdf9eSAlan Adamson, SD OSSD 	size_t		q_sz = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
7237c478bd9Sstevel@tonic-gate 	size_t		size;
724348fdf9eSAlan Adamson, SD OSSD 	int		i, ret;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_init: dip 0x%p\n", dip);
7277c478bd9Sstevel@tonic-gate 
728348fdf9eSAlan Adamson, SD OSSD 	/* must aligned on q_sz (happens to be !!! page) boundary */
729348fdf9eSAlan Adamson, SD OSSD 	ASSERT(q_sz == 8 * 1024);
730348fdf9eSAlan Adamson, SD OSSD 
7317c478bd9Sstevel@tonic-gate 	/*
7327c478bd9Sstevel@tonic-gate 	 * Map the EQ memory into the Fire MMU (has to be 512KB aligned)
7337c478bd9Sstevel@tonic-gate 	 * and then initialize the base address register.
7347c478bd9Sstevel@tonic-gate 	 *
7357c478bd9Sstevel@tonic-gate 	 * Allocate entries from Fire IOMMU so that the resulting address
7367c478bd9Sstevel@tonic-gate 	 * is properly aligned.  Calculate the index of the first allocated
7377c478bd9Sstevel@tonic-gate 	 * entry.  Note: The size of the mapping is assumed to be a multiple
7387c478bd9Sstevel@tonic-gate 	 * of the page size.
7397c478bd9Sstevel@tonic-gate 	 */
740348fdf9eSAlan Adamson, SD OSSD 	size = msiq_state_p->msiq_cnt * q_sz;
741348fdf9eSAlan Adamson, SD OSSD 
742348fdf9eSAlan Adamson, SD OSSD 	msiq_state_p->msiq_buf_p = kmem_zalloc(size, KM_SLEEP);
743348fdf9eSAlan Adamson, SD OSSD 
744348fdf9eSAlan Adamson, SD OSSD 	for (i = 0; i < msiq_state_p->msiq_cnt; i++)
745348fdf9eSAlan Adamson, SD OSSD 		msiq_state_p->msiq_p[i].msiq_base_p = (msiqhead_t *)
746348fdf9eSAlan Adamson, SD OSSD 		    ((caddr_t)msiq_state_p->msiq_buf_p + (i * q_sz));
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	pxu_p->msiq_mapped_p = vmem_xalloc(px_p->px_mmu_p->mmu_dvma_map,
7497c478bd9Sstevel@tonic-gate 	    size, (512 * 1024), 0, 0, NULL, NULL, VM_NOSLEEP | VM_BESTFIT);
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	if (pxu_p->msiq_mapped_p == NULL)
7527c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p,
7557c478bd9Sstevel@tonic-gate 	    MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p));
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if ((ret = px_lib_iommu_map(px_p->px_dip, PCI_TSBID(0, pg_index),
75895003185Segillett 	    MMU_BTOP(size), PCI_MAP_ATTR_WRITE, msiq_state_p->msiq_buf_p,
75995003185Segillett 	    0, MMU_MAP_BUF)) != DDI_SUCCESS) {
7607c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
76156de8cb5Sanbui 		    "px_lib_msiq_init: px_lib_iommu_map failed, "
76256de8cb5Sanbui 		    "ret 0x%lx\n", ret);
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 		(void) px_lib_msiq_fini(dip);
7657c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 
768d8d130aeSanbui 	if ((ret = hvio_msiq_init(DIP_TO_HANDLE(dip),
769d8d130aeSanbui 	    pxu_p)) != H_EOK) {
770d8d130aeSanbui 		DBG(DBG_LIB_MSIQ, dip,
771d8d130aeSanbui 		    "hvio_msiq_init failed, ret 0x%lx\n", ret);
772d8d130aeSanbui 
773d8d130aeSanbui 		(void) px_lib_msiq_fini(dip);
774d8d130aeSanbui 		return (DDI_FAILURE);
775d8d130aeSanbui 	}
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7817c478bd9Sstevel@tonic-gate int
7827c478bd9Sstevel@tonic-gate px_lib_msiq_fini(dev_info_t *dip)
7837c478bd9Sstevel@tonic-gate {
7847c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
7857c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
7867c478bd9Sstevel@tonic-gate 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
7877c478bd9Sstevel@tonic-gate 	px_dvma_addr_t	pg_index;
7887c478bd9Sstevel@tonic-gate 	size_t		size;
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_fini: dip 0x%p\n", dip);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	/*
7937c478bd9Sstevel@tonic-gate 	 * Unmap and free the EQ memory that had been mapped
7947c478bd9Sstevel@tonic-gate 	 * into the Fire IOMMU.
7957c478bd9Sstevel@tonic-gate 	 */
7967c478bd9Sstevel@tonic-gate 	size = msiq_state_p->msiq_cnt *
7977c478bd9Sstevel@tonic-gate 	    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p,
8007c478bd9Sstevel@tonic-gate 	    MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p));
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	(void) px_lib_iommu_demap(px_p->px_dip,
8037c478bd9Sstevel@tonic-gate 	    PCI_TSBID(0, pg_index), MMU_BTOP(size));
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	/* Free the entries from the Fire MMU */
8067c478bd9Sstevel@tonic-gate 	vmem_xfree(px_p->px_mmu_p->mmu_dvma_map,
8077c478bd9Sstevel@tonic-gate 	    (void *)pxu_p->msiq_mapped_p, size);
8087c478bd9Sstevel@tonic-gate 
809348fdf9eSAlan Adamson, SD OSSD 	kmem_free(msiq_state_p->msiq_buf_p, msiq_state_p->msiq_cnt *
810348fdf9eSAlan Adamson, SD OSSD 	    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t));
811348fdf9eSAlan Adamson, SD OSSD 
8127c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8167c478bd9Sstevel@tonic-gate int
8177c478bd9Sstevel@tonic-gate px_lib_msiq_info(dev_info_t *dip, msiqid_t msiq_id, r_addr_t *ra_p,
8187c478bd9Sstevel@tonic-gate     uint_t *msiq_rec_cnt_p)
8197c478bd9Sstevel@tonic-gate {
8207c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
8217c478bd9Sstevel@tonic-gate 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
8227c478bd9Sstevel@tonic-gate 	size_t		msiq_size;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: dip 0x%p msiq_id 0x%x\n",
8257c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
82895003185Segillett 	ra_p = (r_addr_t *)((caddr_t)msiq_state_p->msiq_buf_p +
82995003185Segillett 	    (msiq_id * msiq_size));
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	*msiq_rec_cnt_p = msiq_state_p->msiq_rec_cnt;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: ra_p 0x%p msiq_rec_cnt 0x%x\n",
8347c478bd9Sstevel@tonic-gate 	    ra_p, *msiq_rec_cnt_p);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8407c478bd9Sstevel@tonic-gate int
8417c478bd9Sstevel@tonic-gate px_lib_msiq_getvalid(dev_info_t *dip, msiqid_t msiq_id,
8427c478bd9Sstevel@tonic-gate     pci_msiq_valid_state_t *msiq_valid_state)
8437c478bd9Sstevel@tonic-gate {
8447c478bd9Sstevel@tonic-gate 	uint64_t	ret;
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: dip 0x%p msiq_id 0x%x\n",
8477c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_getvalid(DIP_TO_HANDLE(dip),
8507c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_valid_state)) != H_EOK) {
8517c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
8527c478bd9Sstevel@tonic-gate 		    "hvio_msiq_getvalid failed, ret 0x%lx\n", ret);
8537c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: msiq_valid_state 0x%x\n",
8577c478bd9Sstevel@tonic-gate 	    *msiq_valid_state);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8637c478bd9Sstevel@tonic-gate int
8647c478bd9Sstevel@tonic-gate px_lib_msiq_setvalid(dev_info_t *dip, msiqid_t msiq_id,
8657c478bd9Sstevel@tonic-gate     pci_msiq_valid_state_t msiq_valid_state)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate 	uint64_t	ret;
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setvalid: dip 0x%p msiq_id 0x%x "
8707c478bd9Sstevel@tonic-gate 	    "msiq_valid_state 0x%x\n", dip, msiq_id, msiq_valid_state);
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_setvalid(DIP_TO_HANDLE(dip),
8737c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_valid_state)) != H_EOK) {
8747c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
8757c478bd9Sstevel@tonic-gate 		    "hvio_msiq_setvalid failed, ret 0x%lx\n", ret);
8767c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8837c478bd9Sstevel@tonic-gate int
8847c478bd9Sstevel@tonic-gate px_lib_msiq_getstate(dev_info_t *dip, msiqid_t msiq_id,
8857c478bd9Sstevel@tonic-gate     pci_msiq_state_t *msiq_state)
8867c478bd9Sstevel@tonic-gate {
8877c478bd9Sstevel@tonic-gate 	uint64_t	ret;
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: dip 0x%p msiq_id 0x%x\n",
8907c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_getstate(DIP_TO_HANDLE(dip),
8937c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_state)) != H_EOK) {
8947c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
8957c478bd9Sstevel@tonic-gate 		    "hvio_msiq_getstate failed, ret 0x%lx\n", ret);
8967c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: msiq_state 0x%x\n",
9007c478bd9Sstevel@tonic-gate 	    *msiq_state);
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9037c478bd9Sstevel@tonic-gate }
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9067c478bd9Sstevel@tonic-gate int
9077c478bd9Sstevel@tonic-gate px_lib_msiq_setstate(dev_info_t *dip, msiqid_t msiq_id,
9087c478bd9Sstevel@tonic-gate     pci_msiq_state_t msiq_state)
9097c478bd9Sstevel@tonic-gate {
9107c478bd9Sstevel@tonic-gate 	uint64_t	ret;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setstate: dip 0x%p msiq_id 0x%x "
9137c478bd9Sstevel@tonic-gate 	    "msiq_state 0x%x\n", dip, msiq_id, msiq_state);
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_setstate(DIP_TO_HANDLE(dip),
9167c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_state)) != H_EOK) {
9177c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
9187c478bd9Sstevel@tonic-gate 		    "hvio_msiq_setstate failed, ret 0x%lx\n", ret);
9197c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9237c478bd9Sstevel@tonic-gate }
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9267c478bd9Sstevel@tonic-gate int
9277c478bd9Sstevel@tonic-gate px_lib_msiq_gethead(dev_info_t *dip, msiqid_t msiq_id,
9287c478bd9Sstevel@tonic-gate     msiqhead_t *msiq_head)
9297c478bd9Sstevel@tonic-gate {
9307c478bd9Sstevel@tonic-gate 	uint64_t	ret;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: dip 0x%p msiq_id 0x%x\n",
9337c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_gethead(DIP_TO_HANDLE(dip),
9367c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_head)) != H_EOK) {
9377c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
9387c478bd9Sstevel@tonic-gate 		    "hvio_msiq_gethead failed, ret 0x%lx\n", ret);
9397c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: msiq_head 0x%x\n",
9437c478bd9Sstevel@tonic-gate 	    *msiq_head);
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9497c478bd9Sstevel@tonic-gate int
9507c478bd9Sstevel@tonic-gate px_lib_msiq_sethead(dev_info_t *dip, msiqid_t msiq_id,
9517c478bd9Sstevel@tonic-gate     msiqhead_t msiq_head)
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate 	uint64_t	ret;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_sethead: dip 0x%p msiq_id 0x%x "
9567c478bd9Sstevel@tonic-gate 	    "msiq_head 0x%x\n", dip, msiq_id, msiq_head);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_sethead(DIP_TO_HANDLE(dip),
9597c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_head)) != H_EOK) {
9607c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
9617c478bd9Sstevel@tonic-gate 		    "hvio_msiq_sethead failed, ret 0x%lx\n", ret);
9627c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9697c478bd9Sstevel@tonic-gate int
9707c478bd9Sstevel@tonic-gate px_lib_msiq_gettail(dev_info_t *dip, msiqid_t msiq_id,
9717c478bd9Sstevel@tonic-gate     msiqtail_t *msiq_tail)
9727c478bd9Sstevel@tonic-gate {
9737c478bd9Sstevel@tonic-gate 	uint64_t	ret;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: dip 0x%p msiq_id 0x%x\n",
9767c478bd9Sstevel@tonic-gate 	    dip, msiq_id);
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msiq_gettail(DIP_TO_HANDLE(dip),
9797c478bd9Sstevel@tonic-gate 	    msiq_id, msiq_tail)) != H_EOK) {
9807c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip,
9817c478bd9Sstevel@tonic-gate 		    "hvio_msiq_gettail failed, ret 0x%lx\n", ret);
9827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: msiq_tail 0x%x\n",
9867c478bd9Sstevel@tonic-gate 	    *msiq_tail);
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9927c478bd9Sstevel@tonic-gate void
993023ccc1eSegillett px_lib_get_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p,
994023ccc1eSegillett     msiq_rec_t *msiq_rec_p)
9957c478bd9Sstevel@tonic-gate {
996023ccc1eSegillett 	eq_rec_t	*eq_rec_p = (eq_rec_t *)msiq_head_p;
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p eq_rec_p 0x%p\n",
9997c478bd9Sstevel@tonic-gate 	    dip, eq_rec_p);
10007c478bd9Sstevel@tonic-gate 
10013ee8f295Smg140465 	if (!eq_rec_p->eq_rec_fmt_type) {
10023ee8f295Smg140465 		/* Set msiq_rec_type to zero */
10033ee8f295Smg140465 		msiq_rec_p->msiq_rec_type = 0;
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 		return;
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: EQ RECORD, "
10097c478bd9Sstevel@tonic-gate 	    "eq_rec_rid 0x%llx eq_rec_fmt_type 0x%llx "
10107c478bd9Sstevel@tonic-gate 	    "eq_rec_len 0x%llx eq_rec_addr0 0x%llx "
10117c478bd9Sstevel@tonic-gate 	    "eq_rec_addr1 0x%llx eq_rec_data0 0x%llx "
10127c478bd9Sstevel@tonic-gate 	    "eq_rec_data1 0x%llx\n", eq_rec_p->eq_rec_rid,
10137c478bd9Sstevel@tonic-gate 	    eq_rec_p->eq_rec_fmt_type, eq_rec_p->eq_rec_len,
10147c478bd9Sstevel@tonic-gate 	    eq_rec_p->eq_rec_addr0, eq_rec_p->eq_rec_addr1,
10157c478bd9Sstevel@tonic-gate 	    eq_rec_p->eq_rec_data0, eq_rec_p->eq_rec_data1);
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	/*
10187c478bd9Sstevel@tonic-gate 	 * Only upper 4 bits of eq_rec_fmt_type is used
10197c478bd9Sstevel@tonic-gate 	 * to identify the EQ record type.
10207c478bd9Sstevel@tonic-gate 	 */
10217c478bd9Sstevel@tonic-gate 	switch (eq_rec_p->eq_rec_fmt_type >> 3) {
10227c478bd9Sstevel@tonic-gate 	case EQ_REC_MSI32:
10237c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_type = MSI32_REC;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_data.msi.msi_data =
10267c478bd9Sstevel@tonic-gate 		    eq_rec_p->eq_rec_data0;
10277c478bd9Sstevel@tonic-gate 		break;
10287c478bd9Sstevel@tonic-gate 	case EQ_REC_MSI64:
10297c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_type = MSI64_REC;
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_data.msi.msi_data =
10327c478bd9Sstevel@tonic-gate 		    eq_rec_p->eq_rec_data0;
10337c478bd9Sstevel@tonic-gate 		break;
10347c478bd9Sstevel@tonic-gate 	case EQ_REC_MSG:
10357c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_type = MSG_REC;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_data.msg.msg_route =
10387c478bd9Sstevel@tonic-gate 		    eq_rec_p->eq_rec_fmt_type & 7;
10397c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_data.msg.msg_targ = eq_rec_p->eq_rec_rid;
10407c478bd9Sstevel@tonic-gate 		msiq_rec_p->msiq_rec_data.msg.msg_code = eq_rec_p->eq_rec_data0;
10417c478bd9Sstevel@tonic-gate 		break;
10427c478bd9Sstevel@tonic-gate 	default:
10437c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: px_lib_get_msiq_rec: "
1044b40cec45Skrishnae 		    "0x%x is an unknown EQ record type",
10457c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip),
1046b40cec45Skrishnae 		    (int)eq_rec_p->eq_rec_fmt_type);
10477c478bd9Sstevel@tonic-gate 		break;
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	msiq_rec_p->msiq_rec_rid = eq_rec_p->eq_rec_rid;
10517c478bd9Sstevel@tonic-gate 	msiq_rec_p->msiq_rec_msi_addr = ((eq_rec_p->eq_rec_addr1 << 16) |
10527c478bd9Sstevel@tonic-gate 	    (eq_rec_p->eq_rec_addr0 << 2));
1053b0fc0e77Sgovinda }
10547c478bd9Sstevel@tonic-gate 
1055b0fc0e77Sgovinda /*ARGSUSED*/
1056b0fc0e77Sgovinda void
1057b0fc0e77Sgovinda px_lib_clr_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p)
1058b0fc0e77Sgovinda {
1059b0fc0e77Sgovinda 	eq_rec_t	*eq_rec_p = (eq_rec_t *)msiq_head_p;
1060b0fc0e77Sgovinda 
1061b0fc0e77Sgovinda 	DBG(DBG_LIB_MSIQ, dip, "px_lib_clr_msiq_rec: dip 0x%p eq_rec_p 0x%p\n",
1062b0fc0e77Sgovinda 	    dip, eq_rec_p);
1063b0fc0e77Sgovinda 
1064b0fc0e77Sgovinda 	if (eq_rec_p->eq_rec_fmt_type) {
10653ee8f295Smg140465 		/* Zero out eq_rec_fmt_type field */
10663ee8f295Smg140465 		eq_rec_p->eq_rec_fmt_type = 0;
10677c478bd9Sstevel@tonic-gate 	}
1068b0fc0e77Sgovinda }
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate /*
10717c478bd9Sstevel@tonic-gate  * MSI Functions:
10727c478bd9Sstevel@tonic-gate  */
10737c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10747c478bd9Sstevel@tonic-gate int
10757c478bd9Sstevel@tonic-gate px_lib_msi_init(dev_info_t *dip)
10767c478bd9Sstevel@tonic-gate {
10777c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
10787c478bd9Sstevel@tonic-gate 	px_msi_state_t	*msi_state_p = &px_p->px_ib_p->ib_msi_state;
10797c478bd9Sstevel@tonic-gate 	uint64_t	ret;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_init: dip 0x%p\n", dip);
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_init(DIP_TO_HANDLE(dip),
10847c478bd9Sstevel@tonic-gate 	    msi_state_p->msi_addr32, msi_state_p->msi_addr64)) != H_EOK) {
10857c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSIQ, dip, "px_lib_msi_init failed, ret 0x%lx\n",
10867c478bd9Sstevel@tonic-gate 		    ret);
10877c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10887c478bd9Sstevel@tonic-gate 	}
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10917c478bd9Sstevel@tonic-gate }
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10947c478bd9Sstevel@tonic-gate int
10957c478bd9Sstevel@tonic-gate px_lib_msi_getmsiq(dev_info_t *dip, msinum_t msi_num,
10967c478bd9Sstevel@tonic-gate     msiqid_t *msiq_id)
10977c478bd9Sstevel@tonic-gate {
10987c478bd9Sstevel@tonic-gate 	uint64_t	ret;
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: dip 0x%p msi_num 0x%x\n",
11017c478bd9Sstevel@tonic-gate 	    dip, msi_num);
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_getmsiq(DIP_TO_HANDLE(dip),
11047c478bd9Sstevel@tonic-gate 	    msi_num, msiq_id)) != H_EOK) {
11057c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11067c478bd9Sstevel@tonic-gate 		    "hvio_msi_getmsiq failed, ret 0x%lx\n", ret);
11077c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: msiq_id 0x%x\n",
11117c478bd9Sstevel@tonic-gate 	    *msiq_id);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11177c478bd9Sstevel@tonic-gate int
11187c478bd9Sstevel@tonic-gate px_lib_msi_setmsiq(dev_info_t *dip, msinum_t msi_num,
11197c478bd9Sstevel@tonic-gate     msiqid_t msiq_id, msi_type_t msitype)
11207c478bd9Sstevel@tonic-gate {
11217c478bd9Sstevel@tonic-gate 	uint64_t	ret;
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setmsiq: dip 0x%p msi_num 0x%x "
11247c478bd9Sstevel@tonic-gate 	    "msq_id 0x%x\n", dip, msi_num, msiq_id);
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_setmsiq(DIP_TO_HANDLE(dip),
11277c478bd9Sstevel@tonic-gate 	    msi_num, msiq_id)) != H_EOK) {
11287c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11297c478bd9Sstevel@tonic-gate 		    "hvio_msi_setmsiq failed, ret 0x%lx\n", ret);
11307c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11317c478bd9Sstevel@tonic-gate 	}
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11377c478bd9Sstevel@tonic-gate int
11387c478bd9Sstevel@tonic-gate px_lib_msi_getvalid(dev_info_t *dip, msinum_t msi_num,
11397c478bd9Sstevel@tonic-gate     pci_msi_valid_state_t *msi_valid_state)
11407c478bd9Sstevel@tonic-gate {
11417c478bd9Sstevel@tonic-gate 	uint64_t	ret;
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: dip 0x%p msi_num 0x%x\n",
11447c478bd9Sstevel@tonic-gate 	    dip, msi_num);
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_getvalid(DIP_TO_HANDLE(dip),
11477c478bd9Sstevel@tonic-gate 	    msi_num, msi_valid_state)) != H_EOK) {
11487c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11497c478bd9Sstevel@tonic-gate 		    "hvio_msi_getvalid failed, ret 0x%lx\n", ret);
11507c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11517c478bd9Sstevel@tonic-gate 	}
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: msiq_id 0x%x\n",
11547c478bd9Sstevel@tonic-gate 	    *msi_valid_state);
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11577c478bd9Sstevel@tonic-gate }
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11607c478bd9Sstevel@tonic-gate int
11617c478bd9Sstevel@tonic-gate px_lib_msi_setvalid(dev_info_t *dip, msinum_t msi_num,
11627c478bd9Sstevel@tonic-gate     pci_msi_valid_state_t msi_valid_state)
11637c478bd9Sstevel@tonic-gate {
11647c478bd9Sstevel@tonic-gate 	uint64_t	ret;
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setvalid: dip 0x%p msi_num 0x%x "
11677c478bd9Sstevel@tonic-gate 	    "msi_valid_state 0x%x\n", dip, msi_num, msi_valid_state);
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_setvalid(DIP_TO_HANDLE(dip),
11707c478bd9Sstevel@tonic-gate 	    msi_num, msi_valid_state)) != H_EOK) {
11717c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11727c478bd9Sstevel@tonic-gate 		    "hvio_msi_setvalid failed, ret 0x%lx\n", ret);
11737c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11747c478bd9Sstevel@tonic-gate 	}
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11777c478bd9Sstevel@tonic-gate }
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11807c478bd9Sstevel@tonic-gate int
11817c478bd9Sstevel@tonic-gate px_lib_msi_getstate(dev_info_t *dip, msinum_t msi_num,
11827c478bd9Sstevel@tonic-gate     pci_msi_state_t *msi_state)
11837c478bd9Sstevel@tonic-gate {
11847c478bd9Sstevel@tonic-gate 	uint64_t	ret;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: dip 0x%p msi_num 0x%x\n",
11877c478bd9Sstevel@tonic-gate 	    dip, msi_num);
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_getstate(DIP_TO_HANDLE(dip),
11907c478bd9Sstevel@tonic-gate 	    msi_num, msi_state)) != H_EOK) {
11917c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
11927c478bd9Sstevel@tonic-gate 		    "hvio_msi_getstate failed, ret 0x%lx\n", ret);
11937c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: msi_state 0x%x\n",
11977c478bd9Sstevel@tonic-gate 	    *msi_state);
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12037c478bd9Sstevel@tonic-gate int
12047c478bd9Sstevel@tonic-gate px_lib_msi_setstate(dev_info_t *dip, msinum_t msi_num,
12057c478bd9Sstevel@tonic-gate     pci_msi_state_t msi_state)
12067c478bd9Sstevel@tonic-gate {
12077c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msi_setstate: dip 0x%p msi_num 0x%x "
12107c478bd9Sstevel@tonic-gate 	    "msi_state 0x%x\n", dip, msi_num, msi_state);
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msi_setstate(DIP_TO_HANDLE(dip),
12137c478bd9Sstevel@tonic-gate 	    msi_num, msi_state)) != H_EOK) {
12147c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSI, dip,
12157c478bd9Sstevel@tonic-gate 		    "hvio_msi_setstate failed, ret 0x%lx\n", ret);
12167c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12177c478bd9Sstevel@tonic-gate 	}
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate /*
12237c478bd9Sstevel@tonic-gate  * MSG Functions:
12247c478bd9Sstevel@tonic-gate  */
12257c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12267c478bd9Sstevel@tonic-gate int
12277c478bd9Sstevel@tonic-gate px_lib_msg_getmsiq(dev_info_t *dip, pcie_msg_type_t msg_type,
12287c478bd9Sstevel@tonic-gate     msiqid_t *msiq_id)
12297c478bd9Sstevel@tonic-gate {
12307c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_getmsiq: dip 0x%p msg_type 0x%x\n",
12337c478bd9Sstevel@tonic-gate 	    dip, msg_type);
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msg_getmsiq(DIP_TO_HANDLE(dip),
12367c478bd9Sstevel@tonic-gate 	    msg_type, msiq_id)) != H_EOK) {
12377c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSG, dip,
12387c478bd9Sstevel@tonic-gate 		    "hvio_msg_getmsiq failed, ret 0x%lx\n", ret);
12397c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12407c478bd9Sstevel@tonic-gate 	}
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msg_getmsiq: msiq_id 0x%x\n",
12437c478bd9Sstevel@tonic-gate 	    *msiq_id);
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12467c478bd9Sstevel@tonic-gate }
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12497c478bd9Sstevel@tonic-gate int
12507c478bd9Sstevel@tonic-gate px_lib_msg_setmsiq(dev_info_t *dip, pcie_msg_type_t msg_type,
12517c478bd9Sstevel@tonic-gate     msiqid_t msiq_id)
12527c478bd9Sstevel@tonic-gate {
12537c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSG, dip, "px_lib_msi_setstate: dip 0x%p msg_type 0x%x "
12567c478bd9Sstevel@tonic-gate 	    "msiq_id 0x%x\n", dip, msg_type, msiq_id);
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msg_setmsiq(DIP_TO_HANDLE(dip),
12597c478bd9Sstevel@tonic-gate 	    msg_type, msiq_id)) != H_EOK) {
12607c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSG, dip,
12617c478bd9Sstevel@tonic-gate 		    "hvio_msg_setmsiq failed, ret 0x%lx\n", ret);
12627c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12637c478bd9Sstevel@tonic-gate 	}
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12667c478bd9Sstevel@tonic-gate }
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12697c478bd9Sstevel@tonic-gate int
12707c478bd9Sstevel@tonic-gate px_lib_msg_getvalid(dev_info_t *dip, pcie_msg_type_t msg_type,
12717c478bd9Sstevel@tonic-gate     pcie_msg_valid_state_t *msg_valid_state)
12727c478bd9Sstevel@tonic-gate {
12737c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_getvalid: dip 0x%p msg_type 0x%x\n",
12767c478bd9Sstevel@tonic-gate 	    dip, msg_type);
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msg_getvalid(DIP_TO_HANDLE(dip), msg_type,
12797c478bd9Sstevel@tonic-gate 	    msg_valid_state)) != H_EOK) {
12807c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSG, dip,
12817c478bd9Sstevel@tonic-gate 		    "hvio_msg_getvalid failed, ret 0x%lx\n", ret);
12827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12837c478bd9Sstevel@tonic-gate 	}
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSI, dip, "px_lib_msg_getvalid: msg_valid_state 0x%x\n",
12867c478bd9Sstevel@tonic-gate 	    *msg_valid_state);
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12897c478bd9Sstevel@tonic-gate }
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12927c478bd9Sstevel@tonic-gate int
12937c478bd9Sstevel@tonic-gate px_lib_msg_setvalid(dev_info_t *dip, pcie_msg_type_t msg_type,
12947c478bd9Sstevel@tonic-gate     pcie_msg_valid_state_t msg_valid_state)
12957c478bd9Sstevel@tonic-gate {
12967c478bd9Sstevel@tonic-gate 	uint64_t	ret;
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	DBG(DBG_LIB_MSG, dip, "px_lib_msg_setvalid: dip 0x%p msg_type 0x%x "
12997c478bd9Sstevel@tonic-gate 	    "msg_valid_state 0x%x\n", dip, msg_type, msg_valid_state);
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 	if ((ret = hvio_msg_setvalid(DIP_TO_HANDLE(dip), msg_type,
13027c478bd9Sstevel@tonic-gate 	    msg_valid_state)) != H_EOK) {
13037c478bd9Sstevel@tonic-gate 		DBG(DBG_LIB_MSG, dip,
13047c478bd9Sstevel@tonic-gate 		    "hvio_msg_setvalid failed, ret 0x%lx\n", ret);
13057c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13067c478bd9Sstevel@tonic-gate 	}
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
13097c478bd9Sstevel@tonic-gate }
13107c478bd9Sstevel@tonic-gate 
1311fc256490SJason Beloro /*ARGSUSED*/
1312fc256490SJason Beloro void
1313fc256490SJason Beloro px_panic_domain(px_t *px_p, pcie_req_id_t bdf)
1314fc256490SJason Beloro {
1315fc256490SJason Beloro }
1316fc256490SJason Beloro 
13177c478bd9Sstevel@tonic-gate /*
13187c478bd9Sstevel@tonic-gate  * Suspend/Resume Functions:
13197c478bd9Sstevel@tonic-gate  * Currently unsupported by hypervisor
13207c478bd9Sstevel@tonic-gate  */
13217c478bd9Sstevel@tonic-gate int
13227c478bd9Sstevel@tonic-gate px_lib_suspend(dev_info_t *dip)
13237c478bd9Sstevel@tonic-gate {
13247c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
13257c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
132601689544Sjchu 	px_cb_t		*cb_p = PX2CB(px_p);
13277c478bd9Sstevel@tonic-gate 	devhandle_t	dev_hdl, xbus_dev_hdl;
132801689544Sjchu 	uint64_t	ret = H_EOK;
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	DBG(DBG_DETACH, dip, "px_lib_suspend: dip 0x%p\n", dip);
13317c478bd9Sstevel@tonic-gate 
1332f8d2de6bSjchu 	dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR];
1333f8d2de6bSjchu 	xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC];
13347c478bd9Sstevel@tonic-gate 
133501689544Sjchu 	if ((ret = hvio_suspend(dev_hdl, pxu_p)) != H_EOK)
133601689544Sjchu 		goto fail;
133701689544Sjchu 
133801689544Sjchu 	if (--cb_p->attachcnt == 0) {
133901689544Sjchu 		ret = hvio_cb_suspend(xbus_dev_hdl, pxu_p);
134001689544Sjchu 		if (ret != H_EOK)
134101689544Sjchu 			cb_p->attachcnt++;
13427c478bd9Sstevel@tonic-gate 	}
1343bf8fc234Set142600 	pxu_p->cpr_flag = PX_ENTERED_CPR;
13447c478bd9Sstevel@tonic-gate 
134501689544Sjchu fail:
13467c478bd9Sstevel@tonic-gate 	return ((ret != H_EOK) ? DDI_FAILURE: DDI_SUCCESS);
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate void
13507c478bd9Sstevel@tonic-gate px_lib_resume(dev_info_t *dip)
13517c478bd9Sstevel@tonic-gate {
13527c478bd9Sstevel@tonic-gate 	px_t		*px_p = DIP_TO_STATE(dip);
13537c478bd9Sstevel@tonic-gate 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
135401689544Sjchu 	px_cb_t		*cb_p = PX2CB(px_p);
13557c478bd9Sstevel@tonic-gate 	devhandle_t	dev_hdl, xbus_dev_hdl;
13567c478bd9Sstevel@tonic-gate 	devino_t	pec_ino = px_p->px_inos[PX_INTR_PEC];
13577c478bd9Sstevel@tonic-gate 	devino_t	xbc_ino = px_p->px_inos[PX_INTR_XBC];
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 	DBG(DBG_ATTACH, dip, "px_lib_resume: dip 0x%p\n", dip);
13607c478bd9Sstevel@tonic-gate 
1361f8d2de6bSjchu 	dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR];
1362f8d2de6bSjchu 	xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC];
13637c478bd9Sstevel@tonic-gate 
136401689544Sjchu 	if (++cb_p->attachcnt == 1)
13657c478bd9Sstevel@tonic-gate 		hvio_cb_resume(dev_hdl, xbus_dev_hdl, xbc_ino, pxu_p);
136601689544Sjchu 
13677c478bd9Sstevel@tonic-gate 	hvio_resume(dev_hdl, pec_ino, pxu_p);
13687c478bd9Sstevel@tonic-gate }
13697c478bd9Sstevel@tonic-gate 
137025cf1a30Sjl139090 /*
137125cf1a30Sjl139090  * Generate a unique Oberon UBC ID based on the Logicial System Board and
137225cf1a30Sjl139090  * the IO Channel from the portid property field.
137325cf1a30Sjl139090  */
137425cf1a30Sjl139090 static uint64_t
137525cf1a30Sjl139090 oberon_get_ubc_id(dev_info_t *dip)
137625cf1a30Sjl139090 {
137725cf1a30Sjl139090 	px_t	*px_p = DIP_TO_STATE(dip);
137825cf1a30Sjl139090 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
137925cf1a30Sjl139090 	uint64_t	ubc_id;
138025cf1a30Sjl139090 
138125cf1a30Sjl139090 	/*
138225cf1a30Sjl139090 	 * Generate a unique 6 bit UBC ID using the 2 IO_Channel#[1:0] bits and
138325cf1a30Sjl139090 	 * the 4 LSB_ID[3:0] bits from the Oberon's portid property.
138425cf1a30Sjl139090 	 */
138525cf1a30Sjl139090 	ubc_id = (((pxu_p->portid >> OBERON_PORT_ID_IOC) &
138625cf1a30Sjl139090 	    OBERON_PORT_ID_IOC_MASK) | (((pxu_p->portid >>
138725cf1a30Sjl139090 	    OBERON_PORT_ID_LSB) & OBERON_PORT_ID_LSB_MASK)
138825cf1a30Sjl139090 	    << OBERON_UBC_ID_LSB));
138925cf1a30Sjl139090 
139025cf1a30Sjl139090 	return (ubc_id);
139125cf1a30Sjl139090 }
139225cf1a30Sjl139090 
139325cf1a30Sjl139090 /*
139425cf1a30Sjl139090  * Oberon does not have a UBC scratch register, so alloc an array of scratch
139525cf1a30Sjl139090  * registers when needed and use a unique UBC ID as an index. This code
139625cf1a30Sjl139090  * can be simplified if we use a pre-allocated array. They are currently
139725cf1a30Sjl139090  * being dynamically allocated because it's only needed by the Oberon.
139825cf1a30Sjl139090  */
139925cf1a30Sjl139090 static void
140025cf1a30Sjl139090 oberon_set_cb(dev_info_t *dip, uint64_t val)
140125cf1a30Sjl139090 {
140225cf1a30Sjl139090 	uint64_t	ubc_id;
140325cf1a30Sjl139090 
140425cf1a30Sjl139090 	if (px_oberon_ubc_scratch_regs == NULL)
140525cf1a30Sjl139090 		px_oberon_ubc_scratch_regs =
140625cf1a30Sjl139090 		    (uint64_t *)kmem_zalloc(sizeof (uint64_t)*
140725cf1a30Sjl139090 		    OBERON_UBC_ID_MAX, KM_SLEEP);
140825cf1a30Sjl139090 
140925cf1a30Sjl139090 	ubc_id = oberon_get_ubc_id(dip);
141025cf1a30Sjl139090 
141125cf1a30Sjl139090 	px_oberon_ubc_scratch_regs[ubc_id] = val;
141225cf1a30Sjl139090 
141325cf1a30Sjl139090 	/*
141425cf1a30Sjl139090 	 * Check if any scratch registers are still in use. If all scratch
141525cf1a30Sjl139090 	 * registers are currently set to zero, then deallocate the scratch
141625cf1a30Sjl139090 	 * register array.
141725cf1a30Sjl139090 	 */
141825cf1a30Sjl139090 	for (ubc_id = 0; ubc_id < OBERON_UBC_ID_MAX; ubc_id++) {
141925cf1a30Sjl139090 		if (px_oberon_ubc_scratch_regs[ubc_id] != NULL)
142025cf1a30Sjl139090 			return;
142125cf1a30Sjl139090 	}
142225cf1a30Sjl139090 
142325cf1a30Sjl139090 	/*
142425cf1a30Sjl139090 	 * All scratch registers are set to zero so deallocate the scratch
142525cf1a30Sjl139090 	 * register array and set the pointer to NULL.
142625cf1a30Sjl139090 	 */
142725cf1a30Sjl139090 	kmem_free(px_oberon_ubc_scratch_regs,
142825cf1a30Sjl139090 	    (sizeof (uint64_t)*OBERON_UBC_ID_MAX));
142925cf1a30Sjl139090 
143025cf1a30Sjl139090 	px_oberon_ubc_scratch_regs = NULL;
143125cf1a30Sjl139090 }
143225cf1a30Sjl139090 
143325cf1a30Sjl139090 /*
143425cf1a30Sjl139090  * Oberon does not have a UBC scratch register, so use an allocated array of
143525cf1a30Sjl139090  * scratch registers and use the unique UBC ID as an index into that array.
143625cf1a30Sjl139090  */
143725cf1a30Sjl139090 static uint64_t
143825cf1a30Sjl139090 oberon_get_cb(dev_info_t *dip)
143925cf1a30Sjl139090 {
144025cf1a30Sjl139090 	uint64_t	ubc_id;
144125cf1a30Sjl139090 
144225cf1a30Sjl139090 	if (px_oberon_ubc_scratch_regs == NULL)
144325cf1a30Sjl139090 		return (0);
144425cf1a30Sjl139090 
144525cf1a30Sjl139090 	ubc_id = oberon_get_ubc_id(dip);
144625cf1a30Sjl139090 
144725cf1a30Sjl139090 	return (px_oberon_ubc_scratch_regs[ubc_id]);
144825cf1a30Sjl139090 }
144925cf1a30Sjl139090 
145025cf1a30Sjl139090 /*
145125cf1a30Sjl139090  * Misc Functions:
145225cf1a30Sjl139090  * Currently unsupported by hypervisor
145325cf1a30Sjl139090  */
145425cf1a30Sjl139090 static uint64_t
145525cf1a30Sjl139090 px_get_cb(dev_info_t *dip)
145625cf1a30Sjl139090 {
145725cf1a30Sjl139090 	px_t	*px_p = DIP_TO_STATE(dip);
145825cf1a30Sjl139090 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
145925cf1a30Sjl139090 
146025cf1a30Sjl139090 	/*
146125cf1a30Sjl139090 	 * Oberon does not currently have Scratchpad registers.
146225cf1a30Sjl139090 	 */
146325cf1a30Sjl139090 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON)
146425cf1a30Sjl139090 		return (oberon_get_cb(dip));
146525cf1a30Sjl139090 
146625cf1a30Sjl139090 	return (CSR_XR((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1));
146725cf1a30Sjl139090 }
146825cf1a30Sjl139090 
146925cf1a30Sjl139090 static void
147025cf1a30Sjl139090 px_set_cb(dev_info_t *dip, uint64_t val)
147125cf1a30Sjl139090 {
147225cf1a30Sjl139090 	px_t	*px_p = DIP_TO_STATE(dip);
147325cf1a30Sjl139090 	pxu_t	*pxu_p = (pxu_t *)px_p->px_plat_p;
147425cf1a30Sjl139090 
147525cf1a30Sjl139090 	/*
147625cf1a30Sjl139090 	 * Oberon does not currently have Scratchpad registers.
147725cf1a30Sjl139090 	 */
147825cf1a30Sjl139090 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) {
147925cf1a30Sjl139090 		oberon_set_cb(dip, val);
148025cf1a30Sjl139090 		return;
148125cf1a30Sjl139090 	}
148225cf1a30Sjl139090 
148325cf1a30Sjl139090 	CSR_XS((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1, val);
148425cf1a30Sjl139090 }
148525cf1a30Sjl139090 
14867c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14877c478bd9Sstevel@tonic-gate int
14887c478bd9Sstevel@tonic-gate px_lib_map_vconfig(dev_info_t *dip,
14897c478bd9Sstevel@tonic-gate 	ddi_map_req_t *mp, pci_config_offset_t off,
14907c478bd9Sstevel@tonic-gate 		pci_regspec_t *rp, caddr_t *addrp)
14917c478bd9Sstevel@tonic-gate {
14927c478bd9Sstevel@tonic-gate 	/*
14937c478bd9Sstevel@tonic-gate 	 * No special config space access services in this layer.
14947c478bd9Sstevel@tonic-gate 	 */
14957c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
14967c478bd9Sstevel@tonic-gate }
14977c478bd9Sstevel@tonic-gate 
149869cd775fSschwartz void
14994fbb58f6Sjchu px_lib_map_attr_check(ddi_map_req_t *mp)
15004fbb58f6Sjchu {
15014fbb58f6Sjchu 	ddi_acc_hdl_t *hp = mp->map_handlep;
15024fbb58f6Sjchu 
15034fbb58f6Sjchu 	/* fire does not accept byte masks from PIO store merge */
15044fbb58f6Sjchu 	if (hp->ah_acc.devacc_attr_dataorder == DDI_STORECACHING_OK_ACC)
15054fbb58f6Sjchu 		hp->ah_acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15064fbb58f6Sjchu }
15074fbb58f6Sjchu 
1508bf8fc234Set142600 /* This function is called only by poke, caut put and pxtool poke. */
15094fbb58f6Sjchu void
1510bf8fc234Set142600 px_lib_clr_errs(px_t *px_p, dev_info_t *rdip, uint64_t addr)
1511f8d2de6bSjchu {
151269cd775fSschwartz 	px_pec_t	*pec_p = px_p->px_pec_p;
1513f8d2de6bSjchu 	dev_info_t	*rpdip = px_p->px_dip;
1514bf8fc234Set142600 	int		rc_err, fab_err, i;
1515f8d2de6bSjchu 	int		acctype = pec_p->pec_safeacc_type;
1516f8d2de6bSjchu 	ddi_fm_error_t	derr;
151726947304SEvan Yan 	pci_ranges_t	*ranges_p;
1518bf8fc234Set142600 	int		range_len;
1519bf8fc234Set142600 	uint32_t	addr_high, addr_low;
1520c85864d8SKrishna Elango 	pcie_req_id_t	bdf = PCIE_INVALID_BDF;
1521f8d2de6bSjchu 
1522f8d2de6bSjchu 	/* Create the derr */
1523f8d2de6bSjchu 	bzero(&derr, sizeof (ddi_fm_error_t));
1524f8d2de6bSjchu 	derr.fme_version = DDI_FME_VERSION;
1525f8d2de6bSjchu 	derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
1526f8d2de6bSjchu 	derr.fme_flag = acctype;
1527f8d2de6bSjchu 
1528f8d2de6bSjchu 	if (acctype == DDI_FM_ERR_EXPECTED) {
1529f8d2de6bSjchu 		derr.fme_status = DDI_FM_NONFATAL;
1530f8d2de6bSjchu 		ndi_fm_acc_err_set(pec_p->pec_acc_hdl, &derr);
1531f8d2de6bSjchu 	}
1532f8d2de6bSjchu 
1533eae2e508Skrishnae 	if (px_fm_enter(px_p) != DDI_SUCCESS)
1534eae2e508Skrishnae 		return;
1535f8d2de6bSjchu 
1536f8d2de6bSjchu 	/* send ereport/handle/clear fire registers */
1537bf8fc234Set142600 	rc_err = px_err_cmn_intr(px_p, &derr, PX_LIB_CALL, PX_FM_BLOCK_ALL);
1538f8d2de6bSjchu 
1539bf8fc234Set142600 	/* Figure out if this is a cfg or mem32 access */
1540bf8fc234Set142600 	addr_high = (uint32_t)(addr >> 32);
1541bf8fc234Set142600 	addr_low = (uint32_t)addr;
154226947304SEvan Yan 	range_len = px_p->px_ranges_length / sizeof (pci_ranges_t);
1543bf8fc234Set142600 	i = 0;
1544bf8fc234Set142600 	for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) {
1545bf8fc234Set142600 		if (ranges_p->parent_high == addr_high) {
1546bf8fc234Set142600 			switch (ranges_p->child_high & PCI_ADDR_MASK) {
1547bf8fc234Set142600 			case PCI_ADDR_CONFIG:
1548bf8fc234Set142600 				bdf = (pcie_req_id_t)(addr_low >> 12);
1549bf8fc234Set142600 				addr_low = 0;
1550bf8fc234Set142600 				break;
1551bf8fc234Set142600 			case PCI_ADDR_MEM32:
1552bf8fc234Set142600 				if (rdip)
1553eae2e508Skrishnae 					bdf = PCI_GET_BDF(rdip);
1554bf8fc234Set142600 				else
1555c85864d8SKrishna Elango 					bdf = PCIE_INVALID_BDF;
1556bf8fc234Set142600 				break;
1557bf8fc234Set142600 			}
1558bf8fc234Set142600 			break;
1559bf8fc234Set142600 		}
1560bf8fc234Set142600 	}
1561bf8fc234Set142600 
1562fc256490SJason Beloro 	(void) px_rp_en_q(px_p, bdf, addr_low, NULL);
1563bf8fc234Set142600 
1564bf8fc234Set142600 	/*
1565bf8fc234Set142600 	 * XXX - Current code scans the fabric for all px_tool accesses.
1566bf8fc234Set142600 	 * In future, do not scan fabric for px_tool access to IO Root Nexus
1567bf8fc234Set142600 	 */
1568eae2e508Skrishnae 	fab_err = px_scan_fabric(px_p, rpdip, &derr);
1569f8d2de6bSjchu 
1570eae2e508Skrishnae 	px_err_panic(rc_err, PX_RC, fab_err, B_TRUE);
1571eae2e508Skrishnae 	px_fm_exit(px_p);
1572eae2e508Skrishnae 	px_err_panic(rc_err, PX_RC, fab_err, B_FALSE);
1573f8d2de6bSjchu }
1574f8d2de6bSjchu 
15757c478bd9Sstevel@tonic-gate #ifdef  DEBUG
15767c478bd9Sstevel@tonic-gate int	px_peekfault_cnt = 0;
15777c478bd9Sstevel@tonic-gate int	px_pokefault_cnt = 0;
15787c478bd9Sstevel@tonic-gate #endif  /* DEBUG */
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15817c478bd9Sstevel@tonic-gate static int
15827c478bd9Sstevel@tonic-gate px_lib_do_poke(dev_info_t *dip, dev_info_t *rdip,
15837c478bd9Sstevel@tonic-gate     peekpoke_ctlops_t *in_args)
15847c478bd9Sstevel@tonic-gate {
15857c478bd9Sstevel@tonic-gate 	px_t *px_p = DIP_TO_STATE(dip);
15867c478bd9Sstevel@tonic-gate 	px_pec_t *pec_p = px_p->px_pec_p;
15877c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
15887c478bd9Sstevel@tonic-gate 	on_trap_data_t otd;
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	mutex_enter(&pec_p->pec_pokefault_mutex);
15917c478bd9Sstevel@tonic-gate 	pec_p->pec_ontrap_data = &otd;
1592f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_POKE;
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	/* Set up protected environment. */
15957c478bd9Sstevel@tonic-gate 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
15967c478bd9Sstevel@tonic-gate 		uintptr_t tramp = otd.ot_trampoline;
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = (uintptr_t)&poke_fault;
15997c478bd9Sstevel@tonic-gate 		err = do_poke(in_args->size, (void *)in_args->dev_addr,
16007c478bd9Sstevel@tonic-gate 		    (void *)in_args->host_addr);
16017c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = tramp;
16027c478bd9Sstevel@tonic-gate 	} else
16037c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
16047c478bd9Sstevel@tonic-gate 
1605bf8fc234Set142600 	px_lib_clr_errs(px_p, rdip, in_args->dev_addr);
1606f8d2de6bSjchu 
16077c478bd9Sstevel@tonic-gate 	if (otd.ot_trap & OT_DATA_ACCESS)
16087c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	/* Take down protected environment. */
16117c478bd9Sstevel@tonic-gate 	no_trap();
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	pec_p->pec_ontrap_data = NULL;
1614f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
16157c478bd9Sstevel@tonic-gate 	mutex_exit(&pec_p->pec_pokefault_mutex);
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate #ifdef  DEBUG
16187c478bd9Sstevel@tonic-gate 	if (err == DDI_FAILURE)
16197c478bd9Sstevel@tonic-gate 		px_pokefault_cnt++;
16207c478bd9Sstevel@tonic-gate #endif
16217c478bd9Sstevel@tonic-gate 	return (err);
16227c478bd9Sstevel@tonic-gate }
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16257c478bd9Sstevel@tonic-gate static int
16267c478bd9Sstevel@tonic-gate px_lib_do_caut_put(dev_info_t *dip, dev_info_t *rdip,
16277c478bd9Sstevel@tonic-gate     peekpoke_ctlops_t *cautacc_ctlops_arg)
16287c478bd9Sstevel@tonic-gate {
16297c478bd9Sstevel@tonic-gate 	size_t size = cautacc_ctlops_arg->size;
16307c478bd9Sstevel@tonic-gate 	uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr;
16317c478bd9Sstevel@tonic-gate 	uintptr_t host_addr = cautacc_ctlops_arg->host_addr;
16327c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle;
16337c478bd9Sstevel@tonic-gate 	size_t repcount = cautacc_ctlops_arg->repcount;
16347c478bd9Sstevel@tonic-gate 	uint_t flags = cautacc_ctlops_arg->flags;
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	px_t *px_p = DIP_TO_STATE(dip);
16377c478bd9Sstevel@tonic-gate 	px_pec_t *pec_p = px_p->px_pec_p;
16387c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
16397c478bd9Sstevel@tonic-gate 
1640f8d2de6bSjchu 	/*
1641f8d2de6bSjchu 	 * Note that i_ndi_busop_access_enter ends up grabbing the pokefault
1642f8d2de6bSjchu 	 * mutex.
1643f8d2de6bSjchu 	 */
16447c478bd9Sstevel@tonic-gate 	i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
16457c478bd9Sstevel@tonic-gate 
1646f8d2de6bSjchu 	pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap;
1647f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED;
1648f8d2de6bSjchu 	hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED;
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) {
16517c478bd9Sstevel@tonic-gate 		for (; repcount; repcount--) {
16527c478bd9Sstevel@tonic-gate 			switch (size) {
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 			case sizeof (uint8_t):
16557c478bd9Sstevel@tonic-gate 				i_ddi_put8(hp, (uint8_t *)dev_addr,
16567c478bd9Sstevel@tonic-gate 				    *(uint8_t *)host_addr);
16577c478bd9Sstevel@tonic-gate 				break;
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 			case sizeof (uint16_t):
16607c478bd9Sstevel@tonic-gate 				i_ddi_put16(hp, (uint16_t *)dev_addr,
16617c478bd9Sstevel@tonic-gate 				    *(uint16_t *)host_addr);
16627c478bd9Sstevel@tonic-gate 				break;
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate 			case sizeof (uint32_t):
16657c478bd9Sstevel@tonic-gate 				i_ddi_put32(hp, (uint32_t *)dev_addr,
16667c478bd9Sstevel@tonic-gate 				    *(uint32_t *)host_addr);
16677c478bd9Sstevel@tonic-gate 				break;
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 			case sizeof (uint64_t):
16707c478bd9Sstevel@tonic-gate 				i_ddi_put64(hp, (uint64_t *)dev_addr,
16717c478bd9Sstevel@tonic-gate 				    *(uint64_t *)host_addr);
16727c478bd9Sstevel@tonic-gate 				break;
16737c478bd9Sstevel@tonic-gate 			}
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate 			host_addr += size;
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 			if (flags == DDI_DEV_AUTOINCR)
16787c478bd9Sstevel@tonic-gate 				dev_addr += size;
16797c478bd9Sstevel@tonic-gate 
1680bf8fc234Set142600 			px_lib_clr_errs(px_p, rdip, dev_addr);
1681f8d2de6bSjchu 
16827c478bd9Sstevel@tonic-gate 			if (pec_p->pec_ontrap_data->ot_trap & OT_DATA_ACCESS) {
16837c478bd9Sstevel@tonic-gate 				err = DDI_FAILURE;
16847c478bd9Sstevel@tonic-gate #ifdef  DEBUG
16857c478bd9Sstevel@tonic-gate 				px_pokefault_cnt++;
16867c478bd9Sstevel@tonic-gate #endif
16877c478bd9Sstevel@tonic-gate 				break;
16887c478bd9Sstevel@tonic-gate 			}
16897c478bd9Sstevel@tonic-gate 		}
16907c478bd9Sstevel@tonic-gate 	}
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 	i_ddi_notrap((ddi_acc_handle_t)hp);
16937c478bd9Sstevel@tonic-gate 	pec_p->pec_ontrap_data = NULL;
1694f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
16957c478bd9Sstevel@tonic-gate 	i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
16967c478bd9Sstevel@tonic-gate 	hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED;
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 	return (err);
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate int
17037c478bd9Sstevel@tonic-gate px_lib_ctlops_poke(dev_info_t *dip, dev_info_t *rdip,
17047c478bd9Sstevel@tonic-gate     peekpoke_ctlops_t *in_args)
17057c478bd9Sstevel@tonic-gate {
17067c478bd9Sstevel@tonic-gate 	return (in_args->handle ? px_lib_do_caut_put(dip, rdip, in_args) :
17077c478bd9Sstevel@tonic-gate 	    px_lib_do_poke(dip, rdip, in_args));
17087c478bd9Sstevel@tonic-gate }
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17127c478bd9Sstevel@tonic-gate static int
17137c478bd9Sstevel@tonic-gate px_lib_do_peek(dev_info_t *dip, peekpoke_ctlops_t *in_args)
17147c478bd9Sstevel@tonic-gate {
1715f8d2de6bSjchu 	px_t *px_p = DIP_TO_STATE(dip);
1716f8d2de6bSjchu 	px_pec_t *pec_p = px_p->px_pec_p;
17177c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
17187c478bd9Sstevel@tonic-gate 	on_trap_data_t otd;
17197c478bd9Sstevel@tonic-gate 
1720f8d2de6bSjchu 	mutex_enter(&pec_p->pec_pokefault_mutex);
1721fc256490SJason Beloro 	if (px_fm_enter(px_p) != DDI_SUCCESS) {
1722fc256490SJason Beloro 		mutex_exit(&pec_p->pec_pokefault_mutex);
1723eae2e508Skrishnae 		return (DDI_FAILURE);
1724fc256490SJason Beloro 	}
1725f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK;
1726eae2e508Skrishnae 	px_fm_exit(px_p);
1727f8d2de6bSjchu 
17287c478bd9Sstevel@tonic-gate 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
17297c478bd9Sstevel@tonic-gate 		uintptr_t tramp = otd.ot_trampoline;
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = (uintptr_t)&peek_fault;
17327c478bd9Sstevel@tonic-gate 		err = do_peek(in_args->size, (void *)in_args->dev_addr,
17337c478bd9Sstevel@tonic-gate 		    (void *)in_args->host_addr);
17347c478bd9Sstevel@tonic-gate 		otd.ot_trampoline = tramp;
17357c478bd9Sstevel@tonic-gate 	} else
17367c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	no_trap();
1739f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
1740f8d2de6bSjchu 	mutex_exit(&pec_p->pec_pokefault_mutex);
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate #ifdef  DEBUG
17437c478bd9Sstevel@tonic-gate 	if (err == DDI_FAILURE)
17447c478bd9Sstevel@tonic-gate 		px_peekfault_cnt++;
17457c478bd9Sstevel@tonic-gate #endif
17467c478bd9Sstevel@tonic-gate 	return (err);
17477c478bd9Sstevel@tonic-gate }
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate static int
17517c478bd9Sstevel@tonic-gate px_lib_do_caut_get(dev_info_t *dip, peekpoke_ctlops_t *cautacc_ctlops_arg)
17527c478bd9Sstevel@tonic-gate {
17537c478bd9Sstevel@tonic-gate 	size_t size = cautacc_ctlops_arg->size;
17547c478bd9Sstevel@tonic-gate 	uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr;
17557c478bd9Sstevel@tonic-gate 	uintptr_t host_addr = cautacc_ctlops_arg->host_addr;
17567c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle;
17577c478bd9Sstevel@tonic-gate 	size_t repcount = cautacc_ctlops_arg->repcount;
17587c478bd9Sstevel@tonic-gate 	uint_t flags = cautacc_ctlops_arg->flags;
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	px_t *px_p = DIP_TO_STATE(dip);
17617c478bd9Sstevel@tonic-gate 	px_pec_t *pec_p = px_p->px_pec_p;
17627c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
17637c478bd9Sstevel@tonic-gate 
1764f8d2de6bSjchu 	/*
1765f8d2de6bSjchu 	 * Note that i_ndi_busop_access_enter ends up grabbing the pokefault
1766f8d2de6bSjchu 	 * mutex.
1767f8d2de6bSjchu 	 */
17687c478bd9Sstevel@tonic-gate 	i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
17697c478bd9Sstevel@tonic-gate 
1770f8d2de6bSjchu 	pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap;
1771f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED;
1772f8d2de6bSjchu 	hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED;
1773f8d2de6bSjchu 
17747c478bd9Sstevel@tonic-gate 	if (repcount == 1) {
17757c478bd9Sstevel@tonic-gate 		if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) {
17767c478bd9Sstevel@tonic-gate 			i_ddi_caut_get(size, (void *)dev_addr,
17777c478bd9Sstevel@tonic-gate 			    (void *)host_addr);
17787c478bd9Sstevel@tonic-gate 		} else {
17797c478bd9Sstevel@tonic-gate 			int i;
17807c478bd9Sstevel@tonic-gate 			uint8_t *ff_addr = (uint8_t *)host_addr;
17817c478bd9Sstevel@tonic-gate 			for (i = 0; i < size; i++)
17827c478bd9Sstevel@tonic-gate 				*ff_addr++ = 0xff;
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 			err = DDI_FAILURE;
17857c478bd9Sstevel@tonic-gate #ifdef  DEBUG
17867c478bd9Sstevel@tonic-gate 			px_peekfault_cnt++;
17877c478bd9Sstevel@tonic-gate #endif
17887c478bd9Sstevel@tonic-gate 		}
17897c478bd9Sstevel@tonic-gate 	} else {
17907c478bd9Sstevel@tonic-gate 		if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) {
17917c478bd9Sstevel@tonic-gate 			for (; repcount; repcount--) {
17927c478bd9Sstevel@tonic-gate 				i_ddi_caut_get(size, (void *)dev_addr,
17937c478bd9Sstevel@tonic-gate 				    (void *)host_addr);
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 				host_addr += size;
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 				if (flags == DDI_DEV_AUTOINCR)
17987c478bd9Sstevel@tonic-gate 					dev_addr += size;
17997c478bd9Sstevel@tonic-gate 			}
18007c478bd9Sstevel@tonic-gate 		} else {
18017c478bd9Sstevel@tonic-gate 			err = DDI_FAILURE;
18027c478bd9Sstevel@tonic-gate #ifdef  DEBUG
18037c478bd9Sstevel@tonic-gate 			px_peekfault_cnt++;
18047c478bd9Sstevel@tonic-gate #endif
18057c478bd9Sstevel@tonic-gate 		}
18067c478bd9Sstevel@tonic-gate 	}
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	i_ddi_notrap((ddi_acc_handle_t)hp);
18097c478bd9Sstevel@tonic-gate 	pec_p->pec_ontrap_data = NULL;
1810f8d2de6bSjchu 	pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED;
18117c478bd9Sstevel@tonic-gate 	i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp);
18127c478bd9Sstevel@tonic-gate 	hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED;
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	return (err);
18157c478bd9Sstevel@tonic-gate }
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate /*ARGSUSED*/
18187c478bd9Sstevel@tonic-gate int
18197c478bd9Sstevel@tonic-gate px_lib_ctlops_peek(dev_info_t *dip, dev_info_t *rdip,
18207c478bd9Sstevel@tonic-gate     peekpoke_ctlops_t *in_args, void *result)
18217c478bd9Sstevel@tonic-gate {
18227c478bd9Sstevel@tonic-gate 	result = (void *)in_args->host_addr;
18237c478bd9Sstevel@tonic-gate 	return (in_args->handle ? px_lib_do_caut_get(dip, in_args) :
18247c478bd9Sstevel@tonic-gate 	    px_lib_do_peek(dip, in_args));
18257c478bd9Sstevel@tonic-gate }
18261a887b2eSjchu 
18277c478bd9Sstevel@tonic-gate /*
18287c478bd9Sstevel@tonic-gate  * implements PPM interface
18297c478bd9Sstevel@tonic-gate  */
18307c478bd9Sstevel@tonic-gate int
18317c478bd9Sstevel@tonic-gate px_lib_pmctl(int cmd, px_t *px_p)
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate 	ASSERT((cmd & ~PPMREQ_MASK) == PPMREQ);
18347c478bd9Sstevel@tonic-gate 	switch (cmd) {
18357c478bd9Sstevel@tonic-gate 	case PPMREQ_PRE_PWR_OFF:
18367c478bd9Sstevel@tonic-gate 		/*
18377c478bd9Sstevel@tonic-gate 		 * Currently there is no device power management for
18387c478bd9Sstevel@tonic-gate 		 * the root complex (fire). When there is we need to make
18397c478bd9Sstevel@tonic-gate 		 * sure that it is at full power before trying to send the
18407c478bd9Sstevel@tonic-gate 		 * PME_Turn_Off message.
18417c478bd9Sstevel@tonic-gate 		 */
18427c478bd9Sstevel@tonic-gate 		DBG(DBG_PWR, px_p->px_dip,
18437c478bd9Sstevel@tonic-gate 		    "ioctl: request to send PME_Turn_Off\n");
18447c478bd9Sstevel@tonic-gate 		return (px_goto_l23ready(px_p));
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate 	case PPMREQ_PRE_PWR_ON:
18471a887b2eSjchu 		DBG(DBG_PWR, px_p->px_dip, "ioctl: PRE_PWR_ON request\n");
18481a887b2eSjchu 		return (px_pre_pwron_check(px_p));
18491a887b2eSjchu 
18507c478bd9Sstevel@tonic-gate 	case PPMREQ_POST_PWR_ON:
18511a887b2eSjchu 		DBG(DBG_PWR, px_p->px_dip, "ioctl: POST_PWR_ON request\n");
18521a887b2eSjchu 		return (px_goto_l0(px_p));
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	default:
18557c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate }
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate /*
18607c478bd9Sstevel@tonic-gate  * sends PME_Turn_Off message to put the link in L2/L3 ready state.
18617c478bd9Sstevel@tonic-gate  * called by px_ioctl.
18627c478bd9Sstevel@tonic-gate  * returns DDI_SUCCESS or DDI_FAILURE
18637c478bd9Sstevel@tonic-gate  * 1. Wait for link to be in L1 state (link status reg)
18647c478bd9Sstevel@tonic-gate  * 2. write to PME_Turn_off reg to boradcast
18657c478bd9Sstevel@tonic-gate  * 3. set timeout
18667c478bd9Sstevel@tonic-gate  * 4. If timeout, return failure.
18677c478bd9Sstevel@tonic-gate  * 5. If PM_TO_Ack, wait till link is in L2/L3 ready
18687c478bd9Sstevel@tonic-gate  */
18697c478bd9Sstevel@tonic-gate static int
18707c478bd9Sstevel@tonic-gate px_goto_l23ready(px_t *px_p)
18717c478bd9Sstevel@tonic-gate {
18727c478bd9Sstevel@tonic-gate 	pcie_pwr_t	*pwr_p;
1873f8d2de6bSjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
1874f8d2de6bSjchu 	caddr_t	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
18757c478bd9Sstevel@tonic-gate 	int		ret = DDI_SUCCESS;
18767c478bd9Sstevel@tonic-gate 	clock_t		end, timeleft;
18771a887b2eSjchu 	int		mutex_held = 1;
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	/* If no PM info, return failure */
18807c478bd9Sstevel@tonic-gate 	if (!PCIE_PMINFO(px_p->px_dip) ||
18817c478bd9Sstevel@tonic-gate 	    !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip)))
18827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	mutex_enter(&pwr_p->pwr_lock);
18851a887b2eSjchu 	mutex_enter(&px_p->px_l23ready_lock);
18867c478bd9Sstevel@tonic-gate 	/* Clear the PME_To_ACK receieved flag */
18871a887b2eSjchu 	px_p->px_pm_flags &= ~PX_PMETOACK_RECVD;
18883ee8f295Smg140465 	/*
18893ee8f295Smg140465 	 * When P25 is the downstream device, after receiving
18903ee8f295Smg140465 	 * PME_To_ACK, fire will go to Detect state, which causes
18913ee8f295Smg140465 	 * the link down event. Inform FMA that this is expected.
18923ee8f295Smg140465 	 * In case of all other cards complaint with the pci express
18933ee8f295Smg140465 	 * spec, this will happen when the power is re-applied. FMA
18943ee8f295Smg140465 	 * code will clear this flag after one instance of LDN. Since
18953ee8f295Smg140465 	 * there will not be a LDN event for the spec compliant cards,
18963ee8f295Smg140465 	 * we need to clear the flag after receiving PME_To_ACK.
18973ee8f295Smg140465 	 */
18983ee8f295Smg140465 	px_p->px_pm_flags |= PX_LDN_EXPECTED;
18997c478bd9Sstevel@tonic-gate 	if (px_send_pme_turnoff(csr_base) != DDI_SUCCESS) {
19007c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
19017c478bd9Sstevel@tonic-gate 		goto l23ready_done;
19027c478bd9Sstevel@tonic-gate 	}
19031a887b2eSjchu 	px_p->px_pm_flags |= PX_PME_TURNOFF_PENDING;
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	end = ddi_get_lbolt() + drv_usectohz(px_pme_to_ack_timeout);
19061a887b2eSjchu 	while (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) {
19071a887b2eSjchu 		timeleft = cv_timedwait(&px_p->px_l23ready_cv,
19081a887b2eSjchu 		    &px_p->px_l23ready_lock, end);
19097c478bd9Sstevel@tonic-gate 		/*
19107c478bd9Sstevel@tonic-gate 		 * if cv_timedwait returns -1, it is either
19117c478bd9Sstevel@tonic-gate 		 * 1) timed out or
19127c478bd9Sstevel@tonic-gate 		 * 2) there was a pre-mature wakeup but by the time
19137c478bd9Sstevel@tonic-gate 		 * cv_timedwait is called again end < lbolt i.e.
19147c478bd9Sstevel@tonic-gate 		 * end is in the past.
19157c478bd9Sstevel@tonic-gate 		 * 3) By the time we make first cv_timedwait call,
19167c478bd9Sstevel@tonic-gate 		 * end < lbolt is true.
19177c478bd9Sstevel@tonic-gate 		 */
19187c478bd9Sstevel@tonic-gate 		if (timeleft == -1)
19197c478bd9Sstevel@tonic-gate 			break;
19207c478bd9Sstevel@tonic-gate 	}
19211a887b2eSjchu 	if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) {
19227c478bd9Sstevel@tonic-gate 		/*
19237c478bd9Sstevel@tonic-gate 		 * Either timedout or interrupt didn't get a
19247c478bd9Sstevel@tonic-gate 		 * chance to grab the mutex and set the flag.
19257c478bd9Sstevel@tonic-gate 		 * release the mutex and delay for sometime.
19267c478bd9Sstevel@tonic-gate 		 * This will 1) give a chance for interrupt to
19277c478bd9Sstevel@tonic-gate 		 * set the flag 2) creates a delay between two
19287c478bd9Sstevel@tonic-gate 		 * consequetive requests.
19297c478bd9Sstevel@tonic-gate 		 */
19301a887b2eSjchu 		mutex_exit(&px_p->px_l23ready_lock);
1931f9721e07Sjchu 		delay(drv_usectohz(50 * PX_MSEC_TO_USEC));
19321a887b2eSjchu 		mutex_held = 0;
19331a887b2eSjchu 		if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) {
19347c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
19357c478bd9Sstevel@tonic-gate 			DBG(DBG_PWR, px_p->px_dip, " Timed out while waiting"
19367c478bd9Sstevel@tonic-gate 			    " for PME_TO_ACK\n");
19377c478bd9Sstevel@tonic-gate 		}
19387c478bd9Sstevel@tonic-gate 	}
19393ee8f295Smg140465 	px_p->px_pm_flags &=
19403ee8f295Smg140465 	    ~(PX_PME_TURNOFF_PENDING | PX_PMETOACK_RECVD | PX_LDN_EXPECTED);
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate l23ready_done:
19431a887b2eSjchu 	if (mutex_held)
19441a887b2eSjchu 		mutex_exit(&px_p->px_l23ready_lock);
19451a887b2eSjchu 	/*
19461a887b2eSjchu 	 * Wait till link is in L1 idle, if sending PME_Turn_Off
19471a887b2eSjchu 	 * was succesful.
19481a887b2eSjchu 	 */
19491a887b2eSjchu 	if (ret == DDI_SUCCESS) {
19501a887b2eSjchu 		if (px_link_wait4l1idle(csr_base) != DDI_SUCCESS) {
19511a887b2eSjchu 			DBG(DBG_PWR, px_p->px_dip, " Link is not at L1"
19521a887b2eSjchu 			    " even though we received PME_To_ACK.\n");
19533ee8f295Smg140465 			/*
19543ee8f295Smg140465 			 * Workaround for hardware bug with P25.
19553ee8f295Smg140465 			 * Due to a hardware bug with P25, link state
19563ee8f295Smg140465 			 * will be Detect state rather than L1 after
19573ee8f295Smg140465 			 * link is transitioned to L23Ready state. Since
19583ee8f295Smg140465 			 * we don't know whether link is L23ready state
19593ee8f295Smg140465 			 * without Fire's state being L1_idle, we delay
19603ee8f295Smg140465 			 * here just to make sure that we wait till link
19613ee8f295Smg140465 			 * is transitioned to L23Ready state.
19623ee8f295Smg140465 			 */
1963f9721e07Sjchu 			delay(drv_usectohz(100 * PX_MSEC_TO_USEC));
19643ee8f295Smg140465 		}
19651a887b2eSjchu 		pwr_p->pwr_link_lvl = PM_LEVEL_L3;
19661a887b2eSjchu 
19671a887b2eSjchu 	}
19687c478bd9Sstevel@tonic-gate 	mutex_exit(&pwr_p->pwr_lock);
19697c478bd9Sstevel@tonic-gate 	return (ret);
19707c478bd9Sstevel@tonic-gate }
19717c478bd9Sstevel@tonic-gate 
19721a887b2eSjchu /*
19731a887b2eSjchu  * Message interrupt handler intended to be shared for both
19741a887b2eSjchu  * PME and PME_TO_ACK msg handling, currently only handles
19751a887b2eSjchu  * PME_To_ACK message.
19761a887b2eSjchu  */
19771a887b2eSjchu uint_t
19781a887b2eSjchu px_pmeq_intr(caddr_t arg)
19791a887b2eSjchu {
19801a887b2eSjchu 	px_t	*px_p = (px_t *)arg;
19811a887b2eSjchu 
19823ee8f295Smg140465 	DBG(DBG_PWR, px_p->px_dip, " PME_To_ACK received \n");
19831a887b2eSjchu 	mutex_enter(&px_p->px_l23ready_lock);
19841a887b2eSjchu 	cv_broadcast(&px_p->px_l23ready_cv);
19851a887b2eSjchu 	if (px_p->px_pm_flags & PX_PME_TURNOFF_PENDING) {
19861a887b2eSjchu 		px_p->px_pm_flags |= PX_PMETOACK_RECVD;
19871a887b2eSjchu 	} else {
19881a887b2eSjchu 		/*
19891a887b2eSjchu 		 * This maybe the second ack received. If so then,
19901a887b2eSjchu 		 * we should be receiving it during wait4L1 stage.
19911a887b2eSjchu 		 */
19921a887b2eSjchu 		px_p->px_pmetoack_ignored++;
19931a887b2eSjchu 	}
19941a887b2eSjchu 	mutex_exit(&px_p->px_l23ready_lock);
19951a887b2eSjchu 	return (DDI_INTR_CLAIMED);
19961a887b2eSjchu }
19971a887b2eSjchu 
19981a887b2eSjchu static int
19991a887b2eSjchu px_pre_pwron_check(px_t *px_p)
20001a887b2eSjchu {
20011a887b2eSjchu 	pcie_pwr_t	*pwr_p;
20021a887b2eSjchu 
20031a887b2eSjchu 	/* If no PM info, return failure */
20041a887b2eSjchu 	if (!PCIE_PMINFO(px_p->px_dip) ||
20051a887b2eSjchu 	    !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip)))
20061a887b2eSjchu 		return (DDI_FAILURE);
20071a887b2eSjchu 
20083ee8f295Smg140465 	/*
20093ee8f295Smg140465 	 * For the spec compliant downstream cards link down
20103ee8f295Smg140465 	 * is expected when the device is powered on.
20113ee8f295Smg140465 	 */
20123ee8f295Smg140465 	px_p->px_pm_flags |= PX_LDN_EXPECTED;
20131a887b2eSjchu 	return (pwr_p->pwr_link_lvl == PM_LEVEL_L3 ? DDI_SUCCESS : DDI_FAILURE);
20141a887b2eSjchu }
20151a887b2eSjchu 
20161a887b2eSjchu static int
20171a887b2eSjchu px_goto_l0(px_t *px_p)
20181a887b2eSjchu {
20191a887b2eSjchu 	pcie_pwr_t	*pwr_p;
20201a887b2eSjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
20211a887b2eSjchu 	caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
20221a887b2eSjchu 	int		ret = DDI_SUCCESS;
2023f9721e07Sjchu 	uint64_t	time_spent = 0;
20241a887b2eSjchu 
20251a887b2eSjchu 	/* If no PM info, return failure */
20261a887b2eSjchu 	if (!PCIE_PMINFO(px_p->px_dip) ||
20271a887b2eSjchu 	    !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip)))
20281a887b2eSjchu 		return (DDI_FAILURE);
20291a887b2eSjchu 
20301a887b2eSjchu 	mutex_enter(&pwr_p->pwr_lock);
20313ee8f295Smg140465 	/*
2032f9721e07Sjchu 	 * The following link retrain activity will cause LDN and LUP event.
2033f9721e07Sjchu 	 * Receiving LDN prior to receiving LUP is expected, not an error in
2034f9721e07Sjchu 	 * this case.  Receiving LUP indicates link is fully up to support
2035f9721e07Sjchu 	 * powering up down stream device, and of course any further LDN and
2036f9721e07Sjchu 	 * LUP outside this context will be error.
20373ee8f295Smg140465 	 */
2038f9721e07Sjchu 	px_p->px_lup_pending = 1;
20391a887b2eSjchu 	if (px_link_retrain(csr_base) != DDI_SUCCESS) {
20401a887b2eSjchu 		ret = DDI_FAILURE;
20411a887b2eSjchu 		goto l0_done;
20421a887b2eSjchu 	}
20431a887b2eSjchu 
2044f9721e07Sjchu 	/* LUP event takes the order of 15ms amount of time to occur */
2045f9721e07Sjchu 	for (; px_p->px_lup_pending && (time_spent < px_lup_poll_to);
2046f9721e07Sjchu 	    time_spent += px_lup_poll_interval)
2047f9721e07Sjchu 		drv_usecwait(px_lup_poll_interval);
2048f9721e07Sjchu 	if (px_p->px_lup_pending)
20491a887b2eSjchu 		ret = DDI_FAILURE;
20501a887b2eSjchu l0_done:
20511a887b2eSjchu 	px_enable_detect_quiet(csr_base);
20523ee8f295Smg140465 	if (ret == DDI_SUCCESS)
20533ee8f295Smg140465 		pwr_p->pwr_link_lvl = PM_LEVEL_L0;
20541a887b2eSjchu 	mutex_exit(&pwr_p->pwr_lock);
20551a887b2eSjchu 	return (ret);
20561a887b2eSjchu }
20571a887b2eSjchu 
20587c478bd9Sstevel@tonic-gate /*
20597c478bd9Sstevel@tonic-gate  * Extract the drivers binding name to identify which chip we're binding to.
20607c478bd9Sstevel@tonic-gate  * Whenever a new bus bridge is created, the driver alias entry should be
20617c478bd9Sstevel@tonic-gate  * added here to identify the device if needed.  If a device isn't added,
20627c478bd9Sstevel@tonic-gate  * the identity defaults to PX_CHIP_UNIDENTIFIED.
20637c478bd9Sstevel@tonic-gate  */
20647c478bd9Sstevel@tonic-gate static uint32_t
20657e1db6d2Sschwartz px_identity_init(px_t *px_p)
20667c478bd9Sstevel@tonic-gate {
20677c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = px_p->px_dip;
20687c478bd9Sstevel@tonic-gate 	char		*name = ddi_binding_name(dip);
20697c478bd9Sstevel@tonic-gate 	uint32_t	revision = 0;
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 	revision = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
20727c478bd9Sstevel@tonic-gate 	    "module-revision#", 0);
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	/* Check for Fire driver binding name */
20757e1db6d2Sschwartz 	if (strcmp(name, "pciex108e,80f0") == 0) {
20767e1db6d2Sschwartz 		DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: "
20777e1db6d2Sschwartz 		    "(FIRE), module-revision %d\n", NAMEINST(dip),
20787e1db6d2Sschwartz 		    revision);
20797c478bd9Sstevel@tonic-gate 
20807e1db6d2Sschwartz 		return ((revision >= FIRE_MOD_REV_20) ?
20817e1db6d2Sschwartz 		    PX_CHIP_FIRE : PX_CHIP_UNIDENTIFIED);
20827c478bd9Sstevel@tonic-gate 	}
20837c478bd9Sstevel@tonic-gate 
208425cf1a30Sjl139090 	/* Check for Oberon driver binding name */
208525cf1a30Sjl139090 	if (strcmp(name, "pciex108e,80f8") == 0) {
20867e1db6d2Sschwartz 		DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: "
20877e1db6d2Sschwartz 		    "(OBERON), module-revision %d\n", NAMEINST(dip),
20887e1db6d2Sschwartz 		    revision);
208925cf1a30Sjl139090 
20907e1db6d2Sschwartz 		return (PX_CHIP_OBERON);
209125cf1a30Sjl139090 	}
209225cf1a30Sjl139090 
20937c478bd9Sstevel@tonic-gate 	DBG(DBG_ATTACH, dip, "%s%d: Unknown PCI Express Host bridge %s %x\n",
20947c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip), name, revision);
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate 	return (PX_CHIP_UNIDENTIFIED);
20977c478bd9Sstevel@tonic-gate }
2098f8d2de6bSjchu 
2099f8d2de6bSjchu int
2100f8d2de6bSjchu px_err_add_intr(px_fault_t *px_fault_p)
2101f8d2de6bSjchu {
2102f8d2de6bSjchu 	dev_info_t	*dip = px_fault_p->px_fh_dip;
2103f8d2de6bSjchu 	px_t		*px_p = DIP_TO_STATE(dip);
2104f8d2de6bSjchu 
2105f8d2de6bSjchu 	VERIFY(add_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL,
2106b0fc0e77Sgovinda 	    (intrfunc)px_fault_p->px_err_func, (caddr_t)px_fault_p,
2107b0fc0e77Sgovinda 	    NULL, NULL) == 0);
2108f8d2de6bSjchu 
2109f8d2de6bSjchu 	px_ib_intr_enable(px_p, intr_dist_cpuid(), px_fault_p->px_intr_ino);
2110f8d2de6bSjchu 
2111f8d2de6bSjchu 	return (DDI_SUCCESS);
2112f8d2de6bSjchu }
2113f8d2de6bSjchu 
2114f8d2de6bSjchu void
2115f8d2de6bSjchu px_err_rem_intr(px_fault_t *px_fault_p)
2116f8d2de6bSjchu {
2117f8d2de6bSjchu 	dev_info_t	*dip = px_fault_p->px_fh_dip;
2118f8d2de6bSjchu 	px_t		*px_p = DIP_TO_STATE(dip);
2119f8d2de6bSjchu 
2120f8d2de6bSjchu 	px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino,
2121f8d2de6bSjchu 	    IB_INTR_WAIT);
21229c75c6bfSgovinda 
2123b0fc0e77Sgovinda 	VERIFY(rem_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL) == 0);
2124f8d2de6bSjchu }
2125f8d2de6bSjchu 
212601689544Sjchu /*
2127a3c68edcSjchu  * px_cb_intr_redist() - sun4u only, CB interrupt redistribution
2128a3c68edcSjchu  */
2129a3c68edcSjchu void
2130a3c68edcSjchu px_cb_intr_redist(void *arg)
2131a3c68edcSjchu {
2132a3c68edcSjchu 	px_cb_t		*cb_p = (px_cb_t *)arg;
2133a3c68edcSjchu 	px_cb_list_t	*pxl;
2134a3c68edcSjchu 	px_t		*pxp = NULL;
2135a3c68edcSjchu 	px_fault_t	*f_p = NULL;
2136a3c68edcSjchu 	uint32_t	new_cpuid;
2137a3c68edcSjchu 	intr_valid_state_t	enabled = 0;
2138a3c68edcSjchu 
2139a3c68edcSjchu 	mutex_enter(&cb_p->cb_mutex);
2140a3c68edcSjchu 
2141a3c68edcSjchu 	pxl = cb_p->pxl;
2142a3c68edcSjchu 	if (!pxl)
2143a3c68edcSjchu 		goto cb_done;
2144a3c68edcSjchu 
2145a3c68edcSjchu 	pxp = pxl->pxp;
2146a3c68edcSjchu 	f_p = &pxp->px_cb_fault;
2147a3c68edcSjchu 	for (; pxl && (f_p->px_fh_sysino != cb_p->sysino); ) {
2148a3c68edcSjchu 		pxl = pxl->next;
2149a3c68edcSjchu 		pxp = pxl->pxp;
2150a3c68edcSjchu 		f_p = &pxp->px_cb_fault;
2151a3c68edcSjchu 	}
2152a3c68edcSjchu 	if (pxl == NULL)
2153a3c68edcSjchu 		goto cb_done;
2154a3c68edcSjchu 
2155a3c68edcSjchu 	new_cpuid =  intr_dist_cpuid();
2156a3c68edcSjchu 	if (new_cpuid == cb_p->cpuid)
2157a3c68edcSjchu 		goto cb_done;
2158a3c68edcSjchu 
2159a3c68edcSjchu 	if ((px_lib_intr_getvalid(pxp->px_dip, f_p->px_fh_sysino, &enabled)
2160a3c68edcSjchu 	    != DDI_SUCCESS) || !enabled) {
2161a3c68edcSjchu 		DBG(DBG_IB, pxp->px_dip, "px_cb_intr_redist: CB not enabled, "
2162a3c68edcSjchu 		    "sysino(0x%x)\n", f_p->px_fh_sysino);
2163a3c68edcSjchu 		goto cb_done;
2164a3c68edcSjchu 	}
2165a3c68edcSjchu 
2166a3c68edcSjchu 	PX_INTR_DISABLE(pxp->px_dip, f_p->px_fh_sysino);
2167a3c68edcSjchu 
2168a3c68edcSjchu 	cb_p->cpuid = new_cpuid;
2169a3c68edcSjchu 	cb_p->sysino = f_p->px_fh_sysino;
2170a3c68edcSjchu 	PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid);
2171a3c68edcSjchu 
2172a3c68edcSjchu cb_done:
2173a3c68edcSjchu 	mutex_exit(&cb_p->cb_mutex);
2174a3c68edcSjchu }
2175a3c68edcSjchu 
2176a3c68edcSjchu /*
217701689544Sjchu  * px_cb_add_intr() - Called from attach(9E) to create CB if not yet
217801689544Sjchu  * created, to add CB interrupt vector always, but enable only once.
217901689544Sjchu  */
218001689544Sjchu int
218101689544Sjchu px_cb_add_intr(px_fault_t *fault_p)
218201689544Sjchu {
218301689544Sjchu 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip);
218401689544Sjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
218525cf1a30Sjl139090 	px_cb_t		*cb_p = (px_cb_t *)px_get_cb(fault_p->px_fh_dip);
218601689544Sjchu 	px_cb_list_t	*pxl, *pxl_new;
2187a3c68edcSjchu 	boolean_t	is_proxy = B_FALSE;
218801689544Sjchu 
2189a3c68edcSjchu 	/* create cb */
219001689544Sjchu 	if (cb_p == NULL) {
219101689544Sjchu 		cb_p = kmem_zalloc(sizeof (px_cb_t), KM_SLEEP);
2192a3c68edcSjchu 
2193a3c68edcSjchu 		mutex_init(&cb_p->cb_mutex, NULL, MUTEX_DRIVER,
2194a3c68edcSjchu 		    (void *) ipltospl(FM_ERR_PIL));
2195a3c68edcSjchu 
219601689544Sjchu 		cb_p->px_cb_func = px_cb_intr;
219701689544Sjchu 		pxu_p->px_cb_p = cb_p;
219825cf1a30Sjl139090 		px_set_cb(fault_p->px_fh_dip, (uint64_t)cb_p);
219908a74c0dSschwartz 
220008a74c0dSschwartz 		/* px_lib_dev_init allows only FIRE and OBERON */
220108a74c0dSschwartz 		px_err_reg_enable(
220208a74c0dSschwartz 		    (pxu_p->chip_type == PX_CHIP_FIRE) ?
220308a74c0dSschwartz 		    PX_ERR_JBC : PX_ERR_UBC,
220408a74c0dSschwartz 		    pxu_p->px_address[PX_REG_XBC]);
220501689544Sjchu 	} else
220601689544Sjchu 		pxu_p->px_cb_p = cb_p;
220701689544Sjchu 
2208a3c68edcSjchu 	/* register cb interrupt */
220901689544Sjchu 	VERIFY(add_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL,
2210b0fc0e77Sgovinda 	    (intrfunc)cb_p->px_cb_func, (caddr_t)cb_p, NULL, NULL) == 0);
221101689544Sjchu 
2212a3c68edcSjchu 
2213a3c68edcSjchu 	/* update cb list */
2214a3c68edcSjchu 	mutex_enter(&cb_p->cb_mutex);
221501689544Sjchu 	if (cb_p->pxl == NULL) {
2216a3c68edcSjchu 		is_proxy = B_TRUE;
221701689544Sjchu 		pxl = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP);
221801689544Sjchu 		pxl->pxp = px_p;
221901689544Sjchu 		cb_p->pxl = pxl;
222001689544Sjchu 		cb_p->sysino = fault_p->px_fh_sysino;
2221a3c68edcSjchu 		cb_p->cpuid = intr_dist_cpuid();
222201689544Sjchu 	} else {
222301689544Sjchu 		/*
222401689544Sjchu 		 * Find the last pxl or
2225a3c68edcSjchu 		 * stop short at encountering a redundent entry, or
222601689544Sjchu 		 * both.
222701689544Sjchu 		 */
222801689544Sjchu 		pxl = cb_p->pxl;
2229eae2e508Skrishnae 		for (; !(pxl->pxp == px_p) && pxl->next; pxl = pxl->next) {};
2230a3c68edcSjchu 		ASSERT(pxl->pxp != px_p);
223101689544Sjchu 
223201689544Sjchu 		/* add to linked list */
223301689544Sjchu 		pxl_new = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP);
223401689544Sjchu 		pxl_new->pxp = px_p;
223501689544Sjchu 		pxl->next = pxl_new;
223601689544Sjchu 	}
223701689544Sjchu 	cb_p->attachcnt++;
223801689544Sjchu 	mutex_exit(&cb_p->cb_mutex);
223901689544Sjchu 
2240a3c68edcSjchu 	if (is_proxy) {
2241a3c68edcSjchu 		/* add to interrupt redistribution list */
2242a3c68edcSjchu 		intr_dist_add(px_cb_intr_redist, cb_p);
2243a3c68edcSjchu 
2244a3c68edcSjchu 		/* enable cb hw interrupt */
2245a3c68edcSjchu 		px_ib_intr_enable(px_p, cb_p->cpuid, fault_p->px_intr_ino);
2246a3c68edcSjchu 	}
2247a3c68edcSjchu 
224801689544Sjchu 	return (DDI_SUCCESS);
224901689544Sjchu }
225001689544Sjchu 
225101689544Sjchu /*
225201689544Sjchu  * px_cb_rem_intr() - Called from detach(9E) to remove its CB
225301689544Sjchu  * interrupt vector, to shift proxy to the next available px,
225401689544Sjchu  * or disable CB interrupt when itself is the last.
225501689544Sjchu  */
225601689544Sjchu void
225701689544Sjchu px_cb_rem_intr(px_fault_t *fault_p)
225801689544Sjchu {
225901689544Sjchu 	px_t		*px_p = DIP_TO_STATE(fault_p->px_fh_dip), *pxp;
226001689544Sjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
226101689544Sjchu 	px_cb_t		*cb_p = PX2CB(px_p);
226201689544Sjchu 	px_cb_list_t	*pxl, *prev;
226301689544Sjchu 	px_fault_t	*f_p;
226401689544Sjchu 
226501689544Sjchu 	ASSERT(cb_p->pxl);
226601689544Sjchu 
2267a3c68edcSjchu 	/* find and remove this px, and update cb list */
226801689544Sjchu 	mutex_enter(&cb_p->cb_mutex);
226901689544Sjchu 
227001689544Sjchu 	pxl = cb_p->pxl;
227101689544Sjchu 	if (pxl->pxp == px_p) {
227201689544Sjchu 		cb_p->pxl = pxl->next;
227301689544Sjchu 	} else {
227401689544Sjchu 		prev = pxl;
227501689544Sjchu 		pxl = pxl->next;
2276eae2e508Skrishnae 		for (; pxl && (pxl->pxp != px_p); prev = pxl, pxl = pxl->next) {
2277eae2e508Skrishnae 		};
227801689544Sjchu 		if (!pxl) {
227901689544Sjchu 			cmn_err(CE_WARN, "px_cb_rem_intr: can't find px_p 0x%p "
22807389e29fSjchu 			    "in registered CB list.", (void *)px_p);
2281a3c68edcSjchu 			mutex_exit(&cb_p->cb_mutex);
228201689544Sjchu 			return;
228301689544Sjchu 		}
228401689544Sjchu 		prev->next = pxl->next;
228501689544Sjchu 	}
2286a3c68edcSjchu 	pxu_p->px_cb_p = NULL;
2287a3c68edcSjchu 	cb_p->attachcnt--;
228801689544Sjchu 	kmem_free(pxl, sizeof (px_cb_list_t));
2289a3c68edcSjchu 	mutex_exit(&cb_p->cb_mutex);
229001689544Sjchu 
2291a3c68edcSjchu 	/* disable cb hw interrupt */
2292a3c68edcSjchu 	if (fault_p->px_fh_sysino == cb_p->sysino)
229301689544Sjchu 		px_ib_intr_disable(px_p->px_ib_p, fault_p->px_intr_ino,
229401689544Sjchu 		    IB_INTR_WAIT);
229501689544Sjchu 
2296a3c68edcSjchu 	/* if last px, remove from interrupt redistribution list */
2297a3c68edcSjchu 	if (cb_p->pxl == NULL)
2298a3c68edcSjchu 		intr_dist_rem(px_cb_intr_redist, cb_p);
2299a3c68edcSjchu 
2300a3c68edcSjchu 	/* de-register interrupt */
2301a3c68edcSjchu 	VERIFY(rem_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL) == 0);
2302a3c68edcSjchu 
2303a3c68edcSjchu 	/* if not last px, assign next px to manage cb */
2304a3c68edcSjchu 	mutex_enter(&cb_p->cb_mutex);
230501689544Sjchu 	if (cb_p->pxl) {
2306a3c68edcSjchu 		if (fault_p->px_fh_sysino == cb_p->sysino) {
230701689544Sjchu 			pxp = cb_p->pxl->pxp;
230801689544Sjchu 			f_p = &pxp->px_cb_fault;
230901689544Sjchu 			cb_p->sysino = f_p->px_fh_sysino;
231001689544Sjchu 
231101689544Sjchu 			PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid);
23127389e29fSjchu 			(void) px_lib_intr_setstate(pxp->px_dip, cb_p->sysino,
231301689544Sjchu 			    INTR_IDLE_STATE);
231401689544Sjchu 		}
231501689544Sjchu 		mutex_exit(&cb_p->cb_mutex);
231601689544Sjchu 		return;
231701689544Sjchu 	}
2318a3c68edcSjchu 
2319a3c68edcSjchu 	/* clean up after the last px */
232001689544Sjchu 	mutex_exit(&cb_p->cb_mutex);
232101689544Sjchu 
232208a74c0dSschwartz 	/* px_lib_dev_init allows only FIRE and OBERON */
232308a74c0dSschwartz 	px_err_reg_disable(
232408a74c0dSschwartz 	    (pxu_p->chip_type == PX_CHIP_FIRE) ? PX_ERR_JBC : PX_ERR_UBC,
232508a74c0dSschwartz 	    pxu_p->px_address[PX_REG_XBC]);
232608a74c0dSschwartz 
232701689544Sjchu 	mutex_destroy(&cb_p->cb_mutex);
232825cf1a30Sjl139090 	px_set_cb(fault_p->px_fh_dip, 0ull);
232901689544Sjchu 	kmem_free(cb_p, sizeof (px_cb_t));
233001689544Sjchu }
233101689544Sjchu 
233201689544Sjchu /*
233301689544Sjchu  * px_cb_intr() - sun4u only,  CB interrupt dispatcher
233401689544Sjchu  */
233501689544Sjchu uint_t
233601689544Sjchu px_cb_intr(caddr_t arg)
233701689544Sjchu {
233801689544Sjchu 	px_cb_t		*cb_p = (px_cb_t *)arg;
2339a3c68edcSjchu 	px_t		*pxp;
2340a3c68edcSjchu 	px_fault_t	*f_p;
2341a3c68edcSjchu 	int		ret;
234268ac2337Sjl139090 
234301689544Sjchu 	mutex_enter(&cb_p->cb_mutex);
234401689544Sjchu 
2345a3c68edcSjchu 	if (!cb_p->pxl) {
234601689544Sjchu 		mutex_exit(&cb_p->cb_mutex);
2347a3c68edcSjchu 		return (DDI_INTR_UNCLAIMED);
234801689544Sjchu 	}
234901689544Sjchu 
2350a3c68edcSjchu 	pxp = cb_p->pxl->pxp;
2351a3c68edcSjchu 	f_p = &pxp->px_cb_fault;
2352a3c68edcSjchu 
2353a3c68edcSjchu 	ret = f_p->px_err_func((caddr_t)f_p);
235401689544Sjchu 
235501689544Sjchu 	mutex_exit(&cb_p->cb_mutex);
2356a3c68edcSjchu 	return (ret);
235701689544Sjchu }
235801689544Sjchu 
2359f8d2de6bSjchu #ifdef	FMA
2360f8d2de6bSjchu void
2361f8d2de6bSjchu px_fill_rc_status(px_fault_t *px_fault_p, pciex_rc_error_regs_t *rc_status)
2362f8d2de6bSjchu {
2363f8d2de6bSjchu 	/* populate the rc_status by reading the registers - TBD */
2364f8d2de6bSjchu }
2365f8d2de6bSjchu #endif /* FMA */
23668bc7d88aSet142600 
23678bc7d88aSet142600 /*
2368817a6df8Sjchu  * cpr callback
2369817a6df8Sjchu  *
2370817a6df8Sjchu  * disable fabric error msg interrupt prior to suspending
2371817a6df8Sjchu  * all device drivers; re-enable fabric error msg interrupt
2372817a6df8Sjchu  * after all devices are resumed.
2373817a6df8Sjchu  */
2374817a6df8Sjchu static boolean_t
2375817a6df8Sjchu px_cpr_callb(void *arg, int code)
2376817a6df8Sjchu {
2377817a6df8Sjchu 	px_t		*px_p = (px_t *)arg;
2378817a6df8Sjchu 	px_ib_t		*ib_p = px_p->px_ib_p;
2379817a6df8Sjchu 	px_pec_t	*pec_p = px_p->px_pec_p;
2380817a6df8Sjchu 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
2381817a6df8Sjchu 	caddr_t		csr_base;
2382817a6df8Sjchu 	devino_t	ce_ino, nf_ino, f_ino;
2383b0fc0e77Sgovinda 	px_ino_t	*ce_ino_p, *nf_ino_p, *f_ino_p;
2384817a6df8Sjchu 	uint64_t	imu_log_enable, imu_intr_enable;
2385817a6df8Sjchu 	uint64_t	imu_log_mask, imu_intr_mask;
2386817a6df8Sjchu 
2387817a6df8Sjchu 	ce_ino = px_msiqid_to_devino(px_p, pec_p->pec_corr_msg_msiq_id);
2388817a6df8Sjchu 	nf_ino = px_msiqid_to_devino(px_p, pec_p->pec_non_fatal_msg_msiq_id);
2389817a6df8Sjchu 	f_ino = px_msiqid_to_devino(px_p, pec_p->pec_fatal_msg_msiq_id);
2390817a6df8Sjchu 	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
2391817a6df8Sjchu 
2392817a6df8Sjchu 	imu_log_enable = CSR_XR(csr_base, IMU_ERROR_LOG_ENABLE);
2393817a6df8Sjchu 	imu_intr_enable = CSR_XR(csr_base, IMU_INTERRUPT_ENABLE);
2394817a6df8Sjchu 
2395817a6df8Sjchu 	imu_log_mask = BITMASK(IMU_ERROR_LOG_ENABLE_FATAL_MES_NOT_EN_LOG_EN) |
2396817a6df8Sjchu 	    BITMASK(IMU_ERROR_LOG_ENABLE_NONFATAL_MES_NOT_EN_LOG_EN) |
2397817a6df8Sjchu 	    BITMASK(IMU_ERROR_LOG_ENABLE_COR_MES_NOT_EN_LOG_EN);
2398817a6df8Sjchu 
2399817a6df8Sjchu 	imu_intr_mask =
2400817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_S_INT_EN) |
2401817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_S_INT_EN) |
2402817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_S_INT_EN) |
2403817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_P_INT_EN) |
2404817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_P_INT_EN) |
2405817a6df8Sjchu 	    BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_P_INT_EN);
2406817a6df8Sjchu 
2407817a6df8Sjchu 	switch (code) {
2408817a6df8Sjchu 	case CB_CODE_CPR_CHKPT:
2409817a6df8Sjchu 		/* disable imu rbne on corr/nonfatal/fatal errors */
2410817a6df8Sjchu 		CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE,
2411817a6df8Sjchu 		    imu_log_enable & (~imu_log_mask));
2412817a6df8Sjchu 
2413817a6df8Sjchu 		CSR_XS(csr_base, IMU_INTERRUPT_ENABLE,
2414817a6df8Sjchu 		    imu_intr_enable & (~imu_intr_mask));
2415817a6df8Sjchu 
2416817a6df8Sjchu 		/* disable CORR intr mapping */
2417817a6df8Sjchu 		px_ib_intr_disable(ib_p, ce_ino, IB_INTR_NOWAIT);
2418817a6df8Sjchu 
2419817a6df8Sjchu 		/* disable NON FATAL intr mapping */
2420817a6df8Sjchu 		px_ib_intr_disable(ib_p, nf_ino, IB_INTR_NOWAIT);
2421817a6df8Sjchu 
2422817a6df8Sjchu 		/* disable FATAL intr mapping */
2423817a6df8Sjchu 		px_ib_intr_disable(ib_p, f_ino, IB_INTR_NOWAIT);
2424817a6df8Sjchu 
2425817a6df8Sjchu 		break;
2426817a6df8Sjchu 
2427817a6df8Sjchu 	case CB_CODE_CPR_RESUME:
2428bf8fc234Set142600 		pxu_p->cpr_flag = PX_NOT_CPR;
2429817a6df8Sjchu 		mutex_enter(&ib_p->ib_ino_lst_mutex);
2430817a6df8Sjchu 
2431817a6df8Sjchu 		ce_ino_p = px_ib_locate_ino(ib_p, ce_ino);
2432817a6df8Sjchu 		nf_ino_p = px_ib_locate_ino(ib_p, nf_ino);
2433817a6df8Sjchu 		f_ino_p = px_ib_locate_ino(ib_p, f_ino);
2434817a6df8Sjchu 
2435817a6df8Sjchu 		/* enable CORR intr mapping */
2436817a6df8Sjchu 		if (ce_ino_p)
2437817a6df8Sjchu 			px_ib_intr_enable(px_p, ce_ino_p->ino_cpuid, ce_ino);
2438817a6df8Sjchu 		else
2439817a6df8Sjchu 			cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to "
2440817a6df8Sjchu 			    "reenable PCIe Correctable msg intr.\n");
2441817a6df8Sjchu 
2442817a6df8Sjchu 		/* enable NON FATAL intr mapping */
2443817a6df8Sjchu 		if (nf_ino_p)
2444817a6df8Sjchu 			px_ib_intr_enable(px_p, nf_ino_p->ino_cpuid, nf_ino);
2445817a6df8Sjchu 		else
2446817a6df8Sjchu 			cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to "
2447817a6df8Sjchu 			    "reenable PCIe Non Fatal msg intr.\n");
2448817a6df8Sjchu 
2449817a6df8Sjchu 		/* enable FATAL intr mapping */
2450817a6df8Sjchu 		if (f_ino_p)
2451817a6df8Sjchu 			px_ib_intr_enable(px_p, f_ino_p->ino_cpuid, f_ino);
2452817a6df8Sjchu 		else
2453817a6df8Sjchu 			cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to "
2454817a6df8Sjchu 			    "reenable PCIe Fatal msg intr.\n");
2455817a6df8Sjchu 
2456817a6df8Sjchu 		mutex_exit(&ib_p->ib_ino_lst_mutex);
2457817a6df8Sjchu 
2458817a6df8Sjchu 		/* enable corr/nonfatal/fatal not enable error */
2459817a6df8Sjchu 		CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE, (imu_log_enable |
2460817a6df8Sjchu 		    (imu_log_mask & px_imu_log_mask)));
2461817a6df8Sjchu 		CSR_XS(csr_base, IMU_INTERRUPT_ENABLE, (imu_intr_enable |
2462817a6df8Sjchu 		    (imu_intr_mask & px_imu_intr_mask)));
2463817a6df8Sjchu 
2464817a6df8Sjchu 		break;
2465817a6df8Sjchu 	}
2466817a6df8Sjchu 
2467817a6df8Sjchu 	return (B_TRUE);
2468817a6df8Sjchu }
2469817a6df8Sjchu 
247025cf1a30Sjl139090 uint64_t
2471d3533785Sschwartz px_get_rng_parent_hi_mask(px_t *px_p)
247225cf1a30Sjl139090 {
247325cf1a30Sjl139090 	pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p;
2474d3533785Sschwartz 	uint64_t mask;
247525cf1a30Sjl139090 
247625cf1a30Sjl139090 	switch (PX_CHIP_TYPE(pxu_p)) {
247725cf1a30Sjl139090 	case PX_CHIP_OBERON:
247825cf1a30Sjl139090 		mask = OBERON_RANGE_PROP_MASK;
247925cf1a30Sjl139090 		break;
248025cf1a30Sjl139090 	case PX_CHIP_FIRE:
2481d3533785Sschwartz 		mask = PX_RANGE_PROP_MASK;
248225cf1a30Sjl139090 		break;
248325cf1a30Sjl139090 	default:
2484d3533785Sschwartz 		mask = PX_RANGE_PROP_MASK;
248525cf1a30Sjl139090 	}
2486d3533785Sschwartz 
2487d3533785Sschwartz 	return (mask);
2488d3533785Sschwartz }
2489d3533785Sschwartz 
2490d3533785Sschwartz /*
2491d3533785Sschwartz  * fetch chip's range propery's value
2492d3533785Sschwartz  */
2493d3533785Sschwartz uint64_t
249426947304SEvan Yan px_get_range_prop(px_t *px_p, pci_ranges_t *rp, int bank)
2495d3533785Sschwartz {
2496d3533785Sschwartz 	uint64_t mask, range_prop;
2497d3533785Sschwartz 
2498d3533785Sschwartz 	mask = px_get_rng_parent_hi_mask(px_p);
249925cf1a30Sjl139090 	range_prop = (((uint64_t)(rp[bank].parent_high & mask)) << 32) |
250025cf1a30Sjl139090 	    rp[bank].parent_low;
250125cf1a30Sjl139090 
250225cf1a30Sjl139090 	return (range_prop);
250325cf1a30Sjl139090 }
250425cf1a30Sjl139090 
250525cf1a30Sjl139090 /*
2506c0da6274SZhi-Jun Robin Fu  * fetch the config space base addr of the root complex
2507c0da6274SZhi-Jun Robin Fu  * note this depends on px structure being initialized
2508c0da6274SZhi-Jun Robin Fu  */
2509c0da6274SZhi-Jun Robin Fu uint64_t
2510c0da6274SZhi-Jun Robin Fu px_lib_get_cfgacc_base(dev_info_t *dip)
2511c0da6274SZhi-Jun Robin Fu {
2512c0da6274SZhi-Jun Robin Fu 	int		instance = DIP_TO_INST(dip);
2513c0da6274SZhi-Jun Robin Fu 	px_t		*px_p = INST_TO_STATE(instance);
2514c0da6274SZhi-Jun Robin Fu 	pci_ranges_t	*rp = px_p->px_ranges_p;
2515c0da6274SZhi-Jun Robin Fu 	int		bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG);
2516c0da6274SZhi-Jun Robin Fu 
2517c0da6274SZhi-Jun Robin Fu 	/* Get Fire's Physical Base Address */
2518c0da6274SZhi-Jun Robin Fu 	return (px_get_range_prop(px_p, rp, bank));
2519c0da6274SZhi-Jun Robin Fu }
2520c0da6274SZhi-Jun Robin Fu 
2521c0da6274SZhi-Jun Robin Fu /*
2522817a6df8Sjchu  * add cpr callback
2523817a6df8Sjchu  */
2524817a6df8Sjchu void
2525817a6df8Sjchu px_cpr_add_callb(px_t *px_p)
2526817a6df8Sjchu {
2527817a6df8Sjchu 	px_p->px_cprcb_id = callb_add(px_cpr_callb, (void *)px_p,
2528817a6df8Sjchu 	    CB_CL_CPR_POST_USER, "px_cpr");
2529817a6df8Sjchu }
2530817a6df8Sjchu 
2531817a6df8Sjchu /*
2532817a6df8Sjchu  * remove cpr callback
2533817a6df8Sjchu  */
2534817a6df8Sjchu void
2535817a6df8Sjchu px_cpr_rem_callb(px_t *px_p)
2536817a6df8Sjchu {
2537817a6df8Sjchu 	(void) callb_delete(px_p->px_cprcb_id);
2538817a6df8Sjchu }
2539b65731f1Skini 
2540b65731f1Skini /*ARGSUSED*/
254125cf1a30Sjl139090 static uint_t
254225cf1a30Sjl139090 px_hp_intr(caddr_t arg1, caddr_t arg2)
254325cf1a30Sjl139090 {
254425cf1a30Sjl139090 	px_t		*px_p = (px_t *)arg1;
25450d5b93d9Sgovinda 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
254625cf1a30Sjl139090 	int		rval;
254725cf1a30Sjl139090 
254826947304SEvan Yan 	rval = pcie_intr(px_p->px_dip);
254925cf1a30Sjl139090 
255025cf1a30Sjl139090 #ifdef  DEBUG
255125cf1a30Sjl139090 	if (rval == DDI_INTR_UNCLAIMED)
255225cf1a30Sjl139090 		cmn_err(CE_WARN, "%s%d: UNCLAIMED intr\n",
255325cf1a30Sjl139090 		    ddi_driver_name(px_p->px_dip),
255425cf1a30Sjl139090 		    ddi_get_instance(px_p->px_dip));
255525cf1a30Sjl139090 #endif
255625cf1a30Sjl139090 
25570d5b93d9Sgovinda 	/* Set the interrupt state to idle */
25580d5b93d9Sgovinda 	if (px_lib_intr_setstate(px_p->px_dip,
25590d5b93d9Sgovinda 	    pxu_p->hp_sysino, INTR_IDLE_STATE) != DDI_SUCCESS)
25600d5b93d9Sgovinda 		return (DDI_INTR_UNCLAIMED);
25610d5b93d9Sgovinda 
256225cf1a30Sjl139090 	return (rval);
256325cf1a30Sjl139090 }
256425cf1a30Sjl139090 
2565b65731f1Skini int
2566b65731f1Skini px_lib_hotplug_init(dev_info_t *dip, void *arg)
2567b65731f1Skini {
256825cf1a30Sjl139090 	px_t	*px_p = DIP_TO_STATE(dip);
25690d5b93d9Sgovinda 	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
257025cf1a30Sjl139090 	uint64_t ret;
257125cf1a30Sjl139090 
257226947304SEvan Yan 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
257326947304SEvan Yan 	    "hotplug-capable") == 0)
257426947304SEvan Yan 		return (DDI_FAILURE);
257526947304SEvan Yan 
257625cf1a30Sjl139090 	if ((ret = hvio_hotplug_init(dip, arg)) == DDI_SUCCESS) {
257725cf1a30Sjl139090 		if (px_lib_intr_devino_to_sysino(px_p->px_dip,
25780d5b93d9Sgovinda 		    px_p->px_inos[PX_INTR_HOTPLUG], &pxu_p->hp_sysino) !=
257925cf1a30Sjl139090 		    DDI_SUCCESS) {
258025cf1a30Sjl139090 #ifdef	DEBUG
258125cf1a30Sjl139090 			cmn_err(CE_WARN, "%s%d: devino_to_sysino fails\n",
258225cf1a30Sjl139090 			    ddi_driver_name(px_p->px_dip),
258325cf1a30Sjl139090 			    ddi_get_instance(px_p->px_dip));
258425cf1a30Sjl139090 #endif
258525cf1a30Sjl139090 			return (DDI_FAILURE);
2586b65731f1Skini 		}
2587b65731f1Skini 
258826947304SEvan Yan 		VERIFY(add_ivintr(pxu_p->hp_sysino, PCIE_INTR_PRI,
2589b0fc0e77Sgovinda 		    (intrfunc)px_hp_intr, (caddr_t)px_p, NULL, NULL) == 0);
2590ab4471cdSscarter 
2591ab4471cdSscarter 		px_ib_intr_enable(px_p, intr_dist_cpuid(),
2592ab4471cdSscarter 		    px_p->px_inos[PX_INTR_HOTPLUG]);
259325cf1a30Sjl139090 	}
259425cf1a30Sjl139090 
259525cf1a30Sjl139090 	return (ret);
259625cf1a30Sjl139090 }
259725cf1a30Sjl139090 
2598b65731f1Skini void
2599b65731f1Skini px_lib_hotplug_uninit(dev_info_t *dip)
2600b65731f1Skini {
260125cf1a30Sjl139090 	if (hvio_hotplug_uninit(dip) == DDI_SUCCESS) {
260225cf1a30Sjl139090 		px_t	*px_p = DIP_TO_STATE(dip);
26030d5b93d9Sgovinda 		pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
260425cf1a30Sjl139090 
2605ab4471cdSscarter 		px_ib_intr_disable(px_p->px_ib_p,
2606ab4471cdSscarter 		    px_p->px_inos[PX_INTR_HOTPLUG], IB_INTR_WAIT);
2607ab4471cdSscarter 
260826947304SEvan Yan 		VERIFY(rem_ivintr(pxu_p->hp_sysino, PCIE_INTR_PRI) == 0);
260925cf1a30Sjl139090 	}
2610b65731f1Skini }
2611d60bae31Sdwoods 
2612ab4471cdSscarter /*
2613ab4471cdSscarter  * px_hp_intr_redist() - sun4u only, HP interrupt redistribution
2614ab4471cdSscarter  */
2615ab4471cdSscarter void
2616ab4471cdSscarter px_hp_intr_redist(px_t *px_p)
2617ab4471cdSscarter {
261826947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(px_p->px_dip);
261926947304SEvan Yan 
262026947304SEvan Yan 	if (px_p && PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
2621ab4471cdSscarter 		px_ib_intr_dist_en(px_p->px_dip, intr_dist_cpuid(),
2622ab4471cdSscarter 		    px_p->px_inos[PX_INTR_HOTPLUG], B_FALSE);
2623ab4471cdSscarter 	}
2624ab4471cdSscarter }
2625ab4471cdSscarter 
2626d60bae31Sdwoods boolean_t
2627d60bae31Sdwoods px_lib_is_in_drain_state(px_t *px_p)
2628d60bae31Sdwoods {
2629d60bae31Sdwoods 	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
2630d60bae31Sdwoods 	caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
2631d60bae31Sdwoods 	uint64_t drain_status;
2632d60bae31Sdwoods 
2633d60bae31Sdwoods 	if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) {
2634d60bae31Sdwoods 		drain_status = CSR_BR(csr_base, DRAIN_CONTROL_STATUS, DRAIN);
2635d60bae31Sdwoods 	} else {
2636d60bae31Sdwoods 		drain_status = CSR_BR(csr_base, TLU_STATUS, DRAIN);
2637d60bae31Sdwoods 	}
2638d60bae31Sdwoods 
2639d60bae31Sdwoods 	return (drain_status);
2640d60bae31Sdwoods }
26417ea9b230Set142600 
26427ea9b230Set142600 pcie_req_id_t
26437ea9b230Set142600 px_lib_get_bdf(px_t *px_p)
26447ea9b230Set142600 {
26457ea9b230Set142600 	pxu_t 	*pxu_p = (pxu_t *)px_p->px_plat_p;
26467ea9b230Set142600 	caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
26477ea9b230Set142600 	pcie_req_id_t bdf;
26487ea9b230Set142600 
26497ea9b230Set142600 	bdf = CSR_BR(csr_base, DMC_PCI_EXPRESS_CONFIGURATION, REQ_ID);
26507ea9b230Set142600 
26517ea9b230Set142600 	return (bdf);
26527ea9b230Set142600 }
26530114761dSAlan Adamson, SD OSSD 
26540114761dSAlan Adamson, SD OSSD /*ARGSUSED*/
26550114761dSAlan Adamson, SD OSSD int
26560114761dSAlan Adamson, SD OSSD px_lib_get_root_complex_mps(px_t *px_p, dev_info_t *dip, int *mps)
26570114761dSAlan Adamson, SD OSSD {
26580114761dSAlan Adamson, SD OSSD 	pxu_t	*pxu_p;
26590114761dSAlan Adamson, SD OSSD 	caddr_t csr_base;
26600114761dSAlan Adamson, SD OSSD 
26610114761dSAlan Adamson, SD OSSD 	pxu_p = (pxu_t *)px_p->px_plat_p;
26620114761dSAlan Adamson, SD OSSD 
26630114761dSAlan Adamson, SD OSSD 	if (pxu_p == NULL)
26640114761dSAlan Adamson, SD OSSD 		return (DDI_FAILURE);
26650114761dSAlan Adamson, SD OSSD 
26660114761dSAlan Adamson, SD OSSD 	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
26670114761dSAlan Adamson, SD OSSD 
26680114761dSAlan Adamson, SD OSSD 
26690114761dSAlan Adamson, SD OSSD 	*mps = CSR_XR(csr_base, TLU_DEVICE_CAPABILITIES) &
26700114761dSAlan Adamson, SD OSSD 	    TLU_DEVICE_CAPABILITIES_MPS_MASK;
26710114761dSAlan Adamson, SD OSSD 
26720114761dSAlan Adamson, SD OSSD 	return (DDI_SUCCESS);
26730114761dSAlan Adamson, SD OSSD }
26740114761dSAlan Adamson, SD OSSD 
26750114761dSAlan Adamson, SD OSSD /*ARGSUSED*/
26760114761dSAlan Adamson, SD OSSD int
26770114761dSAlan Adamson, SD OSSD px_lib_set_root_complex_mps(px_t *px_p,  dev_info_t *dip, int mps)
26780114761dSAlan Adamson, SD OSSD {
26790114761dSAlan Adamson, SD OSSD 	pxu_t	*pxu_p;
26800114761dSAlan Adamson, SD OSSD 	caddr_t csr_base;
26810114761dSAlan Adamson, SD OSSD 	uint64_t dev_ctrl;
26820114761dSAlan Adamson, SD OSSD 	int link_width, val;
26830114761dSAlan Adamson, SD OSSD 	px_chip_type_t chip_type = px_identity_init(px_p);
26840114761dSAlan Adamson, SD OSSD 
26850114761dSAlan Adamson, SD OSSD 	pxu_p = (pxu_t *)px_p->px_plat_p;
26860114761dSAlan Adamson, SD OSSD 
26870114761dSAlan Adamson, SD OSSD 	if (pxu_p == NULL)
26880114761dSAlan Adamson, SD OSSD 		return (DDI_FAILURE);
26890114761dSAlan Adamson, SD OSSD 
26900114761dSAlan Adamson, SD OSSD 	csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR];
26910114761dSAlan Adamson, SD OSSD 
26920114761dSAlan Adamson, SD OSSD 	dev_ctrl = CSR_XR(csr_base, TLU_DEVICE_CONTROL);
26930114761dSAlan Adamson, SD OSSD 	dev_ctrl |= (mps << TLU_DEVICE_CONTROL_MPS);
26940114761dSAlan Adamson, SD OSSD 
26950114761dSAlan Adamson, SD OSSD 	CSR_XS(csr_base, TLU_DEVICE_CONTROL, dev_ctrl);
26960114761dSAlan Adamson, SD OSSD 
26970114761dSAlan Adamson, SD OSSD 	link_width = CSR_FR(csr_base, TLU_LINK_STATUS, WIDTH);
26980114761dSAlan Adamson, SD OSSD 
26990114761dSAlan Adamson, SD OSSD 	/*
27000114761dSAlan Adamson, SD OSSD 	 * Convert link_width to match timer array configuration.
27010114761dSAlan Adamson, SD OSSD 	 */
27020114761dSAlan Adamson, SD OSSD 	switch (link_width) {
27030114761dSAlan Adamson, SD OSSD 	case 1:
27040114761dSAlan Adamson, SD OSSD 		link_width = 0;
27050114761dSAlan Adamson, SD OSSD 		break;
27060114761dSAlan Adamson, SD OSSD 	case 4:
27070114761dSAlan Adamson, SD OSSD 		link_width = 1;
27080114761dSAlan Adamson, SD OSSD 		break;
27090114761dSAlan Adamson, SD OSSD 	case 8:
27100114761dSAlan Adamson, SD OSSD 		link_width = 2;
27110114761dSAlan Adamson, SD OSSD 		break;
27120114761dSAlan Adamson, SD OSSD 	case 16:
27130114761dSAlan Adamson, SD OSSD 		link_width = 3;
27140114761dSAlan Adamson, SD OSSD 		break;
27150114761dSAlan Adamson, SD OSSD 	default:
27160114761dSAlan Adamson, SD OSSD 		link_width = 0;
27170114761dSAlan Adamson, SD OSSD 	}
27180114761dSAlan Adamson, SD OSSD 
27190114761dSAlan Adamson, SD OSSD 	val = px_replay_timer_table[mps][link_width];
27200114761dSAlan Adamson, SD OSSD 	CSR_XS(csr_base, LPU_TXLINK_REPLAY_TIMER_THRESHOLD, val);
27210114761dSAlan Adamson, SD OSSD 
27220114761dSAlan Adamson, SD OSSD 	if (chip_type == PX_CHIP_OBERON)
27230114761dSAlan Adamson, SD OSSD 		return (DDI_SUCCESS);
27240114761dSAlan Adamson, SD OSSD 
27250114761dSAlan Adamson, SD OSSD 	val = px_acknak_timer_table[mps][link_width];
27260114761dSAlan Adamson, SD OSSD 	CSR_XS(csr_base, LPU_TXLINK_FREQUENT_NAK_LATENCY_TIMER_THRESHOLD, val);
27270114761dSAlan Adamson, SD OSSD 
27280114761dSAlan Adamson, SD OSSD 	return (DDI_SUCCESS);
27290114761dSAlan Adamson, SD OSSD }
2730fc256490SJason Beloro 
2731fc256490SJason Beloro /*ARGSUSED*/
2732fc256490SJason Beloro int
2733fc256490SJason Beloro px_lib_fabric_sync(dev_info_t *dip)
2734fc256490SJason Beloro {
2735fc256490SJason Beloro 	/* an no-op on sun4u platform */
2736fc256490SJason Beloro 	return (DDI_SUCCESS);
2737fc256490SJason Beloro }
2738