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