10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51540Skini * Common Development and Distribution License (the "License"). 61540Skini * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 223354Sjl139090 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/types.h> 290Sstevel@tonic-gate #include <sys/kmem.h> 300Sstevel@tonic-gate #include <sys/conf.h> 310Sstevel@tonic-gate #include <sys/ddi.h> 320Sstevel@tonic-gate #include <sys/sunddi.h> 3327Sjchu #include <sys/fm/protocol.h> 3427Sjchu #include <sys/fm/util.h> 350Sstevel@tonic-gate #include <sys/modctl.h> 360Sstevel@tonic-gate #include <sys/disp.h> 370Sstevel@tonic-gate #include <sys/stat.h> 380Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 390Sstevel@tonic-gate #include <sys/vmem.h> 400Sstevel@tonic-gate #include <sys/iommutsb.h> 410Sstevel@tonic-gate #include <sys/cpuvar.h> 4227Sjchu #include <sys/ivintr.h> 43383Set142600 #include <sys/byteorder.h> 441531Skini #include <sys/hotplug/pci/pciehpc.h> 453623Sjchu #include <sys/spl.h> 460Sstevel@tonic-gate #include <px_obj.h> 470Sstevel@tonic-gate #include <pcie_pwr.h> 481772Sjl139090 #include "px_tools_var.h" 490Sstevel@tonic-gate #include <px_regs.h> 500Sstevel@tonic-gate #include <px_csr.h> 5127Sjchu #include <sys/machsystm.h> 520Sstevel@tonic-gate #include "px_lib4u.h" 5327Sjchu #include "px_err.h" 541772Sjl139090 #include "oberon_regs.h" 550Sstevel@tonic-gate 560Sstevel@tonic-gate #pragma weak jbus_stst_order 570Sstevel@tonic-gate 580Sstevel@tonic-gate extern void jbus_stst_order(); 590Sstevel@tonic-gate 600Sstevel@tonic-gate ulong_t px_mmu_dvma_end = 0xfffffffful; 610Sstevel@tonic-gate uint_t px_ranges_phi_mask = 0xfffffffful; 621772Sjl139090 uint64_t *px_oberon_ubc_scratch_regs; 632276Sschwartz uint64_t px_paddr_mask; 640Sstevel@tonic-gate 650Sstevel@tonic-gate static int px_goto_l23ready(px_t *px_p); 66118Sjchu static int px_goto_l0(px_t *px_p); 67118Sjchu static int px_pre_pwron_check(px_t *px_p); 682426Sschwartz static uint32_t px_identity_init(px_t *px_p); 69435Sjchu static boolean_t px_cpr_callb(void *arg, int code); 701648Sjchu static uint_t px_cb_intr(caddr_t arg); 7127Sjchu 7227Sjchu /* 7327Sjchu * px_lib_map_registers 7427Sjchu * 7527Sjchu * This function is called from the attach routine to map the registers 7627Sjchu * accessed by this driver. 7727Sjchu * 7827Sjchu * used by: px_attach() 7927Sjchu * 8027Sjchu * return value: DDI_FAILURE on failure 8127Sjchu */ 8227Sjchu int 8327Sjchu px_lib_map_regs(pxu_t *pxu_p, dev_info_t *dip) 8427Sjchu { 8527Sjchu ddi_device_acc_attr_t attr; 8627Sjchu px_reg_bank_t reg_bank = PX_REG_CSR; 8727Sjchu 8827Sjchu DBG(DBG_ATTACH, dip, "px_lib_map_regs: pxu_p:0x%p, dip 0x%p\n", 8927Sjchu pxu_p, dip); 9027Sjchu 9127Sjchu attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 9227Sjchu attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 9327Sjchu attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 9427Sjchu 9527Sjchu /* 9627Sjchu * PCI CSR Base 9727Sjchu */ 9827Sjchu if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank], 9927Sjchu 0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) { 10027Sjchu goto fail; 10127Sjchu } 10227Sjchu 10327Sjchu reg_bank++; 10427Sjchu 10527Sjchu /* 10627Sjchu * XBUS CSR Base 10727Sjchu */ 10827Sjchu if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank], 10927Sjchu 0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) { 11027Sjchu goto fail; 11127Sjchu } 11227Sjchu 11327Sjchu pxu_p->px_address[reg_bank] -= FIRE_CONTROL_STATUS; 11427Sjchu 11527Sjchu done: 11627Sjchu for (; reg_bank >= PX_REG_CSR; reg_bank--) { 11727Sjchu DBG(DBG_ATTACH, dip, "reg_bank 0x%x address 0x%p\n", 11827Sjchu reg_bank, pxu_p->px_address[reg_bank]); 11927Sjchu } 12027Sjchu 12127Sjchu return (DDI_SUCCESS); 12227Sjchu 12327Sjchu fail: 12427Sjchu cmn_err(CE_WARN, "%s%d: unable to map reg entry %d\n", 12527Sjchu ddi_driver_name(dip), ddi_get_instance(dip), reg_bank); 12627Sjchu 12727Sjchu for (reg_bank--; reg_bank >= PX_REG_CSR; reg_bank--) { 12827Sjchu pxu_p->px_address[reg_bank] = NULL; 12927Sjchu ddi_regs_map_free(&pxu_p->px_ac[reg_bank]); 13027Sjchu } 13127Sjchu 13227Sjchu return (DDI_FAILURE); 13327Sjchu } 13427Sjchu 13527Sjchu /* 13627Sjchu * px_lib_unmap_regs: 13727Sjchu * 13827Sjchu * This routine unmaps the registers mapped by map_px_registers. 13927Sjchu * 14027Sjchu * used by: px_detach(), and error conditions in px_attach() 14127Sjchu * 14227Sjchu * return value: none 14327Sjchu */ 14427Sjchu void 14527Sjchu px_lib_unmap_regs(pxu_t *pxu_p) 14627Sjchu { 14727Sjchu int i; 14827Sjchu 14927Sjchu for (i = 0; i < PX_REG_MAX; i++) { 15027Sjchu if (pxu_p->px_ac[i]) 15127Sjchu ddi_regs_map_free(&pxu_p->px_ac[i]); 15227Sjchu } 15327Sjchu } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate int 1560Sstevel@tonic-gate px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl) 1570Sstevel@tonic-gate { 1582509Sschwartz 1592509Sschwartz caddr_t xbc_csr_base, csr_base; 1600Sstevel@tonic-gate px_dvma_range_prop_t px_dvma_range; 1612509Sschwartz pxu_t *pxu_p; 1622509Sschwartz uint8_t chip_mask; 1632509Sschwartz px_t *px_p = DIP_TO_STATE(dip); 1642509Sschwartz px_chip_type_t chip_type = px_identity_init(px_p); 1650Sstevel@tonic-gate 1662426Sschwartz DBG(DBG_ATTACH, dip, "px_lib_dev_init: dip 0x%p", dip); 1672426Sschwartz 1682426Sschwartz if (chip_type == PX_CHIP_UNIDENTIFIED) { 1692426Sschwartz cmn_err(CE_WARN, "%s%d: Unrecognized Hardware Version\n", 1702426Sschwartz NAMEINST(dip)); 1710Sstevel@tonic-gate return (DDI_FAILURE); 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1742509Sschwartz chip_mask = BITMASK(chip_type); 1752426Sschwartz px_paddr_mask = (chip_type == PX_CHIP_FIRE) ? MMU_FIRE_PADDR_MASK : 1762426Sschwartz MMU_OBERON_PADDR_MASK; 1772426Sschwartz 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * Allocate platform specific structure and link it to 1800Sstevel@tonic-gate * the px state structure. 1810Sstevel@tonic-gate */ 1820Sstevel@tonic-gate pxu_p = kmem_zalloc(sizeof (pxu_t), KM_SLEEP); 1832426Sschwartz pxu_p->chip_type = chip_type; 1840Sstevel@tonic-gate pxu_p->portid = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1850Sstevel@tonic-gate "portid", -1); 1860Sstevel@tonic-gate 18727Sjchu /* Map in the registers */ 18827Sjchu if (px_lib_map_regs(pxu_p, dip) == DDI_FAILURE) { 18927Sjchu kmem_free(pxu_p, sizeof (pxu_t)); 19027Sjchu 19127Sjchu return (DDI_FAILURE); 19227Sjchu } 19327Sjchu 19427Sjchu xbc_csr_base = (caddr_t)pxu_p->px_address[PX_REG_XBC]; 19527Sjchu csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 19627Sjchu 1970Sstevel@tonic-gate pxu_p->tsb_cookie = iommu_tsb_alloc(pxu_p->portid); 1980Sstevel@tonic-gate pxu_p->tsb_size = iommu_tsb_cookie_to_size(pxu_p->tsb_cookie); 1990Sstevel@tonic-gate pxu_p->tsb_vaddr = iommu_tsb_cookie_to_va(pxu_p->tsb_cookie); 2000Sstevel@tonic-gate 2011772Sjl139090 pxu_p->tsb_paddr = va_to_pa(pxu_p->tsb_vaddr); 2021772Sjl139090 2030Sstevel@tonic-gate /* 2040Sstevel@tonic-gate * Create "virtual-dma" property to support child devices 2050Sstevel@tonic-gate * needing to know DVMA range. 2060Sstevel@tonic-gate */ 2070Sstevel@tonic-gate px_dvma_range.dvma_base = (uint32_t)px_mmu_dvma_end + 1 2080Sstevel@tonic-gate - ((pxu_p->tsb_size >> 3) << MMU_PAGE_SHIFT); 2090Sstevel@tonic-gate px_dvma_range.dvma_len = (uint32_t) 2100Sstevel@tonic-gate px_mmu_dvma_end - px_dvma_range.dvma_base + 1; 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 2130Sstevel@tonic-gate "virtual-dma", (caddr_t)&px_dvma_range, 2140Sstevel@tonic-gate sizeof (px_dvma_range_prop_t)); 2150Sstevel@tonic-gate /* 2160Sstevel@tonic-gate * Initilize all fire hardware specific blocks. 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate hvio_cb_init(xbc_csr_base, pxu_p); 2190Sstevel@tonic-gate hvio_ib_init(csr_base, pxu_p); 2200Sstevel@tonic-gate hvio_pec_init(csr_base, pxu_p); 2210Sstevel@tonic-gate hvio_mmu_init(csr_base, pxu_p); 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate px_p->px_plat_p = (void *)pxu_p; 2240Sstevel@tonic-gate 22527Sjchu /* 22627Sjchu * Initialize all the interrupt handlers 22727Sjchu */ 2281772Sjl139090 switch (PX_CHIP_TYPE(pxu_p)) { 2291772Sjl139090 case PX_CHIP_OBERON: 2302044Sjj156685 /* 2312044Sjj156685 * Oberon hotplug uses SPARE3 field in ILU Error Log Enable 2322044Sjj156685 * register to indicate the status of leaf reset, 2332044Sjj156685 * we need to preserve the value of this bit, and keep it in 2342044Sjj156685 * px_ilu_log_mask to reflect the state of the bit 2352044Sjj156685 */ 2362044Sjj156685 if (CSR_BR(csr_base, ILU_ERROR_LOG_ENABLE, SPARE3)) 2372044Sjj156685 px_ilu_log_mask |= (1ull << 2382044Sjj156685 ILU_ERROR_LOG_ENABLE_SPARE3); 2392044Sjj156685 else 2402044Sjj156685 px_ilu_log_mask &= ~(1ull << 2412044Sjj156685 ILU_ERROR_LOG_ENABLE_SPARE3); 2422509Sschwartz 2432509Sschwartz px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE); 2441772Sjl139090 px_fabric_die_rc_ue |= PCIE_AER_UCE_UC; 2451772Sjl139090 break; 2461772Sjl139090 2471772Sjl139090 case PX_CHIP_FIRE: 2482509Sschwartz px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE); 2491772Sjl139090 break; 2502509Sschwartz 2511772Sjl139090 default: 2521772Sjl139090 cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n", 2531772Sjl139090 ddi_driver_name(dip), ddi_get_instance(dip)); 2541772Sjl139090 return (DDI_FAILURE); 2551772Sjl139090 } 25627Sjchu 2570Sstevel@tonic-gate /* Initilize device handle */ 2580Sstevel@tonic-gate *dev_hdl = (devhandle_t)csr_base; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "px_lib_dev_init: dev_hdl 0x%llx\n", *dev_hdl); 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate return (DDI_SUCCESS); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate int 2660Sstevel@tonic-gate px_lib_dev_fini(dev_info_t *dip) 2670Sstevel@tonic-gate { 2682509Sschwartz caddr_t csr_base; 2692509Sschwartz uint8_t chip_mask; 2702509Sschwartz px_t *px_p = DIP_TO_STATE(dip); 2712509Sschwartz pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate DBG(DBG_DETACH, dip, "px_lib_dev_fini: dip 0x%p\n", dip); 2740Sstevel@tonic-gate 27527Sjchu /* 27627Sjchu * Deinitialize all the interrupt handlers 27727Sjchu */ 2781772Sjl139090 switch (PX_CHIP_TYPE(pxu_p)) { 2791772Sjl139090 case PX_CHIP_OBERON: 2802509Sschwartz case PX_CHIP_FIRE: 2812509Sschwartz chip_mask = BITMASK(PX_CHIP_TYPE(pxu_p)); 2822509Sschwartz csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 2832509Sschwartz px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_DISABLE); 2841772Sjl139090 break; 2852509Sschwartz 2861772Sjl139090 default: 2871772Sjl139090 cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n", 2881772Sjl139090 ddi_driver_name(dip), ddi_get_instance(dip)); 2891772Sjl139090 return (DDI_FAILURE); 2901772Sjl139090 } 29127Sjchu 2920Sstevel@tonic-gate iommu_tsb_free(pxu_p->tsb_cookie); 2930Sstevel@tonic-gate 29427Sjchu px_lib_unmap_regs((pxu_t *)px_p->px_plat_p); 29527Sjchu kmem_free(px_p->px_plat_p, sizeof (pxu_t)); 2960Sstevel@tonic-gate px_p->px_plat_p = NULL; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate return (DDI_SUCCESS); 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate /*ARGSUSED*/ 3020Sstevel@tonic-gate int 3030Sstevel@tonic-gate px_lib_intr_devino_to_sysino(dev_info_t *dip, devino_t devino, 3040Sstevel@tonic-gate sysino_t *sysino) 3050Sstevel@tonic-gate { 3060Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 3070Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 3080Sstevel@tonic-gate uint64_t ret; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: dip 0x%p " 3110Sstevel@tonic-gate "devino 0x%x\n", dip, devino); 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate if ((ret = hvio_intr_devino_to_sysino(DIP_TO_HANDLE(dip), 3140Sstevel@tonic-gate pxu_p, devino, sysino)) != H_EOK) { 3150Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, 3160Sstevel@tonic-gate "hvio_intr_devino_to_sysino failed, ret 0x%lx\n", ret); 3170Sstevel@tonic-gate return (DDI_FAILURE); 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: sysino 0x%llx\n", 3210Sstevel@tonic-gate *sysino); 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate return (DDI_SUCCESS); 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate /*ARGSUSED*/ 3270Sstevel@tonic-gate int 3280Sstevel@tonic-gate px_lib_intr_getvalid(dev_info_t *dip, sysino_t sysino, 3290Sstevel@tonic-gate intr_valid_state_t *intr_valid_state) 3300Sstevel@tonic-gate { 3310Sstevel@tonic-gate uint64_t ret; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: dip 0x%p sysino 0x%llx\n", 3340Sstevel@tonic-gate dip, sysino); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate if ((ret = hvio_intr_getvalid(DIP_TO_HANDLE(dip), 3370Sstevel@tonic-gate sysino, intr_valid_state)) != H_EOK) { 3380Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_getvalid failed, ret 0x%lx\n", 3390Sstevel@tonic-gate ret); 3400Sstevel@tonic-gate return (DDI_FAILURE); 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: intr_valid_state 0x%x\n", 3440Sstevel@tonic-gate *intr_valid_state); 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate return (DDI_SUCCESS); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /*ARGSUSED*/ 3500Sstevel@tonic-gate int 3510Sstevel@tonic-gate px_lib_intr_setvalid(dev_info_t *dip, sysino_t sysino, 3520Sstevel@tonic-gate intr_valid_state_t intr_valid_state) 3530Sstevel@tonic-gate { 3540Sstevel@tonic-gate uint64_t ret; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_setvalid: dip 0x%p sysino 0x%llx " 3570Sstevel@tonic-gate "intr_valid_state 0x%x\n", dip, sysino, intr_valid_state); 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate if ((ret = hvio_intr_setvalid(DIP_TO_HANDLE(dip), 3600Sstevel@tonic-gate sysino, intr_valid_state)) != H_EOK) { 3610Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_setvalid failed, ret 0x%lx\n", 3620Sstevel@tonic-gate ret); 3630Sstevel@tonic-gate return (DDI_FAILURE); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate return (DDI_SUCCESS); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /*ARGSUSED*/ 3700Sstevel@tonic-gate int 3710Sstevel@tonic-gate px_lib_intr_getstate(dev_info_t *dip, sysino_t sysino, 3720Sstevel@tonic-gate intr_state_t *intr_state) 3730Sstevel@tonic-gate { 3740Sstevel@tonic-gate uint64_t ret; 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: dip 0x%p sysino 0x%llx\n", 3770Sstevel@tonic-gate dip, sysino); 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate if ((ret = hvio_intr_getstate(DIP_TO_HANDLE(dip), 3800Sstevel@tonic-gate sysino, intr_state)) != H_EOK) { 3810Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_getstate failed, ret 0x%lx\n", 3820Sstevel@tonic-gate ret); 3830Sstevel@tonic-gate return (DDI_FAILURE); 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: intr_state 0x%x\n", 3870Sstevel@tonic-gate *intr_state); 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate return (DDI_SUCCESS); 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate /*ARGSUSED*/ 3930Sstevel@tonic-gate int 3940Sstevel@tonic-gate px_lib_intr_setstate(dev_info_t *dip, sysino_t sysino, 3950Sstevel@tonic-gate intr_state_t intr_state) 3960Sstevel@tonic-gate { 3970Sstevel@tonic-gate uint64_t ret; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_setstate: dip 0x%p sysino 0x%llx " 4000Sstevel@tonic-gate "intr_state 0x%x\n", dip, sysino, intr_state); 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate if ((ret = hvio_intr_setstate(DIP_TO_HANDLE(dip), 4030Sstevel@tonic-gate sysino, intr_state)) != H_EOK) { 4040Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_setstate failed, ret 0x%lx\n", 4050Sstevel@tonic-gate ret); 4060Sstevel@tonic-gate return (DDI_FAILURE); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate return (DDI_SUCCESS); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /*ARGSUSED*/ 4130Sstevel@tonic-gate int 4140Sstevel@tonic-gate px_lib_intr_gettarget(dev_info_t *dip, sysino_t sysino, cpuid_t *cpuid) 4150Sstevel@tonic-gate { 4161772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 4171772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 4180Sstevel@tonic-gate uint64_t ret; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: dip 0x%p sysino 0x%llx\n", 4210Sstevel@tonic-gate dip, sysino); 4220Sstevel@tonic-gate 4231772Sjl139090 if ((ret = hvio_intr_gettarget(DIP_TO_HANDLE(dip), pxu_p, 4240Sstevel@tonic-gate sysino, cpuid)) != H_EOK) { 4250Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_gettarget failed, ret 0x%lx\n", 4260Sstevel@tonic-gate ret); 4270Sstevel@tonic-gate return (DDI_FAILURE); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: cpuid 0x%x\n", cpuid); 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate return (DDI_SUCCESS); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /*ARGSUSED*/ 4360Sstevel@tonic-gate int 4370Sstevel@tonic-gate px_lib_intr_settarget(dev_info_t *dip, sysino_t sysino, cpuid_t cpuid) 4380Sstevel@tonic-gate { 4391772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 4401772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 4410Sstevel@tonic-gate uint64_t ret; 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_settarget: dip 0x%p sysino 0x%llx " 4440Sstevel@tonic-gate "cpuid 0x%x\n", dip, sysino, cpuid); 4450Sstevel@tonic-gate 4461772Sjl139090 if ((ret = hvio_intr_settarget(DIP_TO_HANDLE(dip), pxu_p, 4470Sstevel@tonic-gate sysino, cpuid)) != H_EOK) { 4480Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_settarget failed, ret 0x%lx\n", 4490Sstevel@tonic-gate ret); 4500Sstevel@tonic-gate return (DDI_FAILURE); 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate return (DDI_SUCCESS); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate /*ARGSUSED*/ 4570Sstevel@tonic-gate int 4580Sstevel@tonic-gate px_lib_intr_reset(dev_info_t *dip) 4590Sstevel@tonic-gate { 4600Sstevel@tonic-gate devino_t ino; 4610Sstevel@tonic-gate sysino_t sysino; 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_reset: dip 0x%p\n", dip); 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate /* Reset all Interrupts */ 4660Sstevel@tonic-gate for (ino = 0; ino < INTERRUPT_MAPPING_ENTRIES; ino++) { 4670Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(dip, ino, 4680Sstevel@tonic-gate &sysino) != DDI_SUCCESS) 4690Sstevel@tonic-gate return (BF_FATAL); 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate if (px_lib_intr_setstate(dip, sysino, 4720Sstevel@tonic-gate INTR_IDLE_STATE) != DDI_SUCCESS) 4730Sstevel@tonic-gate return (BF_FATAL); 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate return (BF_NONE); 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate /*ARGSUSED*/ 4800Sstevel@tonic-gate int 4810Sstevel@tonic-gate px_lib_iommu_map(dev_info_t *dip, tsbid_t tsbid, pages_t pages, 4821617Sgovinda io_attributes_t attr, void *addr, size_t pfn_index, int flags) 4830Sstevel@tonic-gate { 4840Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 4850Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 4860Sstevel@tonic-gate uint64_t ret; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_map: dip 0x%p tsbid 0x%llx " 4891617Sgovinda "pages 0x%x attr 0x%x addr 0x%p pfn_index 0x%llx flags 0x%x\n", 4901617Sgovinda dip, tsbid, pages, attr, addr, pfn_index, flags); 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate if ((ret = hvio_iommu_map(px_p->px_dev_hdl, pxu_p, tsbid, pages, 4931617Sgovinda attr, addr, pfn_index, flags)) != H_EOK) { 4940Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 4950Sstevel@tonic-gate "px_lib_iommu_map failed, ret 0x%lx\n", ret); 4960Sstevel@tonic-gate return (DDI_FAILURE); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate return (DDI_SUCCESS); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /*ARGSUSED*/ 5030Sstevel@tonic-gate int 5040Sstevel@tonic-gate px_lib_iommu_demap(dev_info_t *dip, tsbid_t tsbid, pages_t pages) 5050Sstevel@tonic-gate { 5060Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5070Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 5080Sstevel@tonic-gate uint64_t ret; 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_demap: dip 0x%p tsbid 0x%llx " 5110Sstevel@tonic-gate "pages 0x%x\n", dip, tsbid, pages); 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate if ((ret = hvio_iommu_demap(px_p->px_dev_hdl, pxu_p, tsbid, pages)) 5140Sstevel@tonic-gate != H_EOK) { 5150Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 5160Sstevel@tonic-gate "px_lib_iommu_demap failed, ret 0x%lx\n", ret); 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate return (DDI_FAILURE); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate return (DDI_SUCCESS); 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate /*ARGSUSED*/ 5250Sstevel@tonic-gate int 5261617Sgovinda px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, io_attributes_t *attr_p, 5271617Sgovinda r_addr_t *r_addr_p) 5280Sstevel@tonic-gate { 5290Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5300Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 5310Sstevel@tonic-gate uint64_t ret; 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: dip 0x%p tsbid 0x%llx\n", 5340Sstevel@tonic-gate dip, tsbid); 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate if ((ret = hvio_iommu_getmap(DIP_TO_HANDLE(dip), pxu_p, tsbid, 5371617Sgovinda attr_p, r_addr_p)) != H_EOK) { 5380Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 5390Sstevel@tonic-gate "hvio_iommu_getmap failed, ret 0x%lx\n", ret); 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate return ((ret == H_ENOMAP) ? DDI_DMA_NOMAPPING:DDI_FAILURE); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: attr 0x%x r_addr 0x%llx\n", 5451617Sgovinda *attr_p, *r_addr_p); 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate return (DDI_SUCCESS); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate /* 5520Sstevel@tonic-gate * Checks dma attributes against system bypass ranges 5530Sstevel@tonic-gate * The bypass range is determined by the hardware. Return them so the 5540Sstevel@tonic-gate * common code can do generic checking against them. 5550Sstevel@tonic-gate */ 5560Sstevel@tonic-gate /*ARGSUSED*/ 5570Sstevel@tonic-gate int 5581772Sjl139090 px_lib_dma_bypass_rngchk(dev_info_t *dip, ddi_dma_attr_t *attr_p, 5591772Sjl139090 uint64_t *lo_p, uint64_t *hi_p) 5600Sstevel@tonic-gate { 5611772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 5621772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 5631772Sjl139090 5641772Sjl139090 *lo_p = hvio_get_bypass_base(pxu_p); 5651772Sjl139090 *hi_p = hvio_get_bypass_end(pxu_p); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate return (DDI_SUCCESS); 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate /*ARGSUSED*/ 5720Sstevel@tonic-gate int 5731617Sgovinda px_lib_iommu_getbypass(dev_info_t *dip, r_addr_t ra, io_attributes_t attr, 5741617Sgovinda io_addr_t *io_addr_p) 5750Sstevel@tonic-gate { 5760Sstevel@tonic-gate uint64_t ret; 5771772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 5781772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: dip 0x%p ra 0x%llx " 5811617Sgovinda "attr 0x%x\n", dip, ra, attr); 5820Sstevel@tonic-gate 5831772Sjl139090 if ((ret = hvio_iommu_getbypass(DIP_TO_HANDLE(dip), pxu_p, ra, 5841772Sjl139090 attr, io_addr_p)) != H_EOK) { 5850Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 5860Sstevel@tonic-gate "hvio_iommu_getbypass failed, ret 0x%lx\n", ret); 5870Sstevel@tonic-gate return (DDI_FAILURE); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: io_addr 0x%llx\n", 5910Sstevel@tonic-gate *io_addr_p); 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate return (DDI_SUCCESS); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* 5970Sstevel@tonic-gate * bus dma sync entry point. 5980Sstevel@tonic-gate */ 5990Sstevel@tonic-gate /*ARGSUSED*/ 6000Sstevel@tonic-gate int 6010Sstevel@tonic-gate px_lib_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, 6021617Sgovinda off_t off, size_t len, uint_t cache_flags) 6030Sstevel@tonic-gate { 6040Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 6051772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 6061772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_dma_sync: dip 0x%p rdip 0x%p " 6090Sstevel@tonic-gate "handle 0x%llx off 0x%x len 0x%x flags 0x%x\n", 6100Sstevel@tonic-gate dip, rdip, handle, off, len, cache_flags); 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate /* 6131772Sjl139090 * No flush needed for Oberon 6141772Sjl139090 */ 6151772Sjl139090 if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) 6161772Sjl139090 return (DDI_SUCCESS); 6171772Sjl139090 6181772Sjl139090 /* 6190Sstevel@tonic-gate * jbus_stst_order is found only in certain cpu modules. 6200Sstevel@tonic-gate * Just return success if not present. 6210Sstevel@tonic-gate */ 6220Sstevel@tonic-gate if (&jbus_stst_order == NULL) 6230Sstevel@tonic-gate return (DDI_SUCCESS); 6240Sstevel@tonic-gate 625909Segillett if (!(mp->dmai_flags & PX_DMAI_FLAGS_INUSE)) { 62627Sjchu cmn_err(CE_WARN, "%s%d: Unbound dma handle %p.", 62727Sjchu ddi_driver_name(rdip), ddi_get_instance(rdip), (void *)mp); 62827Sjchu 6290Sstevel@tonic-gate return (DDI_FAILURE); 6300Sstevel@tonic-gate } 6310Sstevel@tonic-gate 632909Segillett if (mp->dmai_flags & PX_DMAI_FLAGS_NOSYNC) 6330Sstevel@tonic-gate return (DDI_SUCCESS); 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate /* 6360Sstevel@tonic-gate * No flush needed when sending data from memory to device. 6370Sstevel@tonic-gate * Nothing to do to "sync" memory to what device would already see. 6380Sstevel@tonic-gate */ 6390Sstevel@tonic-gate if (!(mp->dmai_rflags & DDI_DMA_READ) || 6400Sstevel@tonic-gate ((cache_flags & PX_DMA_SYNC_DDI_FLAGS) == DDI_DMA_SYNC_FORDEV)) 6410Sstevel@tonic-gate return (DDI_SUCCESS); 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate /* 6440Sstevel@tonic-gate * Perform necessary cpu workaround to ensure jbus ordering. 6450Sstevel@tonic-gate * CPU's internal "invalidate FIFOs" are flushed. 6460Sstevel@tonic-gate */ 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate #if !defined(lint) 6490Sstevel@tonic-gate kpreempt_disable(); 6500Sstevel@tonic-gate #endif 6510Sstevel@tonic-gate jbus_stst_order(); 6520Sstevel@tonic-gate #if !defined(lint) 6530Sstevel@tonic-gate kpreempt_enable(); 6540Sstevel@tonic-gate #endif 6550Sstevel@tonic-gate return (DDI_SUCCESS); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate /* 6590Sstevel@tonic-gate * MSIQ Functions: 6600Sstevel@tonic-gate */ 6610Sstevel@tonic-gate /*ARGSUSED*/ 6620Sstevel@tonic-gate int 6630Sstevel@tonic-gate px_lib_msiq_init(dev_info_t *dip) 6640Sstevel@tonic-gate { 6650Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 6660Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 6670Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 6680Sstevel@tonic-gate px_dvma_addr_t pg_index; 6690Sstevel@tonic-gate size_t size; 6700Sstevel@tonic-gate int ret; 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_init: dip 0x%p\n", dip); 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate /* 6750Sstevel@tonic-gate * Map the EQ memory into the Fire MMU (has to be 512KB aligned) 6760Sstevel@tonic-gate * and then initialize the base address register. 6770Sstevel@tonic-gate * 6780Sstevel@tonic-gate * Allocate entries from Fire IOMMU so that the resulting address 6790Sstevel@tonic-gate * is properly aligned. Calculate the index of the first allocated 6800Sstevel@tonic-gate * entry. Note: The size of the mapping is assumed to be a multiple 6810Sstevel@tonic-gate * of the page size. 6820Sstevel@tonic-gate */ 6830Sstevel@tonic-gate size = msiq_state_p->msiq_cnt * 6840Sstevel@tonic-gate msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t); 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate pxu_p->msiq_mapped_p = vmem_xalloc(px_p->px_mmu_p->mmu_dvma_map, 6870Sstevel@tonic-gate size, (512 * 1024), 0, 0, NULL, NULL, VM_NOSLEEP | VM_BESTFIT); 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate if (pxu_p->msiq_mapped_p == NULL) 6900Sstevel@tonic-gate return (DDI_FAILURE); 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p, 6930Sstevel@tonic-gate MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p)); 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate if ((ret = px_lib_iommu_map(px_p->px_dip, PCI_TSBID(0, pg_index), 6962755Segillett MMU_BTOP(size), PCI_MAP_ATTR_WRITE, msiq_state_p->msiq_buf_p, 6972755Segillett 0, MMU_MAP_BUF)) != DDI_SUCCESS) { 6980Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 6990Sstevel@tonic-gate "hvio_msiq_init failed, ret 0x%lx\n", ret); 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate (void) px_lib_msiq_fini(dip); 7020Sstevel@tonic-gate return (DDI_FAILURE); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate (void) hvio_msiq_init(DIP_TO_HANDLE(dip), pxu_p); 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate return (DDI_SUCCESS); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate /*ARGSUSED*/ 7110Sstevel@tonic-gate int 7120Sstevel@tonic-gate px_lib_msiq_fini(dev_info_t *dip) 7130Sstevel@tonic-gate { 7140Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 7150Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 7160Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 7170Sstevel@tonic-gate px_dvma_addr_t pg_index; 7180Sstevel@tonic-gate size_t size; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_fini: dip 0x%p\n", dip); 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate /* 7230Sstevel@tonic-gate * Unmap and free the EQ memory that had been mapped 7240Sstevel@tonic-gate * into the Fire IOMMU. 7250Sstevel@tonic-gate */ 7260Sstevel@tonic-gate size = msiq_state_p->msiq_cnt * 7270Sstevel@tonic-gate msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t); 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p, 7300Sstevel@tonic-gate MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p)); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate (void) px_lib_iommu_demap(px_p->px_dip, 7330Sstevel@tonic-gate PCI_TSBID(0, pg_index), MMU_BTOP(size)); 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate /* Free the entries from the Fire MMU */ 7360Sstevel@tonic-gate vmem_xfree(px_p->px_mmu_p->mmu_dvma_map, 7370Sstevel@tonic-gate (void *)pxu_p->msiq_mapped_p, size); 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate return (DDI_SUCCESS); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate /*ARGSUSED*/ 7430Sstevel@tonic-gate int 7440Sstevel@tonic-gate px_lib_msiq_info(dev_info_t *dip, msiqid_t msiq_id, r_addr_t *ra_p, 7450Sstevel@tonic-gate uint_t *msiq_rec_cnt_p) 7460Sstevel@tonic-gate { 7470Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 7480Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 7490Sstevel@tonic-gate size_t msiq_size; 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: dip 0x%p msiq_id 0x%x\n", 7520Sstevel@tonic-gate dip, msiq_id); 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t); 7552755Segillett ra_p = (r_addr_t *)((caddr_t)msiq_state_p->msiq_buf_p + 7562755Segillett (msiq_id * msiq_size)); 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate *msiq_rec_cnt_p = msiq_state_p->msiq_rec_cnt; 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: ra_p 0x%p msiq_rec_cnt 0x%x\n", 7610Sstevel@tonic-gate ra_p, *msiq_rec_cnt_p); 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate return (DDI_SUCCESS); 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate /*ARGSUSED*/ 7670Sstevel@tonic-gate int 7680Sstevel@tonic-gate px_lib_msiq_getvalid(dev_info_t *dip, msiqid_t msiq_id, 7690Sstevel@tonic-gate pci_msiq_valid_state_t *msiq_valid_state) 7700Sstevel@tonic-gate { 7710Sstevel@tonic-gate uint64_t ret; 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: dip 0x%p msiq_id 0x%x\n", 7740Sstevel@tonic-gate dip, msiq_id); 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate if ((ret = hvio_msiq_getvalid(DIP_TO_HANDLE(dip), 7770Sstevel@tonic-gate msiq_id, msiq_valid_state)) != H_EOK) { 7780Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 7790Sstevel@tonic-gate "hvio_msiq_getvalid failed, ret 0x%lx\n", ret); 7800Sstevel@tonic-gate return (DDI_FAILURE); 7810Sstevel@tonic-gate } 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: msiq_valid_state 0x%x\n", 7840Sstevel@tonic-gate *msiq_valid_state); 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate return (DDI_SUCCESS); 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate /*ARGSUSED*/ 7900Sstevel@tonic-gate int 7910Sstevel@tonic-gate px_lib_msiq_setvalid(dev_info_t *dip, msiqid_t msiq_id, 7920Sstevel@tonic-gate pci_msiq_valid_state_t msiq_valid_state) 7930Sstevel@tonic-gate { 7940Sstevel@tonic-gate uint64_t ret; 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setvalid: dip 0x%p msiq_id 0x%x " 7970Sstevel@tonic-gate "msiq_valid_state 0x%x\n", dip, msiq_id, msiq_valid_state); 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate if ((ret = hvio_msiq_setvalid(DIP_TO_HANDLE(dip), 8000Sstevel@tonic-gate msiq_id, msiq_valid_state)) != H_EOK) { 8010Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8020Sstevel@tonic-gate "hvio_msiq_setvalid failed, ret 0x%lx\n", ret); 8030Sstevel@tonic-gate return (DDI_FAILURE); 8040Sstevel@tonic-gate } 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate return (DDI_SUCCESS); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate /*ARGSUSED*/ 8100Sstevel@tonic-gate int 8110Sstevel@tonic-gate px_lib_msiq_getstate(dev_info_t *dip, msiqid_t msiq_id, 8120Sstevel@tonic-gate pci_msiq_state_t *msiq_state) 8130Sstevel@tonic-gate { 8140Sstevel@tonic-gate uint64_t ret; 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: dip 0x%p msiq_id 0x%x\n", 8170Sstevel@tonic-gate dip, msiq_id); 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate if ((ret = hvio_msiq_getstate(DIP_TO_HANDLE(dip), 8200Sstevel@tonic-gate msiq_id, msiq_state)) != H_EOK) { 8210Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8220Sstevel@tonic-gate "hvio_msiq_getstate failed, ret 0x%lx\n", ret); 8230Sstevel@tonic-gate return (DDI_FAILURE); 8240Sstevel@tonic-gate } 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: msiq_state 0x%x\n", 8270Sstevel@tonic-gate *msiq_state); 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate return (DDI_SUCCESS); 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate /*ARGSUSED*/ 8330Sstevel@tonic-gate int 8340Sstevel@tonic-gate px_lib_msiq_setstate(dev_info_t *dip, msiqid_t msiq_id, 8350Sstevel@tonic-gate pci_msiq_state_t msiq_state) 8360Sstevel@tonic-gate { 8370Sstevel@tonic-gate uint64_t ret; 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setstate: dip 0x%p msiq_id 0x%x " 8400Sstevel@tonic-gate "msiq_state 0x%x\n", dip, msiq_id, msiq_state); 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate if ((ret = hvio_msiq_setstate(DIP_TO_HANDLE(dip), 8430Sstevel@tonic-gate msiq_id, msiq_state)) != H_EOK) { 8440Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8450Sstevel@tonic-gate "hvio_msiq_setstate failed, ret 0x%lx\n", ret); 8460Sstevel@tonic-gate return (DDI_FAILURE); 8470Sstevel@tonic-gate } 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate return (DDI_SUCCESS); 8500Sstevel@tonic-gate } 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate /*ARGSUSED*/ 8530Sstevel@tonic-gate int 8540Sstevel@tonic-gate px_lib_msiq_gethead(dev_info_t *dip, msiqid_t msiq_id, 8550Sstevel@tonic-gate msiqhead_t *msiq_head) 8560Sstevel@tonic-gate { 8570Sstevel@tonic-gate uint64_t ret; 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: dip 0x%p msiq_id 0x%x\n", 8600Sstevel@tonic-gate dip, msiq_id); 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate if ((ret = hvio_msiq_gethead(DIP_TO_HANDLE(dip), 8630Sstevel@tonic-gate msiq_id, msiq_head)) != H_EOK) { 8640Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8650Sstevel@tonic-gate "hvio_msiq_gethead failed, ret 0x%lx\n", ret); 8660Sstevel@tonic-gate return (DDI_FAILURE); 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: msiq_head 0x%x\n", 8700Sstevel@tonic-gate *msiq_head); 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate return (DDI_SUCCESS); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate /*ARGSUSED*/ 8760Sstevel@tonic-gate int 8770Sstevel@tonic-gate px_lib_msiq_sethead(dev_info_t *dip, msiqid_t msiq_id, 8780Sstevel@tonic-gate msiqhead_t msiq_head) 8790Sstevel@tonic-gate { 8800Sstevel@tonic-gate uint64_t ret; 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_sethead: dip 0x%p msiq_id 0x%x " 8830Sstevel@tonic-gate "msiq_head 0x%x\n", dip, msiq_id, msiq_head); 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate if ((ret = hvio_msiq_sethead(DIP_TO_HANDLE(dip), 8860Sstevel@tonic-gate msiq_id, msiq_head)) != H_EOK) { 8870Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8880Sstevel@tonic-gate "hvio_msiq_sethead failed, ret 0x%lx\n", ret); 8890Sstevel@tonic-gate return (DDI_FAILURE); 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate return (DDI_SUCCESS); 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate /*ARGSUSED*/ 8960Sstevel@tonic-gate int 8970Sstevel@tonic-gate px_lib_msiq_gettail(dev_info_t *dip, msiqid_t msiq_id, 8980Sstevel@tonic-gate msiqtail_t *msiq_tail) 8990Sstevel@tonic-gate { 9000Sstevel@tonic-gate uint64_t ret; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: dip 0x%p msiq_id 0x%x\n", 9030Sstevel@tonic-gate dip, msiq_id); 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate if ((ret = hvio_msiq_gettail(DIP_TO_HANDLE(dip), 9060Sstevel@tonic-gate msiq_id, msiq_tail)) != H_EOK) { 9070Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 9080Sstevel@tonic-gate "hvio_msiq_gettail failed, ret 0x%lx\n", ret); 9090Sstevel@tonic-gate return (DDI_FAILURE); 9100Sstevel@tonic-gate } 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: msiq_tail 0x%x\n", 9130Sstevel@tonic-gate *msiq_tail); 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate return (DDI_SUCCESS); 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate /*ARGSUSED*/ 9190Sstevel@tonic-gate void 9202588Segillett px_lib_get_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p, 9212588Segillett msiq_rec_t *msiq_rec_p) 9220Sstevel@tonic-gate { 9232588Segillett eq_rec_t *eq_rec_p = (eq_rec_t *)msiq_head_p; 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p eq_rec_p 0x%p\n", 9260Sstevel@tonic-gate dip, eq_rec_p); 9270Sstevel@tonic-gate 928287Smg140465 if (!eq_rec_p->eq_rec_fmt_type) { 929287Smg140465 /* Set msiq_rec_type to zero */ 930287Smg140465 msiq_rec_p->msiq_rec_type = 0; 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate return; 9330Sstevel@tonic-gate } 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: EQ RECORD, " 9360Sstevel@tonic-gate "eq_rec_rid 0x%llx eq_rec_fmt_type 0x%llx " 9370Sstevel@tonic-gate "eq_rec_len 0x%llx eq_rec_addr0 0x%llx " 9380Sstevel@tonic-gate "eq_rec_addr1 0x%llx eq_rec_data0 0x%llx " 9390Sstevel@tonic-gate "eq_rec_data1 0x%llx\n", eq_rec_p->eq_rec_rid, 9400Sstevel@tonic-gate eq_rec_p->eq_rec_fmt_type, eq_rec_p->eq_rec_len, 9410Sstevel@tonic-gate eq_rec_p->eq_rec_addr0, eq_rec_p->eq_rec_addr1, 9420Sstevel@tonic-gate eq_rec_p->eq_rec_data0, eq_rec_p->eq_rec_data1); 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate /* 9450Sstevel@tonic-gate * Only upper 4 bits of eq_rec_fmt_type is used 9460Sstevel@tonic-gate * to identify the EQ record type. 9470Sstevel@tonic-gate */ 9480Sstevel@tonic-gate switch (eq_rec_p->eq_rec_fmt_type >> 3) { 9490Sstevel@tonic-gate case EQ_REC_MSI32: 9500Sstevel@tonic-gate msiq_rec_p->msiq_rec_type = MSI32_REC; 9510Sstevel@tonic-gate 952225Sess msiq_rec_p->msiq_rec_data.msi.msi_data = 953225Sess eq_rec_p->eq_rec_data0; 9540Sstevel@tonic-gate break; 9550Sstevel@tonic-gate case EQ_REC_MSI64: 9560Sstevel@tonic-gate msiq_rec_p->msiq_rec_type = MSI64_REC; 9570Sstevel@tonic-gate 958225Sess msiq_rec_p->msiq_rec_data.msi.msi_data = 959225Sess eq_rec_p->eq_rec_data0; 9600Sstevel@tonic-gate break; 9610Sstevel@tonic-gate case EQ_REC_MSG: 9620Sstevel@tonic-gate msiq_rec_p->msiq_rec_type = MSG_REC; 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate msiq_rec_p->msiq_rec_data.msg.msg_route = 9650Sstevel@tonic-gate eq_rec_p->eq_rec_fmt_type & 7; 9660Sstevel@tonic-gate msiq_rec_p->msiq_rec_data.msg.msg_targ = eq_rec_p->eq_rec_rid; 9670Sstevel@tonic-gate msiq_rec_p->msiq_rec_data.msg.msg_code = eq_rec_p->eq_rec_data0; 9680Sstevel@tonic-gate break; 9690Sstevel@tonic-gate default: 9700Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_lib_get_msiq_rec: " 971671Skrishnae "0x%x is an unknown EQ record type", 9720Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 973671Skrishnae (int)eq_rec_p->eq_rec_fmt_type); 9740Sstevel@tonic-gate break; 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate msiq_rec_p->msiq_rec_rid = eq_rec_p->eq_rec_rid; 9780Sstevel@tonic-gate msiq_rec_p->msiq_rec_msi_addr = ((eq_rec_p->eq_rec_addr1 << 16) | 9790Sstevel@tonic-gate (eq_rec_p->eq_rec_addr0 << 2)); 9802973Sgovinda } 9812973Sgovinda 9822973Sgovinda /*ARGSUSED*/ 9832973Sgovinda void 9842973Sgovinda px_lib_clr_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p) 9852973Sgovinda { 9862973Sgovinda eq_rec_t *eq_rec_p = (eq_rec_t *)msiq_head_p; 9872973Sgovinda 9882973Sgovinda DBG(DBG_LIB_MSIQ, dip, "px_lib_clr_msiq_rec: dip 0x%p eq_rec_p 0x%p\n", 9892973Sgovinda dip, eq_rec_p); 9902973Sgovinda 9912973Sgovinda if (eq_rec_p->eq_rec_fmt_type) { 9922973Sgovinda /* Zero out eq_rec_fmt_type field */ 9932973Sgovinda eq_rec_p->eq_rec_fmt_type = 0; 9942973Sgovinda } 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate /* 9980Sstevel@tonic-gate * MSI Functions: 9990Sstevel@tonic-gate */ 10000Sstevel@tonic-gate /*ARGSUSED*/ 10010Sstevel@tonic-gate int 10020Sstevel@tonic-gate px_lib_msi_init(dev_info_t *dip) 10030Sstevel@tonic-gate { 10040Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 10050Sstevel@tonic-gate px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 10060Sstevel@tonic-gate uint64_t ret; 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_init: dip 0x%p\n", dip); 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate if ((ret = hvio_msi_init(DIP_TO_HANDLE(dip), 10110Sstevel@tonic-gate msi_state_p->msi_addr32, msi_state_p->msi_addr64)) != H_EOK) { 10120Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msi_init failed, ret 0x%lx\n", 10130Sstevel@tonic-gate ret); 10140Sstevel@tonic-gate return (DDI_FAILURE); 10150Sstevel@tonic-gate } 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate return (DDI_SUCCESS); 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate /*ARGSUSED*/ 10210Sstevel@tonic-gate int 10220Sstevel@tonic-gate px_lib_msi_getmsiq(dev_info_t *dip, msinum_t msi_num, 10230Sstevel@tonic-gate msiqid_t *msiq_id) 10240Sstevel@tonic-gate { 10250Sstevel@tonic-gate uint64_t ret; 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: dip 0x%p msi_num 0x%x\n", 10280Sstevel@tonic-gate dip, msi_num); 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate if ((ret = hvio_msi_getmsiq(DIP_TO_HANDLE(dip), 10310Sstevel@tonic-gate msi_num, msiq_id)) != H_EOK) { 10320Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10330Sstevel@tonic-gate "hvio_msi_getmsiq failed, ret 0x%lx\n", ret); 10340Sstevel@tonic-gate return (DDI_FAILURE); 10350Sstevel@tonic-gate } 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: msiq_id 0x%x\n", 10380Sstevel@tonic-gate *msiq_id); 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate return (DDI_SUCCESS); 10410Sstevel@tonic-gate } 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate /*ARGSUSED*/ 10440Sstevel@tonic-gate int 10450Sstevel@tonic-gate px_lib_msi_setmsiq(dev_info_t *dip, msinum_t msi_num, 10460Sstevel@tonic-gate msiqid_t msiq_id, msi_type_t msitype) 10470Sstevel@tonic-gate { 10480Sstevel@tonic-gate uint64_t ret; 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_setmsiq: dip 0x%p msi_num 0x%x " 10510Sstevel@tonic-gate "msq_id 0x%x\n", dip, msi_num, msiq_id); 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate if ((ret = hvio_msi_setmsiq(DIP_TO_HANDLE(dip), 10540Sstevel@tonic-gate msi_num, msiq_id)) != H_EOK) { 10550Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10560Sstevel@tonic-gate "hvio_msi_setmsiq failed, ret 0x%lx\n", ret); 10570Sstevel@tonic-gate return (DDI_FAILURE); 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate return (DDI_SUCCESS); 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate /*ARGSUSED*/ 10640Sstevel@tonic-gate int 10650Sstevel@tonic-gate px_lib_msi_getvalid(dev_info_t *dip, msinum_t msi_num, 10660Sstevel@tonic-gate pci_msi_valid_state_t *msi_valid_state) 10670Sstevel@tonic-gate { 10680Sstevel@tonic-gate uint64_t ret; 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: dip 0x%p msi_num 0x%x\n", 10710Sstevel@tonic-gate dip, msi_num); 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate if ((ret = hvio_msi_getvalid(DIP_TO_HANDLE(dip), 10740Sstevel@tonic-gate msi_num, msi_valid_state)) != H_EOK) { 10750Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10760Sstevel@tonic-gate "hvio_msi_getvalid failed, ret 0x%lx\n", ret); 10770Sstevel@tonic-gate return (DDI_FAILURE); 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: msiq_id 0x%x\n", 10810Sstevel@tonic-gate *msi_valid_state); 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate return (DDI_SUCCESS); 10840Sstevel@tonic-gate } 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate /*ARGSUSED*/ 10870Sstevel@tonic-gate int 10880Sstevel@tonic-gate px_lib_msi_setvalid(dev_info_t *dip, msinum_t msi_num, 10890Sstevel@tonic-gate pci_msi_valid_state_t msi_valid_state) 10900Sstevel@tonic-gate { 10910Sstevel@tonic-gate uint64_t ret; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_setvalid: dip 0x%p msi_num 0x%x " 10940Sstevel@tonic-gate "msi_valid_state 0x%x\n", dip, msi_num, msi_valid_state); 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate if ((ret = hvio_msi_setvalid(DIP_TO_HANDLE(dip), 10970Sstevel@tonic-gate msi_num, msi_valid_state)) != H_EOK) { 10980Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10990Sstevel@tonic-gate "hvio_msi_setvalid failed, ret 0x%lx\n", ret); 11000Sstevel@tonic-gate return (DDI_FAILURE); 11010Sstevel@tonic-gate } 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate return (DDI_SUCCESS); 11040Sstevel@tonic-gate } 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate /*ARGSUSED*/ 11070Sstevel@tonic-gate int 11080Sstevel@tonic-gate px_lib_msi_getstate(dev_info_t *dip, msinum_t msi_num, 11090Sstevel@tonic-gate pci_msi_state_t *msi_state) 11100Sstevel@tonic-gate { 11110Sstevel@tonic-gate uint64_t ret; 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: dip 0x%p msi_num 0x%x\n", 11140Sstevel@tonic-gate dip, msi_num); 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate if ((ret = hvio_msi_getstate(DIP_TO_HANDLE(dip), 11170Sstevel@tonic-gate msi_num, msi_state)) != H_EOK) { 11180Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 11190Sstevel@tonic-gate "hvio_msi_getstate failed, ret 0x%lx\n", ret); 11200Sstevel@tonic-gate return (DDI_FAILURE); 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: msi_state 0x%x\n", 11240Sstevel@tonic-gate *msi_state); 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate return (DDI_SUCCESS); 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate /*ARGSUSED*/ 11300Sstevel@tonic-gate int 11310Sstevel@tonic-gate px_lib_msi_setstate(dev_info_t *dip, msinum_t msi_num, 11320Sstevel@tonic-gate pci_msi_state_t msi_state) 11330Sstevel@tonic-gate { 11340Sstevel@tonic-gate uint64_t ret; 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_setstate: dip 0x%p msi_num 0x%x " 11370Sstevel@tonic-gate "msi_state 0x%x\n", dip, msi_num, msi_state); 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate if ((ret = hvio_msi_setstate(DIP_TO_HANDLE(dip), 11400Sstevel@tonic-gate msi_num, msi_state)) != H_EOK) { 11410Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 11420Sstevel@tonic-gate "hvio_msi_setstate failed, ret 0x%lx\n", ret); 11430Sstevel@tonic-gate return (DDI_FAILURE); 11440Sstevel@tonic-gate } 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate return (DDI_SUCCESS); 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate /* 11500Sstevel@tonic-gate * MSG Functions: 11510Sstevel@tonic-gate */ 11520Sstevel@tonic-gate /*ARGSUSED*/ 11530Sstevel@tonic-gate int 11540Sstevel@tonic-gate px_lib_msg_getmsiq(dev_info_t *dip, pcie_msg_type_t msg_type, 11550Sstevel@tonic-gate msiqid_t *msiq_id) 11560Sstevel@tonic-gate { 11570Sstevel@tonic-gate uint64_t ret; 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msg_getmsiq: dip 0x%p msg_type 0x%x\n", 11600Sstevel@tonic-gate dip, msg_type); 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate if ((ret = hvio_msg_getmsiq(DIP_TO_HANDLE(dip), 11630Sstevel@tonic-gate msg_type, msiq_id)) != H_EOK) { 11640Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 11650Sstevel@tonic-gate "hvio_msg_getmsiq failed, ret 0x%lx\n", ret); 11660Sstevel@tonic-gate return (DDI_FAILURE); 11670Sstevel@tonic-gate } 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msg_getmsiq: msiq_id 0x%x\n", 11700Sstevel@tonic-gate *msiq_id); 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate return (DDI_SUCCESS); 11730Sstevel@tonic-gate } 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate /*ARGSUSED*/ 11760Sstevel@tonic-gate int 11770Sstevel@tonic-gate px_lib_msg_setmsiq(dev_info_t *dip, pcie_msg_type_t msg_type, 11780Sstevel@tonic-gate msiqid_t msiq_id) 11790Sstevel@tonic-gate { 11800Sstevel@tonic-gate uint64_t ret; 11810Sstevel@tonic-gate 11820Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msi_setstate: dip 0x%p msg_type 0x%x " 11830Sstevel@tonic-gate "msiq_id 0x%x\n", dip, msg_type, msiq_id); 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate if ((ret = hvio_msg_setmsiq(DIP_TO_HANDLE(dip), 11860Sstevel@tonic-gate msg_type, msiq_id)) != H_EOK) { 11870Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 11880Sstevel@tonic-gate "hvio_msg_setmsiq failed, ret 0x%lx\n", ret); 11890Sstevel@tonic-gate return (DDI_FAILURE); 11900Sstevel@tonic-gate } 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate return (DDI_SUCCESS); 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate /*ARGSUSED*/ 11960Sstevel@tonic-gate int 11970Sstevel@tonic-gate px_lib_msg_getvalid(dev_info_t *dip, pcie_msg_type_t msg_type, 11980Sstevel@tonic-gate pcie_msg_valid_state_t *msg_valid_state) 11990Sstevel@tonic-gate { 12000Sstevel@tonic-gate uint64_t ret; 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msg_getvalid: dip 0x%p msg_type 0x%x\n", 12030Sstevel@tonic-gate dip, msg_type); 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate if ((ret = hvio_msg_getvalid(DIP_TO_HANDLE(dip), msg_type, 12060Sstevel@tonic-gate msg_valid_state)) != H_EOK) { 12070Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 12080Sstevel@tonic-gate "hvio_msg_getvalid failed, ret 0x%lx\n", ret); 12090Sstevel@tonic-gate return (DDI_FAILURE); 12100Sstevel@tonic-gate } 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msg_getvalid: msg_valid_state 0x%x\n", 12130Sstevel@tonic-gate *msg_valid_state); 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate return (DDI_SUCCESS); 12160Sstevel@tonic-gate } 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate /*ARGSUSED*/ 12190Sstevel@tonic-gate int 12200Sstevel@tonic-gate px_lib_msg_setvalid(dev_info_t *dip, pcie_msg_type_t msg_type, 12210Sstevel@tonic-gate pcie_msg_valid_state_t msg_valid_state) 12220Sstevel@tonic-gate { 12230Sstevel@tonic-gate uint64_t ret; 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msg_setvalid: dip 0x%p msg_type 0x%x " 12260Sstevel@tonic-gate "msg_valid_state 0x%x\n", dip, msg_type, msg_valid_state); 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate if ((ret = hvio_msg_setvalid(DIP_TO_HANDLE(dip), msg_type, 12290Sstevel@tonic-gate msg_valid_state)) != H_EOK) { 12300Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 12310Sstevel@tonic-gate "hvio_msg_setvalid failed, ret 0x%lx\n", ret); 12320Sstevel@tonic-gate return (DDI_FAILURE); 12330Sstevel@tonic-gate } 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate return (DDI_SUCCESS); 12360Sstevel@tonic-gate } 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate /* 12390Sstevel@tonic-gate * Suspend/Resume Functions: 12400Sstevel@tonic-gate * Currently unsupported by hypervisor 12410Sstevel@tonic-gate */ 12420Sstevel@tonic-gate int 12430Sstevel@tonic-gate px_lib_suspend(dev_info_t *dip) 12440Sstevel@tonic-gate { 12450Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 12460Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 12471648Sjchu px_cb_t *cb_p = PX2CB(px_p); 12480Sstevel@tonic-gate devhandle_t dev_hdl, xbus_dev_hdl; 12491648Sjchu uint64_t ret = H_EOK; 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate DBG(DBG_DETACH, dip, "px_lib_suspend: dip 0x%p\n", dip); 12520Sstevel@tonic-gate 125327Sjchu dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR]; 125427Sjchu xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC]; 12550Sstevel@tonic-gate 12561648Sjchu if ((ret = hvio_suspend(dev_hdl, pxu_p)) != H_EOK) 12571648Sjchu goto fail; 12581648Sjchu 12591648Sjchu if (--cb_p->attachcnt == 0) { 12601648Sjchu ret = hvio_cb_suspend(xbus_dev_hdl, pxu_p); 12611648Sjchu if (ret != H_EOK) 12621648Sjchu cb_p->attachcnt++; 12630Sstevel@tonic-gate } 12643274Set142600 pxu_p->cpr_flag = PX_ENTERED_CPR; 12650Sstevel@tonic-gate 12661648Sjchu fail: 12670Sstevel@tonic-gate return ((ret != H_EOK) ? DDI_FAILURE: DDI_SUCCESS); 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate void 12710Sstevel@tonic-gate px_lib_resume(dev_info_t *dip) 12720Sstevel@tonic-gate { 12730Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 12740Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 12751648Sjchu px_cb_t *cb_p = PX2CB(px_p); 12760Sstevel@tonic-gate devhandle_t dev_hdl, xbus_dev_hdl; 12770Sstevel@tonic-gate devino_t pec_ino = px_p->px_inos[PX_INTR_PEC]; 12780Sstevel@tonic-gate devino_t xbc_ino = px_p->px_inos[PX_INTR_XBC]; 12790Sstevel@tonic-gate 12800Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "px_lib_resume: dip 0x%p\n", dip); 12810Sstevel@tonic-gate 128227Sjchu dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR]; 128327Sjchu xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC]; 12840Sstevel@tonic-gate 12851648Sjchu if (++cb_p->attachcnt == 1) 12860Sstevel@tonic-gate hvio_cb_resume(dev_hdl, xbus_dev_hdl, xbc_ino, pxu_p); 12870Sstevel@tonic-gate 12881648Sjchu hvio_resume(dev_hdl, pec_ino, pxu_p); 12890Sstevel@tonic-gate } 12900Sstevel@tonic-gate 12911772Sjl139090 /* 12921772Sjl139090 * Generate a unique Oberon UBC ID based on the Logicial System Board and 12931772Sjl139090 * the IO Channel from the portid property field. 12941772Sjl139090 */ 12951772Sjl139090 static uint64_t 12961772Sjl139090 oberon_get_ubc_id(dev_info_t *dip) 12971772Sjl139090 { 12981772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 12991772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 13001772Sjl139090 uint64_t ubc_id; 13011772Sjl139090 13021772Sjl139090 /* 13031772Sjl139090 * Generate a unique 6 bit UBC ID using the 2 IO_Channel#[1:0] bits and 13041772Sjl139090 * the 4 LSB_ID[3:0] bits from the Oberon's portid property. 13051772Sjl139090 */ 13061772Sjl139090 ubc_id = (((pxu_p->portid >> OBERON_PORT_ID_IOC) & 13071772Sjl139090 OBERON_PORT_ID_IOC_MASK) | (((pxu_p->portid >> 13081772Sjl139090 OBERON_PORT_ID_LSB) & OBERON_PORT_ID_LSB_MASK) 13091772Sjl139090 << OBERON_UBC_ID_LSB)); 13101772Sjl139090 13111772Sjl139090 return (ubc_id); 13121772Sjl139090 } 13131772Sjl139090 13141772Sjl139090 /* 13151772Sjl139090 * Oberon does not have a UBC scratch register, so alloc an array of scratch 13161772Sjl139090 * registers when needed and use a unique UBC ID as an index. This code 13171772Sjl139090 * can be simplified if we use a pre-allocated array. They are currently 13181772Sjl139090 * being dynamically allocated because it's only needed by the Oberon. 13191772Sjl139090 */ 13201772Sjl139090 static void 13211772Sjl139090 oberon_set_cb(dev_info_t *dip, uint64_t val) 13221772Sjl139090 { 13231772Sjl139090 uint64_t ubc_id; 13241772Sjl139090 13251772Sjl139090 if (px_oberon_ubc_scratch_regs == NULL) 13261772Sjl139090 px_oberon_ubc_scratch_regs = 13271772Sjl139090 (uint64_t *)kmem_zalloc(sizeof (uint64_t)* 13281772Sjl139090 OBERON_UBC_ID_MAX, KM_SLEEP); 13291772Sjl139090 13301772Sjl139090 ubc_id = oberon_get_ubc_id(dip); 13311772Sjl139090 13321772Sjl139090 px_oberon_ubc_scratch_regs[ubc_id] = val; 13331772Sjl139090 13341772Sjl139090 /* 13351772Sjl139090 * Check if any scratch registers are still in use. If all scratch 13361772Sjl139090 * registers are currently set to zero, then deallocate the scratch 13371772Sjl139090 * register array. 13381772Sjl139090 */ 13391772Sjl139090 for (ubc_id = 0; ubc_id < OBERON_UBC_ID_MAX; ubc_id++) { 13401772Sjl139090 if (px_oberon_ubc_scratch_regs[ubc_id] != NULL) 13411772Sjl139090 return; 13421772Sjl139090 } 13431772Sjl139090 13441772Sjl139090 /* 13451772Sjl139090 * All scratch registers are set to zero so deallocate the scratch 13461772Sjl139090 * register array and set the pointer to NULL. 13471772Sjl139090 */ 13481772Sjl139090 kmem_free(px_oberon_ubc_scratch_regs, 13491772Sjl139090 (sizeof (uint64_t)*OBERON_UBC_ID_MAX)); 13501772Sjl139090 13511772Sjl139090 px_oberon_ubc_scratch_regs = NULL; 13521772Sjl139090 } 13531772Sjl139090 13541772Sjl139090 /* 13551772Sjl139090 * Oberon does not have a UBC scratch register, so use an allocated array of 13561772Sjl139090 * scratch registers and use the unique UBC ID as an index into that array. 13571772Sjl139090 */ 13581772Sjl139090 static uint64_t 13591772Sjl139090 oberon_get_cb(dev_info_t *dip) 13601772Sjl139090 { 13611772Sjl139090 uint64_t ubc_id; 13621772Sjl139090 13631772Sjl139090 if (px_oberon_ubc_scratch_regs == NULL) 13641772Sjl139090 return (0); 13651772Sjl139090 13661772Sjl139090 ubc_id = oberon_get_ubc_id(dip); 13671772Sjl139090 13681772Sjl139090 return (px_oberon_ubc_scratch_regs[ubc_id]); 13691772Sjl139090 } 13701772Sjl139090 13711772Sjl139090 /* 13721772Sjl139090 * Misc Functions: 13731772Sjl139090 * Currently unsupported by hypervisor 13741772Sjl139090 */ 13751772Sjl139090 static uint64_t 13761772Sjl139090 px_get_cb(dev_info_t *dip) 13771772Sjl139090 { 13781772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 13791772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 13801772Sjl139090 13811772Sjl139090 /* 13821772Sjl139090 * Oberon does not currently have Scratchpad registers. 13831772Sjl139090 */ 13841772Sjl139090 if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) 13851772Sjl139090 return (oberon_get_cb(dip)); 13861772Sjl139090 13871772Sjl139090 return (CSR_XR((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1)); 13881772Sjl139090 } 13891772Sjl139090 13901772Sjl139090 static void 13911772Sjl139090 px_set_cb(dev_info_t *dip, uint64_t val) 13921772Sjl139090 { 13931772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 13941772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 13951772Sjl139090 13961772Sjl139090 /* 13971772Sjl139090 * Oberon does not currently have Scratchpad registers. 13981772Sjl139090 */ 13991772Sjl139090 if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) { 14001772Sjl139090 oberon_set_cb(dip, val); 14011772Sjl139090 return; 14021772Sjl139090 } 14031772Sjl139090 14041772Sjl139090 CSR_XS((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1, val); 14051772Sjl139090 } 14061772Sjl139090 14070Sstevel@tonic-gate /*ARGSUSED*/ 14080Sstevel@tonic-gate int 14090Sstevel@tonic-gate px_lib_map_vconfig(dev_info_t *dip, 14100Sstevel@tonic-gate ddi_map_req_t *mp, pci_config_offset_t off, 14110Sstevel@tonic-gate pci_regspec_t *rp, caddr_t *addrp) 14120Sstevel@tonic-gate { 14130Sstevel@tonic-gate /* 14140Sstevel@tonic-gate * No special config space access services in this layer. 14150Sstevel@tonic-gate */ 14160Sstevel@tonic-gate return (DDI_FAILURE); 14170Sstevel@tonic-gate } 14180Sstevel@tonic-gate 1419624Sschwartz void 1420677Sjchu px_lib_map_attr_check(ddi_map_req_t *mp) 1421677Sjchu { 1422677Sjchu ddi_acc_hdl_t *hp = mp->map_handlep; 1423677Sjchu 1424677Sjchu /* fire does not accept byte masks from PIO store merge */ 1425677Sjchu if (hp->ah_acc.devacc_attr_dataorder == DDI_STORECACHING_OK_ACC) 1426677Sjchu hp->ah_acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1427677Sjchu } 1428677Sjchu 14293274Set142600 /* This function is called only by poke, caut put and pxtool poke. */ 1430677Sjchu void 14313274Set142600 px_lib_clr_errs(px_t *px_p, dev_info_t *rdip, uint64_t addr) 143227Sjchu { 1433624Sschwartz px_pec_t *pec_p = px_p->px_pec_p; 143427Sjchu dev_info_t *rpdip = px_p->px_dip; 14353274Set142600 int rc_err, fab_err, i; 143627Sjchu int acctype = pec_p->pec_safeacc_type; 143727Sjchu ddi_fm_error_t derr; 14383274Set142600 px_ranges_t *ranges_p; 14393274Set142600 int range_len; 14403274Set142600 uint32_t addr_high, addr_low; 14413274Set142600 pcie_req_id_t bdf = 0; 144227Sjchu 144327Sjchu /* Create the derr */ 144427Sjchu bzero(&derr, sizeof (ddi_fm_error_t)); 144527Sjchu derr.fme_version = DDI_FME_VERSION; 144627Sjchu derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 144727Sjchu derr.fme_flag = acctype; 144827Sjchu 144927Sjchu if (acctype == DDI_FM_ERR_EXPECTED) { 145027Sjchu derr.fme_status = DDI_FM_NONFATAL; 145127Sjchu ndi_fm_acc_err_set(pec_p->pec_acc_hdl, &derr); 145227Sjchu } 145327Sjchu 14541648Sjchu mutex_enter(&px_p->px_fm_mutex); 145527Sjchu 145627Sjchu /* send ereport/handle/clear fire registers */ 14573274Set142600 rc_err = px_err_cmn_intr(px_p, &derr, PX_LIB_CALL, PX_FM_BLOCK_ALL); 14583274Set142600 14593274Set142600 /* Figure out if this is a cfg or mem32 access */ 14603274Set142600 addr_high = (uint32_t)(addr >> 32); 14613274Set142600 addr_low = (uint32_t)addr; 14623274Set142600 range_len = px_p->px_ranges_length / sizeof (px_ranges_t); 14633274Set142600 i = 0; 14643274Set142600 for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) { 14653274Set142600 if (ranges_p->parent_high == addr_high) { 14663274Set142600 switch (ranges_p->child_high & PCI_ADDR_MASK) { 14673274Set142600 case PCI_ADDR_CONFIG: 14683274Set142600 bdf = (pcie_req_id_t)(addr_low >> 12); 14693274Set142600 addr_low = 0; 14703274Set142600 break; 14713274Set142600 case PCI_ADDR_MEM32: 14723274Set142600 if (rdip) 14733274Set142600 (void) pcie_get_bdf_from_dip(rdip, 14743274Set142600 &bdf); 14753274Set142600 else 14763274Set142600 bdf = NULL; 14773274Set142600 break; 14783274Set142600 } 14793274Set142600 break; 14803274Set142600 } 14813274Set142600 } 14823274Set142600 14833274Set142600 px_rp_en_q(px_p, bdf, addr_low, NULL); 14843274Set142600 14853274Set142600 /* 14863274Set142600 * XXX - Current code scans the fabric for all px_tool accesses. 14873274Set142600 * In future, do not scan fabric for px_tool access to IO Root Nexus 14883274Set142600 */ 14893274Set142600 fab_err = pf_scan_fabric(rpdip, &derr, px_p->px_dq_p, 14903274Set142600 &px_p->px_dq_tail); 14913272Sdduvall 14923272Sdduvall mutex_exit(&px_p->px_fm_mutex); 14933270Set142600 14943274Set142600 px_err_panic(rc_err, PX_RC, fab_err); 149527Sjchu } 149627Sjchu 14970Sstevel@tonic-gate #ifdef DEBUG 14980Sstevel@tonic-gate int px_peekfault_cnt = 0; 14990Sstevel@tonic-gate int px_pokefault_cnt = 0; 15000Sstevel@tonic-gate #endif /* DEBUG */ 15010Sstevel@tonic-gate 15020Sstevel@tonic-gate /*ARGSUSED*/ 15030Sstevel@tonic-gate static int 15040Sstevel@tonic-gate px_lib_do_poke(dev_info_t *dip, dev_info_t *rdip, 15050Sstevel@tonic-gate peekpoke_ctlops_t *in_args) 15060Sstevel@tonic-gate { 15070Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 15080Sstevel@tonic-gate px_pec_t *pec_p = px_p->px_pec_p; 15090Sstevel@tonic-gate int err = DDI_SUCCESS; 15100Sstevel@tonic-gate on_trap_data_t otd; 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate mutex_enter(&pec_p->pec_pokefault_mutex); 15130Sstevel@tonic-gate pec_p->pec_ontrap_data = &otd; 151427Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_POKE; 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate /* Set up protected environment. */ 15170Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 15180Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&poke_fault; 15210Sstevel@tonic-gate err = do_poke(in_args->size, (void *)in_args->dev_addr, 15220Sstevel@tonic-gate (void *)in_args->host_addr); 15230Sstevel@tonic-gate otd.ot_trampoline = tramp; 15240Sstevel@tonic-gate } else 15250Sstevel@tonic-gate err = DDI_FAILURE; 15260Sstevel@tonic-gate 15273274Set142600 px_lib_clr_errs(px_p, rdip, in_args->dev_addr); 152827Sjchu 15290Sstevel@tonic-gate if (otd.ot_trap & OT_DATA_ACCESS) 15300Sstevel@tonic-gate err = DDI_FAILURE; 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate /* Take down protected environment. */ 15330Sstevel@tonic-gate no_trap(); 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate pec_p->pec_ontrap_data = NULL; 153627Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 15370Sstevel@tonic-gate mutex_exit(&pec_p->pec_pokefault_mutex); 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate #ifdef DEBUG 15400Sstevel@tonic-gate if (err == DDI_FAILURE) 15410Sstevel@tonic-gate px_pokefault_cnt++; 15420Sstevel@tonic-gate #endif 15430Sstevel@tonic-gate return (err); 15440Sstevel@tonic-gate } 15450Sstevel@tonic-gate 15460Sstevel@tonic-gate /*ARGSUSED*/ 15470Sstevel@tonic-gate static int 15480Sstevel@tonic-gate px_lib_do_caut_put(dev_info_t *dip, dev_info_t *rdip, 15490Sstevel@tonic-gate peekpoke_ctlops_t *cautacc_ctlops_arg) 15500Sstevel@tonic-gate { 15510Sstevel@tonic-gate size_t size = cautacc_ctlops_arg->size; 15520Sstevel@tonic-gate uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 15530Sstevel@tonic-gate uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 15540Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 15550Sstevel@tonic-gate size_t repcount = cautacc_ctlops_arg->repcount; 15560Sstevel@tonic-gate uint_t flags = cautacc_ctlops_arg->flags; 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 15590Sstevel@tonic-gate px_pec_t *pec_p = px_p->px_pec_p; 15600Sstevel@tonic-gate int err = DDI_SUCCESS; 15610Sstevel@tonic-gate 156227Sjchu /* 156327Sjchu * Note that i_ndi_busop_access_enter ends up grabbing the pokefault 156427Sjchu * mutex. 156527Sjchu */ 15660Sstevel@tonic-gate i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 15670Sstevel@tonic-gate 156827Sjchu pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap; 156927Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED; 157027Sjchu hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 15710Sstevel@tonic-gate 15720Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 15730Sstevel@tonic-gate for (; repcount; repcount--) { 15740Sstevel@tonic-gate switch (size) { 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate case sizeof (uint8_t): 15770Sstevel@tonic-gate i_ddi_put8(hp, (uint8_t *)dev_addr, 15780Sstevel@tonic-gate *(uint8_t *)host_addr); 15790Sstevel@tonic-gate break; 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate case sizeof (uint16_t): 15820Sstevel@tonic-gate i_ddi_put16(hp, (uint16_t *)dev_addr, 15830Sstevel@tonic-gate *(uint16_t *)host_addr); 15840Sstevel@tonic-gate break; 15850Sstevel@tonic-gate 15860Sstevel@tonic-gate case sizeof (uint32_t): 15870Sstevel@tonic-gate i_ddi_put32(hp, (uint32_t *)dev_addr, 15880Sstevel@tonic-gate *(uint32_t *)host_addr); 15890Sstevel@tonic-gate break; 15900Sstevel@tonic-gate 15910Sstevel@tonic-gate case sizeof (uint64_t): 15920Sstevel@tonic-gate i_ddi_put64(hp, (uint64_t *)dev_addr, 15930Sstevel@tonic-gate *(uint64_t *)host_addr); 15940Sstevel@tonic-gate break; 15950Sstevel@tonic-gate } 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate host_addr += size; 15980Sstevel@tonic-gate 15990Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 16000Sstevel@tonic-gate dev_addr += size; 16010Sstevel@tonic-gate 16023274Set142600 px_lib_clr_errs(px_p, rdip, dev_addr); 160327Sjchu 16040Sstevel@tonic-gate if (pec_p->pec_ontrap_data->ot_trap & OT_DATA_ACCESS) { 16050Sstevel@tonic-gate err = DDI_FAILURE; 16060Sstevel@tonic-gate #ifdef DEBUG 16070Sstevel@tonic-gate px_pokefault_cnt++; 16080Sstevel@tonic-gate #endif 16090Sstevel@tonic-gate break; 16100Sstevel@tonic-gate } 16110Sstevel@tonic-gate } 16120Sstevel@tonic-gate } 16130Sstevel@tonic-gate 16140Sstevel@tonic-gate i_ddi_notrap((ddi_acc_handle_t)hp); 16150Sstevel@tonic-gate pec_p->pec_ontrap_data = NULL; 161627Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 16170Sstevel@tonic-gate i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 16180Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate return (err); 16210Sstevel@tonic-gate } 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate int 16250Sstevel@tonic-gate px_lib_ctlops_poke(dev_info_t *dip, dev_info_t *rdip, 16260Sstevel@tonic-gate peekpoke_ctlops_t *in_args) 16270Sstevel@tonic-gate { 16280Sstevel@tonic-gate return (in_args->handle ? px_lib_do_caut_put(dip, rdip, in_args) : 16290Sstevel@tonic-gate px_lib_do_poke(dip, rdip, in_args)); 16300Sstevel@tonic-gate } 16310Sstevel@tonic-gate 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate /*ARGSUSED*/ 16340Sstevel@tonic-gate static int 16350Sstevel@tonic-gate px_lib_do_peek(dev_info_t *dip, peekpoke_ctlops_t *in_args) 16360Sstevel@tonic-gate { 163727Sjchu px_t *px_p = DIP_TO_STATE(dip); 163827Sjchu px_pec_t *pec_p = px_p->px_pec_p; 16390Sstevel@tonic-gate int err = DDI_SUCCESS; 16400Sstevel@tonic-gate on_trap_data_t otd; 16410Sstevel@tonic-gate 164227Sjchu mutex_enter(&pec_p->pec_pokefault_mutex); 16433613Set142600 mutex_enter(&px_p->px_fm_mutex); 164427Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK; 16453613Set142600 mutex_exit(&px_p->px_fm_mutex); 164627Sjchu 16470Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 16480Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&peek_fault; 16510Sstevel@tonic-gate err = do_peek(in_args->size, (void *)in_args->dev_addr, 16520Sstevel@tonic-gate (void *)in_args->host_addr); 16530Sstevel@tonic-gate otd.ot_trampoline = tramp; 16540Sstevel@tonic-gate } else 16550Sstevel@tonic-gate err = DDI_FAILURE; 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate no_trap(); 165827Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 165927Sjchu mutex_exit(&pec_p->pec_pokefault_mutex); 16600Sstevel@tonic-gate 16610Sstevel@tonic-gate #ifdef DEBUG 16620Sstevel@tonic-gate if (err == DDI_FAILURE) 16630Sstevel@tonic-gate px_peekfault_cnt++; 16640Sstevel@tonic-gate #endif 16650Sstevel@tonic-gate return (err); 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate 16690Sstevel@tonic-gate static int 16700Sstevel@tonic-gate px_lib_do_caut_get(dev_info_t *dip, peekpoke_ctlops_t *cautacc_ctlops_arg) 16710Sstevel@tonic-gate { 16720Sstevel@tonic-gate size_t size = cautacc_ctlops_arg->size; 16730Sstevel@tonic-gate uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 16740Sstevel@tonic-gate uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 16750Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 16760Sstevel@tonic-gate size_t repcount = cautacc_ctlops_arg->repcount; 16770Sstevel@tonic-gate uint_t flags = cautacc_ctlops_arg->flags; 16780Sstevel@tonic-gate 16790Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 16800Sstevel@tonic-gate px_pec_t *pec_p = px_p->px_pec_p; 16810Sstevel@tonic-gate int err = DDI_SUCCESS; 16820Sstevel@tonic-gate 168327Sjchu /* 168427Sjchu * Note that i_ndi_busop_access_enter ends up grabbing the pokefault 168527Sjchu * mutex. 168627Sjchu */ 168727Sjchu i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 168827Sjchu 168927Sjchu pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap; 169027Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED; 16910Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 16920Sstevel@tonic-gate 16930Sstevel@tonic-gate if (repcount == 1) { 16940Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 16950Sstevel@tonic-gate i_ddi_caut_get(size, (void *)dev_addr, 16960Sstevel@tonic-gate (void *)host_addr); 16970Sstevel@tonic-gate } else { 16980Sstevel@tonic-gate int i; 16990Sstevel@tonic-gate uint8_t *ff_addr = (uint8_t *)host_addr; 17000Sstevel@tonic-gate for (i = 0; i < size; i++) 17010Sstevel@tonic-gate *ff_addr++ = 0xff; 17020Sstevel@tonic-gate 17030Sstevel@tonic-gate err = DDI_FAILURE; 17040Sstevel@tonic-gate #ifdef DEBUG 17050Sstevel@tonic-gate px_peekfault_cnt++; 17060Sstevel@tonic-gate #endif 17070Sstevel@tonic-gate } 17080Sstevel@tonic-gate } else { 17090Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 17100Sstevel@tonic-gate for (; repcount; repcount--) { 17110Sstevel@tonic-gate i_ddi_caut_get(size, (void *)dev_addr, 17120Sstevel@tonic-gate (void *)host_addr); 17130Sstevel@tonic-gate 17140Sstevel@tonic-gate host_addr += size; 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 17170Sstevel@tonic-gate dev_addr += size; 17180Sstevel@tonic-gate } 17190Sstevel@tonic-gate } else { 17200Sstevel@tonic-gate err = DDI_FAILURE; 17210Sstevel@tonic-gate #ifdef DEBUG 17220Sstevel@tonic-gate px_peekfault_cnt++; 17230Sstevel@tonic-gate #endif 17240Sstevel@tonic-gate } 17250Sstevel@tonic-gate } 17260Sstevel@tonic-gate 17270Sstevel@tonic-gate i_ddi_notrap((ddi_acc_handle_t)hp); 17280Sstevel@tonic-gate pec_p->pec_ontrap_data = NULL; 172927Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 17300Sstevel@tonic-gate i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 17310Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 17320Sstevel@tonic-gate 17330Sstevel@tonic-gate return (err); 17340Sstevel@tonic-gate } 17350Sstevel@tonic-gate 17360Sstevel@tonic-gate /*ARGSUSED*/ 17370Sstevel@tonic-gate int 17380Sstevel@tonic-gate px_lib_ctlops_peek(dev_info_t *dip, dev_info_t *rdip, 17390Sstevel@tonic-gate peekpoke_ctlops_t *in_args, void *result) 17400Sstevel@tonic-gate { 17410Sstevel@tonic-gate result = (void *)in_args->host_addr; 17420Sstevel@tonic-gate return (in_args->handle ? px_lib_do_caut_get(dip, in_args) : 17430Sstevel@tonic-gate px_lib_do_peek(dip, in_args)); 17440Sstevel@tonic-gate } 1745118Sjchu 17460Sstevel@tonic-gate /* 17470Sstevel@tonic-gate * implements PPM interface 17480Sstevel@tonic-gate */ 17490Sstevel@tonic-gate int 17500Sstevel@tonic-gate px_lib_pmctl(int cmd, px_t *px_p) 17510Sstevel@tonic-gate { 17520Sstevel@tonic-gate ASSERT((cmd & ~PPMREQ_MASK) == PPMREQ); 17530Sstevel@tonic-gate switch (cmd) { 17540Sstevel@tonic-gate case PPMREQ_PRE_PWR_OFF: 17550Sstevel@tonic-gate /* 17560Sstevel@tonic-gate * Currently there is no device power management for 17570Sstevel@tonic-gate * the root complex (fire). When there is we need to make 17580Sstevel@tonic-gate * sure that it is at full power before trying to send the 17590Sstevel@tonic-gate * PME_Turn_Off message. 17600Sstevel@tonic-gate */ 17610Sstevel@tonic-gate DBG(DBG_PWR, px_p->px_dip, 17620Sstevel@tonic-gate "ioctl: request to send PME_Turn_Off\n"); 17630Sstevel@tonic-gate return (px_goto_l23ready(px_p)); 17640Sstevel@tonic-gate 17650Sstevel@tonic-gate case PPMREQ_PRE_PWR_ON: 1766118Sjchu DBG(DBG_PWR, px_p->px_dip, "ioctl: PRE_PWR_ON request\n"); 1767118Sjchu return (px_pre_pwron_check(px_p)); 1768118Sjchu 17690Sstevel@tonic-gate case PPMREQ_POST_PWR_ON: 1770118Sjchu DBG(DBG_PWR, px_p->px_dip, "ioctl: POST_PWR_ON request\n"); 1771118Sjchu return (px_goto_l0(px_p)); 17720Sstevel@tonic-gate 17730Sstevel@tonic-gate default: 17740Sstevel@tonic-gate return (DDI_FAILURE); 17750Sstevel@tonic-gate } 17760Sstevel@tonic-gate } 17770Sstevel@tonic-gate 17780Sstevel@tonic-gate /* 17790Sstevel@tonic-gate * sends PME_Turn_Off message to put the link in L2/L3 ready state. 17800Sstevel@tonic-gate * called by px_ioctl. 17810Sstevel@tonic-gate * returns DDI_SUCCESS or DDI_FAILURE 17820Sstevel@tonic-gate * 1. Wait for link to be in L1 state (link status reg) 17830Sstevel@tonic-gate * 2. write to PME_Turn_off reg to boradcast 17840Sstevel@tonic-gate * 3. set timeout 17850Sstevel@tonic-gate * 4. If timeout, return failure. 17860Sstevel@tonic-gate * 5. If PM_TO_Ack, wait till link is in L2/L3 ready 17870Sstevel@tonic-gate */ 17880Sstevel@tonic-gate static int 17890Sstevel@tonic-gate px_goto_l23ready(px_t *px_p) 17900Sstevel@tonic-gate { 17910Sstevel@tonic-gate pcie_pwr_t *pwr_p; 179227Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 179327Sjchu caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 17940Sstevel@tonic-gate int ret = DDI_SUCCESS; 17950Sstevel@tonic-gate clock_t end, timeleft; 1796118Sjchu int mutex_held = 1; 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate /* If no PM info, return failure */ 17990Sstevel@tonic-gate if (!PCIE_PMINFO(px_p->px_dip) || 18000Sstevel@tonic-gate !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) 18010Sstevel@tonic-gate return (DDI_FAILURE); 18020Sstevel@tonic-gate 18030Sstevel@tonic-gate mutex_enter(&pwr_p->pwr_lock); 1804118Sjchu mutex_enter(&px_p->px_l23ready_lock); 18050Sstevel@tonic-gate /* Clear the PME_To_ACK receieved flag */ 1806118Sjchu px_p->px_pm_flags &= ~PX_PMETOACK_RECVD; 1807287Smg140465 /* 1808287Smg140465 * When P25 is the downstream device, after receiving 1809287Smg140465 * PME_To_ACK, fire will go to Detect state, which causes 1810287Smg140465 * the link down event. Inform FMA that this is expected. 1811287Smg140465 * In case of all other cards complaint with the pci express 1812287Smg140465 * spec, this will happen when the power is re-applied. FMA 1813287Smg140465 * code will clear this flag after one instance of LDN. Since 1814287Smg140465 * there will not be a LDN event for the spec compliant cards, 1815287Smg140465 * we need to clear the flag after receiving PME_To_ACK. 1816287Smg140465 */ 1817287Smg140465 px_p->px_pm_flags |= PX_LDN_EXPECTED; 18180Sstevel@tonic-gate if (px_send_pme_turnoff(csr_base) != DDI_SUCCESS) { 18190Sstevel@tonic-gate ret = DDI_FAILURE; 18200Sstevel@tonic-gate goto l23ready_done; 18210Sstevel@tonic-gate } 1822118Sjchu px_p->px_pm_flags |= PX_PME_TURNOFF_PENDING; 18230Sstevel@tonic-gate 18240Sstevel@tonic-gate end = ddi_get_lbolt() + drv_usectohz(px_pme_to_ack_timeout); 1825118Sjchu while (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { 1826118Sjchu timeleft = cv_timedwait(&px_p->px_l23ready_cv, 1827118Sjchu &px_p->px_l23ready_lock, end); 18280Sstevel@tonic-gate /* 18290Sstevel@tonic-gate * if cv_timedwait returns -1, it is either 18300Sstevel@tonic-gate * 1) timed out or 18310Sstevel@tonic-gate * 2) there was a pre-mature wakeup but by the time 18320Sstevel@tonic-gate * cv_timedwait is called again end < lbolt i.e. 18330Sstevel@tonic-gate * end is in the past. 18340Sstevel@tonic-gate * 3) By the time we make first cv_timedwait call, 18350Sstevel@tonic-gate * end < lbolt is true. 18360Sstevel@tonic-gate */ 18370Sstevel@tonic-gate if (timeleft == -1) 18380Sstevel@tonic-gate break; 18390Sstevel@tonic-gate } 1840118Sjchu if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { 18410Sstevel@tonic-gate /* 18420Sstevel@tonic-gate * Either timedout or interrupt didn't get a 18430Sstevel@tonic-gate * chance to grab the mutex and set the flag. 18440Sstevel@tonic-gate * release the mutex and delay for sometime. 18450Sstevel@tonic-gate * This will 1) give a chance for interrupt to 18460Sstevel@tonic-gate * set the flag 2) creates a delay between two 18470Sstevel@tonic-gate * consequetive requests. 18480Sstevel@tonic-gate */ 1849118Sjchu mutex_exit(&px_p->px_l23ready_lock); 18501147Sjchu delay(drv_usectohz(50 * PX_MSEC_TO_USEC)); 1851118Sjchu mutex_held = 0; 1852118Sjchu if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { 18530Sstevel@tonic-gate ret = DDI_FAILURE; 18540Sstevel@tonic-gate DBG(DBG_PWR, px_p->px_dip, " Timed out while waiting" 18550Sstevel@tonic-gate " for PME_TO_ACK\n"); 18560Sstevel@tonic-gate } 18570Sstevel@tonic-gate } 1858287Smg140465 px_p->px_pm_flags &= 1859287Smg140465 ~(PX_PME_TURNOFF_PENDING | PX_PMETOACK_RECVD | PX_LDN_EXPECTED); 18600Sstevel@tonic-gate 18610Sstevel@tonic-gate l23ready_done: 1862118Sjchu if (mutex_held) 1863118Sjchu mutex_exit(&px_p->px_l23ready_lock); 1864118Sjchu /* 1865118Sjchu * Wait till link is in L1 idle, if sending PME_Turn_Off 1866118Sjchu * was succesful. 1867118Sjchu */ 1868118Sjchu if (ret == DDI_SUCCESS) { 1869118Sjchu if (px_link_wait4l1idle(csr_base) != DDI_SUCCESS) { 1870118Sjchu DBG(DBG_PWR, px_p->px_dip, " Link is not at L1" 1871287Smg140465 " even though we received PME_To_ACK.\n"); 1872287Smg140465 /* 1873287Smg140465 * Workaround for hardware bug with P25. 1874287Smg140465 * Due to a hardware bug with P25, link state 1875287Smg140465 * will be Detect state rather than L1 after 1876287Smg140465 * link is transitioned to L23Ready state. Since 1877287Smg140465 * we don't know whether link is L23ready state 1878287Smg140465 * without Fire's state being L1_idle, we delay 1879287Smg140465 * here just to make sure that we wait till link 1880287Smg140465 * is transitioned to L23Ready state. 1881287Smg140465 */ 18821147Sjchu delay(drv_usectohz(100 * PX_MSEC_TO_USEC)); 1883287Smg140465 } 1884287Smg140465 pwr_p->pwr_link_lvl = PM_LEVEL_L3; 1885118Sjchu 1886118Sjchu } 18870Sstevel@tonic-gate mutex_exit(&pwr_p->pwr_lock); 18880Sstevel@tonic-gate return (ret); 18890Sstevel@tonic-gate } 18900Sstevel@tonic-gate 1891118Sjchu /* 1892118Sjchu * Message interrupt handler intended to be shared for both 1893118Sjchu * PME and PME_TO_ACK msg handling, currently only handles 1894118Sjchu * PME_To_ACK message. 1895118Sjchu */ 1896118Sjchu uint_t 1897118Sjchu px_pmeq_intr(caddr_t arg) 1898118Sjchu { 1899118Sjchu px_t *px_p = (px_t *)arg; 1900118Sjchu 1901287Smg140465 DBG(DBG_PWR, px_p->px_dip, " PME_To_ACK received \n"); 1902118Sjchu mutex_enter(&px_p->px_l23ready_lock); 1903118Sjchu cv_broadcast(&px_p->px_l23ready_cv); 1904118Sjchu if (px_p->px_pm_flags & PX_PME_TURNOFF_PENDING) { 1905118Sjchu px_p->px_pm_flags |= PX_PMETOACK_RECVD; 1906118Sjchu } else { 1907118Sjchu /* 1908118Sjchu * This maybe the second ack received. If so then, 1909118Sjchu * we should be receiving it during wait4L1 stage. 1910118Sjchu */ 1911118Sjchu px_p->px_pmetoack_ignored++; 1912118Sjchu } 1913118Sjchu mutex_exit(&px_p->px_l23ready_lock); 1914118Sjchu return (DDI_INTR_CLAIMED); 1915118Sjchu } 1916118Sjchu 1917118Sjchu static int 1918118Sjchu px_pre_pwron_check(px_t *px_p) 1919118Sjchu { 1920118Sjchu pcie_pwr_t *pwr_p; 1921118Sjchu 1922118Sjchu /* If no PM info, return failure */ 1923118Sjchu if (!PCIE_PMINFO(px_p->px_dip) || 1924118Sjchu !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) 1925118Sjchu return (DDI_FAILURE); 1926118Sjchu 1927287Smg140465 /* 1928287Smg140465 * For the spec compliant downstream cards link down 1929287Smg140465 * is expected when the device is powered on. 1930287Smg140465 */ 1931287Smg140465 px_p->px_pm_flags |= PX_LDN_EXPECTED; 1932118Sjchu return (pwr_p->pwr_link_lvl == PM_LEVEL_L3 ? DDI_SUCCESS : DDI_FAILURE); 1933118Sjchu } 1934118Sjchu 1935118Sjchu static int 1936118Sjchu px_goto_l0(px_t *px_p) 1937118Sjchu { 1938118Sjchu pcie_pwr_t *pwr_p; 1939118Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 1940118Sjchu caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 1941118Sjchu int ret = DDI_SUCCESS; 19421147Sjchu uint64_t time_spent = 0; 1943118Sjchu 1944118Sjchu /* If no PM info, return failure */ 1945118Sjchu if (!PCIE_PMINFO(px_p->px_dip) || 1946118Sjchu !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) 1947118Sjchu return (DDI_FAILURE); 1948118Sjchu 1949118Sjchu mutex_enter(&pwr_p->pwr_lock); 1950287Smg140465 /* 19511147Sjchu * The following link retrain activity will cause LDN and LUP event. 19521147Sjchu * Receiving LDN prior to receiving LUP is expected, not an error in 19531147Sjchu * this case. Receiving LUP indicates link is fully up to support 19541147Sjchu * powering up down stream device, and of course any further LDN and 19551147Sjchu * LUP outside this context will be error. 1956287Smg140465 */ 19571147Sjchu px_p->px_lup_pending = 1; 1958118Sjchu if (px_link_retrain(csr_base) != DDI_SUCCESS) { 1959118Sjchu ret = DDI_FAILURE; 1960118Sjchu goto l0_done; 1961118Sjchu } 1962118Sjchu 19631147Sjchu /* LUP event takes the order of 15ms amount of time to occur */ 19641147Sjchu for (; px_p->px_lup_pending && (time_spent < px_lup_poll_to); 19651147Sjchu time_spent += px_lup_poll_interval) 19661147Sjchu drv_usecwait(px_lup_poll_interval); 19671147Sjchu if (px_p->px_lup_pending) 19681147Sjchu ret = DDI_FAILURE; 1969118Sjchu l0_done: 1970287Smg140465 px_enable_detect_quiet(csr_base); 1971118Sjchu if (ret == DDI_SUCCESS) 1972287Smg140465 pwr_p->pwr_link_lvl = PM_LEVEL_L0; 1973118Sjchu mutex_exit(&pwr_p->pwr_lock); 1974118Sjchu return (ret); 1975118Sjchu } 1976118Sjchu 19770Sstevel@tonic-gate /* 19780Sstevel@tonic-gate * Extract the drivers binding name to identify which chip we're binding to. 19790Sstevel@tonic-gate * Whenever a new bus bridge is created, the driver alias entry should be 19800Sstevel@tonic-gate * added here to identify the device if needed. If a device isn't added, 19810Sstevel@tonic-gate * the identity defaults to PX_CHIP_UNIDENTIFIED. 19820Sstevel@tonic-gate */ 19830Sstevel@tonic-gate static uint32_t 19842426Sschwartz px_identity_init(px_t *px_p) 19850Sstevel@tonic-gate { 19860Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 19870Sstevel@tonic-gate char *name = ddi_binding_name(dip); 19880Sstevel@tonic-gate uint32_t revision = 0; 19890Sstevel@tonic-gate 19900Sstevel@tonic-gate revision = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 19910Sstevel@tonic-gate "module-revision#", 0); 19920Sstevel@tonic-gate 19930Sstevel@tonic-gate /* Check for Fire driver binding name */ 19942426Sschwartz if (strcmp(name, "pciex108e,80f0") == 0) { 19952426Sschwartz DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: " 19962426Sschwartz "(FIRE), module-revision %d\n", NAMEINST(dip), 19972426Sschwartz revision); 19982426Sschwartz 19992426Sschwartz return ((revision >= FIRE_MOD_REV_20) ? 20002426Sschwartz PX_CHIP_FIRE : PX_CHIP_UNIDENTIFIED); 20010Sstevel@tonic-gate } 20020Sstevel@tonic-gate 20031772Sjl139090 /* Check for Oberon driver binding name */ 20041772Sjl139090 if (strcmp(name, "pciex108e,80f8") == 0) { 20052426Sschwartz DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: " 20062426Sschwartz "(OBERON), module-revision %d\n", NAMEINST(dip), 20072426Sschwartz revision); 20082426Sschwartz 20092426Sschwartz return (PX_CHIP_OBERON); 20101772Sjl139090 } 20111772Sjl139090 20120Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "%s%d: Unknown PCI Express Host bridge %s %x\n", 20130Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), name, revision); 20140Sstevel@tonic-gate 20150Sstevel@tonic-gate return (PX_CHIP_UNIDENTIFIED); 20160Sstevel@tonic-gate } 201727Sjchu 201827Sjchu int 201927Sjchu px_err_add_intr(px_fault_t *px_fault_p) 202027Sjchu { 202127Sjchu dev_info_t *dip = px_fault_p->px_fh_dip; 202227Sjchu px_t *px_p = DIP_TO_STATE(dip); 202327Sjchu 202427Sjchu VERIFY(add_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL, 20252973Sgovinda (intrfunc)px_fault_p->px_err_func, (caddr_t)px_fault_p, 20262973Sgovinda NULL, NULL) == 0); 202727Sjchu 202827Sjchu px_ib_intr_enable(px_p, intr_dist_cpuid(), px_fault_p->px_intr_ino); 202927Sjchu 203027Sjchu return (DDI_SUCCESS); 203127Sjchu } 203227Sjchu 203327Sjchu void 203427Sjchu px_err_rem_intr(px_fault_t *px_fault_p) 203527Sjchu { 203627Sjchu dev_info_t *dip = px_fault_p->px_fh_dip; 203727Sjchu px_t *px_p = DIP_TO_STATE(dip); 203827Sjchu 203927Sjchu px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino, 204027Sjchu IB_INTR_WAIT); 2041965Sgovinda 20422973Sgovinda VERIFY(rem_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL) == 0); 204327Sjchu } 204427Sjchu 20451648Sjchu /* 20463623Sjchu * px_cb_intr_redist() - sun4u only, CB interrupt redistribution 20473623Sjchu */ 20483623Sjchu void 20493623Sjchu px_cb_intr_redist(void *arg) 20503623Sjchu { 20513623Sjchu px_cb_t *cb_p = (px_cb_t *)arg; 20523623Sjchu px_cb_list_t *pxl; 20533623Sjchu px_t *pxp = NULL; 20543623Sjchu px_fault_t *f_p = NULL; 20553623Sjchu uint32_t new_cpuid; 20563623Sjchu intr_valid_state_t enabled = 0; 20573623Sjchu 20583623Sjchu mutex_enter(&cb_p->cb_mutex); 20593623Sjchu 20603623Sjchu pxl = cb_p->pxl; 20613623Sjchu if (!pxl) 20623623Sjchu goto cb_done; 20633623Sjchu 20643623Sjchu pxp = pxl->pxp; 20653623Sjchu f_p = &pxp->px_cb_fault; 20663623Sjchu for (; pxl && (f_p->px_fh_sysino != cb_p->sysino); ) { 20673623Sjchu pxl = pxl->next; 20683623Sjchu pxp = pxl->pxp; 20693623Sjchu f_p = &pxp->px_cb_fault; 20703623Sjchu } 20713623Sjchu if (pxl == NULL) 20723623Sjchu goto cb_done; 20733623Sjchu 20743623Sjchu new_cpuid = intr_dist_cpuid(); 20753623Sjchu if (new_cpuid == cb_p->cpuid) 20763623Sjchu goto cb_done; 20773623Sjchu 20783623Sjchu if ((px_lib_intr_getvalid(pxp->px_dip, f_p->px_fh_sysino, &enabled) 20793623Sjchu != DDI_SUCCESS) || !enabled) { 20803623Sjchu DBG(DBG_IB, pxp->px_dip, "px_cb_intr_redist: CB not enabled, " 20813623Sjchu "sysino(0x%x)\n", f_p->px_fh_sysino); 20823623Sjchu goto cb_done; 20833623Sjchu } 20843623Sjchu 20853623Sjchu PX_INTR_DISABLE(pxp->px_dip, f_p->px_fh_sysino); 20863623Sjchu 20873623Sjchu cb_p->cpuid = new_cpuid; 20883623Sjchu cb_p->sysino = f_p->px_fh_sysino; 20893623Sjchu PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid); 20903623Sjchu 20913623Sjchu cb_done: 20923623Sjchu mutex_exit(&cb_p->cb_mutex); 20933623Sjchu } 20943623Sjchu 20953623Sjchu /* 20961648Sjchu * px_cb_add_intr() - Called from attach(9E) to create CB if not yet 20971648Sjchu * created, to add CB interrupt vector always, but enable only once. 20981648Sjchu */ 20991648Sjchu int 21001648Sjchu px_cb_add_intr(px_fault_t *fault_p) 21011648Sjchu { 21021648Sjchu px_t *px_p = DIP_TO_STATE(fault_p->px_fh_dip); 21031648Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 21041772Sjl139090 px_cb_t *cb_p = (px_cb_t *)px_get_cb(fault_p->px_fh_dip); 21051648Sjchu px_cb_list_t *pxl, *pxl_new; 21063623Sjchu boolean_t is_proxy = B_FALSE; 21073623Sjchu 21083623Sjchu /* create cb */ 21091648Sjchu if (cb_p == NULL) { 21101648Sjchu cb_p = kmem_zalloc(sizeof (px_cb_t), KM_SLEEP); 21113623Sjchu 21123623Sjchu mutex_init(&cb_p->cb_mutex, NULL, MUTEX_DRIVER, 21133623Sjchu (void *) ipltospl(FM_ERR_PIL)); 21143623Sjchu 21151648Sjchu cb_p->px_cb_func = px_cb_intr; 21161648Sjchu pxu_p->px_cb_p = cb_p; 21171772Sjl139090 px_set_cb(fault_p->px_fh_dip, (uint64_t)cb_p); 21182509Sschwartz 21192509Sschwartz /* px_lib_dev_init allows only FIRE and OBERON */ 21202509Sschwartz px_err_reg_enable( 21212509Sschwartz (pxu_p->chip_type == PX_CHIP_FIRE) ? 21222509Sschwartz PX_ERR_JBC : PX_ERR_UBC, 21232509Sschwartz pxu_p->px_address[PX_REG_XBC]); 21241648Sjchu } else 21251648Sjchu pxu_p->px_cb_p = cb_p; 21261648Sjchu 21273623Sjchu /* register cb interrupt */ 21281648Sjchu VERIFY(add_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL, 21292973Sgovinda (intrfunc)cb_p->px_cb_func, (caddr_t)cb_p, NULL, NULL) == 0); 21301648Sjchu 21313623Sjchu 21323623Sjchu /* update cb list */ 21333623Sjchu mutex_enter(&cb_p->cb_mutex); 21341648Sjchu if (cb_p->pxl == NULL) { 21353623Sjchu is_proxy = B_TRUE; 21361648Sjchu pxl = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP); 21371648Sjchu pxl->pxp = px_p; 21381648Sjchu cb_p->pxl = pxl; 21391648Sjchu cb_p->sysino = fault_p->px_fh_sysino; 21403623Sjchu cb_p->cpuid = intr_dist_cpuid(); 21411648Sjchu } else { 21421648Sjchu /* 21431648Sjchu * Find the last pxl or 21443623Sjchu * stop short at encountering a redundent entry, or 21451648Sjchu * both. 21461648Sjchu */ 21471648Sjchu pxl = cb_p->pxl; 21481648Sjchu for (; !(pxl->pxp == px_p) && pxl->next; pxl = pxl->next); 21493623Sjchu ASSERT(pxl->pxp != px_p); 21501648Sjchu 21511648Sjchu /* add to linked list */ 21521648Sjchu pxl_new = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP); 21531648Sjchu pxl_new->pxp = px_p; 21541648Sjchu pxl->next = pxl_new; 21551648Sjchu } 21561648Sjchu cb_p->attachcnt++; 21571648Sjchu mutex_exit(&cb_p->cb_mutex); 21581648Sjchu 21593623Sjchu if (is_proxy) { 21603623Sjchu /* add to interrupt redistribution list */ 21613623Sjchu intr_dist_add(px_cb_intr_redist, cb_p); 21623623Sjchu 21633623Sjchu /* enable cb hw interrupt */ 21643623Sjchu px_ib_intr_enable(px_p, cb_p->cpuid, fault_p->px_intr_ino); 21653623Sjchu } 21663623Sjchu 21671648Sjchu return (DDI_SUCCESS); 21681648Sjchu } 21691648Sjchu 21701648Sjchu /* 21711648Sjchu * px_cb_rem_intr() - Called from detach(9E) to remove its CB 21721648Sjchu * interrupt vector, to shift proxy to the next available px, 21731648Sjchu * or disable CB interrupt when itself is the last. 21741648Sjchu */ 21751648Sjchu void 21761648Sjchu px_cb_rem_intr(px_fault_t *fault_p) 21771648Sjchu { 21781648Sjchu px_t *px_p = DIP_TO_STATE(fault_p->px_fh_dip), *pxp; 21791648Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 21801648Sjchu px_cb_t *cb_p = PX2CB(px_p); 21811648Sjchu px_cb_list_t *pxl, *prev; 21821648Sjchu px_fault_t *f_p; 21831648Sjchu 21841648Sjchu ASSERT(cb_p->pxl); 21851648Sjchu 21863623Sjchu /* find and remove this px, and update cb list */ 21871648Sjchu mutex_enter(&cb_p->cb_mutex); 21881648Sjchu 21891648Sjchu pxl = cb_p->pxl; 21901648Sjchu if (pxl->pxp == px_p) { 21911648Sjchu cb_p->pxl = pxl->next; 21921648Sjchu } else { 21931648Sjchu prev = pxl; 21941648Sjchu pxl = pxl->next; 21951648Sjchu for (; pxl && (pxl->pxp != px_p); prev = pxl, pxl = pxl->next); 21961648Sjchu if (!pxl) { 21971648Sjchu cmn_err(CE_WARN, "px_cb_rem_intr: can't find px_p 0x%p " 21981650Sjchu "in registered CB list.", (void *)px_p); 21993623Sjchu mutex_exit(&cb_p->cb_mutex); 22001648Sjchu return; 22011648Sjchu } 22021648Sjchu prev->next = pxl->next; 22031648Sjchu } 22043623Sjchu pxu_p->px_cb_p = NULL; 22053623Sjchu cb_p->attachcnt--; 22061648Sjchu kmem_free(pxl, sizeof (px_cb_list_t)); 22073623Sjchu mutex_exit(&cb_p->cb_mutex); 22083623Sjchu 22093623Sjchu /* disable cb hw interrupt */ 22103623Sjchu if (fault_p->px_fh_sysino == cb_p->sysino) 22111648Sjchu px_ib_intr_disable(px_p->px_ib_p, fault_p->px_intr_ino, 22121648Sjchu IB_INTR_WAIT); 22131648Sjchu 22143623Sjchu /* if last px, remove from interrupt redistribution list */ 22153623Sjchu if (cb_p->pxl == NULL) 22163623Sjchu intr_dist_rem(px_cb_intr_redist, cb_p); 22173623Sjchu 22183623Sjchu /* de-register interrupt */ 22193623Sjchu VERIFY(rem_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL) == 0); 22203623Sjchu 22213623Sjchu /* if not last px, assign next px to manage cb */ 22223623Sjchu mutex_enter(&cb_p->cb_mutex); 22233623Sjchu if (cb_p->pxl) { 22243623Sjchu if (fault_p->px_fh_sysino == cb_p->sysino) { 22251648Sjchu pxp = cb_p->pxl->pxp; 22261648Sjchu f_p = &pxp->px_cb_fault; 22271648Sjchu cb_p->sysino = f_p->px_fh_sysino; 22281648Sjchu 22291648Sjchu PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid); 22301650Sjchu (void) px_lib_intr_setstate(pxp->px_dip, cb_p->sysino, 22311648Sjchu INTR_IDLE_STATE); 22321648Sjchu } 22331648Sjchu mutex_exit(&cb_p->cb_mutex); 22341648Sjchu return; 22351648Sjchu } 22363623Sjchu 22373623Sjchu /* clean up after the last px */ 22381648Sjchu mutex_exit(&cb_p->cb_mutex); 22391648Sjchu 22402509Sschwartz /* px_lib_dev_init allows only FIRE and OBERON */ 22412509Sschwartz px_err_reg_disable( 22422509Sschwartz (pxu_p->chip_type == PX_CHIP_FIRE) ? PX_ERR_JBC : PX_ERR_UBC, 22432509Sschwartz pxu_p->px_address[PX_REG_XBC]); 22442509Sschwartz 22451648Sjchu mutex_destroy(&cb_p->cb_mutex); 22461772Sjl139090 px_set_cb(fault_p->px_fh_dip, 0ull); 22471648Sjchu kmem_free(cb_p, sizeof (px_cb_t)); 22481648Sjchu } 22491648Sjchu 22501648Sjchu /* 22511648Sjchu * px_cb_intr() - sun4u only, CB interrupt dispatcher 22521648Sjchu */ 22531648Sjchu uint_t 22541648Sjchu px_cb_intr(caddr_t arg) 22551648Sjchu { 22561648Sjchu px_cb_t *cb_p = (px_cb_t *)arg; 22573623Sjchu px_t *pxp; 22583623Sjchu px_fault_t *f_p; 22593623Sjchu int ret; 22603354Sjl139090 22611648Sjchu mutex_enter(&cb_p->cb_mutex); 22621648Sjchu 22633623Sjchu if (!cb_p->pxl) { 22641648Sjchu mutex_exit(&cb_p->cb_mutex); 22653623Sjchu return (DDI_INTR_UNCLAIMED); 22661648Sjchu } 22671648Sjchu 22683623Sjchu pxp = cb_p->pxl->pxp; 22693623Sjchu f_p = &pxp->px_cb_fault; 22703623Sjchu 22713623Sjchu ret = f_p->px_err_func((caddr_t)f_p); 22721648Sjchu 22731648Sjchu mutex_exit(&cb_p->cb_mutex); 22743623Sjchu return (ret); 22751648Sjchu } 22761648Sjchu 22773623Sjchu #ifdef FMA 227827Sjchu void 227927Sjchu px_fill_rc_status(px_fault_t *px_fault_p, pciex_rc_error_regs_t *rc_status) 228027Sjchu { 228127Sjchu /* populate the rc_status by reading the registers - TBD */ 228227Sjchu } 228327Sjchu #endif /* FMA */ 2284383Set142600 2285383Set142600 /* 2286383Set142600 * Unprotected raw reads/writes of fabric device's config space. 2287383Set142600 * Only used for temporary PCI-E Fabric Error Handling. 2288383Set142600 */ 2289383Set142600 uint32_t 22901648Sjchu px_fab_get(px_t *px_p, pcie_req_id_t bdf, uint16_t offset) 22911648Sjchu { 2292383Set142600 px_ranges_t *rp = px_p->px_ranges_p; 2293383Set142600 uint64_t range_prop, base_addr; 2294383Set142600 int bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG); 2295383Set142600 uint32_t val; 2296383Set142600 2297383Set142600 /* Get Fire's Physical Base Address */ 22981772Sjl139090 range_prop = px_get_range_prop(px_p, rp, bank); 2299383Set142600 2300383Set142600 /* Get config space first. */ 2301383Set142600 base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset); 2302383Set142600 2303383Set142600 val = ldphysio(base_addr); 2304383Set142600 2305383Set142600 return (LE_32(val)); 2306383Set142600 } 2307383Set142600 2308383Set142600 void 2309383Set142600 px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset, 2310383Set142600 uint32_t val) { 2311383Set142600 px_ranges_t *rp = px_p->px_ranges_p; 2312383Set142600 uint64_t range_prop, base_addr; 2313383Set142600 int bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG); 2314383Set142600 2315383Set142600 /* Get Fire's Physical Base Address */ 23161772Sjl139090 range_prop = px_get_range_prop(px_p, rp, bank); 2317383Set142600 2318383Set142600 /* Get config space first. */ 2319383Set142600 base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset); 2320383Set142600 2321383Set142600 stphysio(base_addr, LE_32(val)); 2322383Set142600 } 2323435Sjchu 2324435Sjchu /* 2325435Sjchu * cpr callback 2326435Sjchu * 2327435Sjchu * disable fabric error msg interrupt prior to suspending 2328435Sjchu * all device drivers; re-enable fabric error msg interrupt 2329435Sjchu * after all devices are resumed. 2330435Sjchu */ 2331435Sjchu static boolean_t 2332435Sjchu px_cpr_callb(void *arg, int code) 2333435Sjchu { 2334435Sjchu px_t *px_p = (px_t *)arg; 2335435Sjchu px_ib_t *ib_p = px_p->px_ib_p; 2336435Sjchu px_pec_t *pec_p = px_p->px_pec_p; 2337435Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 2338435Sjchu caddr_t csr_base; 2339435Sjchu devino_t ce_ino, nf_ino, f_ino; 23402973Sgovinda px_ino_t *ce_ino_p, *nf_ino_p, *f_ino_p; 2341435Sjchu uint64_t imu_log_enable, imu_intr_enable; 2342435Sjchu uint64_t imu_log_mask, imu_intr_mask; 2343435Sjchu 2344435Sjchu ce_ino = px_msiqid_to_devino(px_p, pec_p->pec_corr_msg_msiq_id); 2345435Sjchu nf_ino = px_msiqid_to_devino(px_p, pec_p->pec_non_fatal_msg_msiq_id); 2346435Sjchu f_ino = px_msiqid_to_devino(px_p, pec_p->pec_fatal_msg_msiq_id); 2347435Sjchu csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 2348435Sjchu 2349435Sjchu imu_log_enable = CSR_XR(csr_base, IMU_ERROR_LOG_ENABLE); 2350435Sjchu imu_intr_enable = CSR_XR(csr_base, IMU_INTERRUPT_ENABLE); 2351435Sjchu 2352435Sjchu imu_log_mask = BITMASK(IMU_ERROR_LOG_ENABLE_FATAL_MES_NOT_EN_LOG_EN) | 2353435Sjchu BITMASK(IMU_ERROR_LOG_ENABLE_NONFATAL_MES_NOT_EN_LOG_EN) | 2354435Sjchu BITMASK(IMU_ERROR_LOG_ENABLE_COR_MES_NOT_EN_LOG_EN); 2355435Sjchu 2356435Sjchu imu_intr_mask = 2357435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_S_INT_EN) | 2358435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_S_INT_EN) | 2359435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_S_INT_EN) | 2360435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_P_INT_EN) | 2361435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_P_INT_EN) | 2362435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_P_INT_EN); 2363435Sjchu 2364435Sjchu switch (code) { 2365435Sjchu case CB_CODE_CPR_CHKPT: 2366435Sjchu /* disable imu rbne on corr/nonfatal/fatal errors */ 2367435Sjchu CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE, 2368435Sjchu imu_log_enable & (~imu_log_mask)); 2369435Sjchu 2370435Sjchu CSR_XS(csr_base, IMU_INTERRUPT_ENABLE, 2371435Sjchu imu_intr_enable & (~imu_intr_mask)); 2372435Sjchu 2373435Sjchu /* disable CORR intr mapping */ 2374435Sjchu px_ib_intr_disable(ib_p, ce_ino, IB_INTR_NOWAIT); 2375435Sjchu 2376435Sjchu /* disable NON FATAL intr mapping */ 2377435Sjchu px_ib_intr_disable(ib_p, nf_ino, IB_INTR_NOWAIT); 2378435Sjchu 2379435Sjchu /* disable FATAL intr mapping */ 2380435Sjchu px_ib_intr_disable(ib_p, f_ino, IB_INTR_NOWAIT); 2381435Sjchu 2382435Sjchu break; 2383435Sjchu 2384435Sjchu case CB_CODE_CPR_RESUME: 23853274Set142600 pxu_p->cpr_flag = PX_NOT_CPR; 2386435Sjchu mutex_enter(&ib_p->ib_ino_lst_mutex); 2387435Sjchu 2388435Sjchu ce_ino_p = px_ib_locate_ino(ib_p, ce_ino); 2389435Sjchu nf_ino_p = px_ib_locate_ino(ib_p, nf_ino); 2390435Sjchu f_ino_p = px_ib_locate_ino(ib_p, f_ino); 2391435Sjchu 2392435Sjchu /* enable CORR intr mapping */ 2393435Sjchu if (ce_ino_p) 2394435Sjchu px_ib_intr_enable(px_p, ce_ino_p->ino_cpuid, ce_ino); 2395435Sjchu else 2396435Sjchu cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to " 2397435Sjchu "reenable PCIe Correctable msg intr.\n"); 2398435Sjchu 2399435Sjchu /* enable NON FATAL intr mapping */ 2400435Sjchu if (nf_ino_p) 2401435Sjchu px_ib_intr_enable(px_p, nf_ino_p->ino_cpuid, nf_ino); 2402435Sjchu else 2403435Sjchu cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to " 2404435Sjchu "reenable PCIe Non Fatal msg intr.\n"); 2405435Sjchu 2406435Sjchu /* enable FATAL intr mapping */ 2407435Sjchu if (f_ino_p) 2408435Sjchu px_ib_intr_enable(px_p, f_ino_p->ino_cpuid, f_ino); 2409435Sjchu else 2410435Sjchu cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to " 2411435Sjchu "reenable PCIe Fatal msg intr.\n"); 2412435Sjchu 2413435Sjchu mutex_exit(&ib_p->ib_ino_lst_mutex); 2414435Sjchu 2415435Sjchu /* enable corr/nonfatal/fatal not enable error */ 2416435Sjchu CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE, (imu_log_enable | 2417435Sjchu (imu_log_mask & px_imu_log_mask))); 2418435Sjchu CSR_XS(csr_base, IMU_INTERRUPT_ENABLE, (imu_intr_enable | 2419435Sjchu (imu_intr_mask & px_imu_intr_mask))); 2420435Sjchu 2421435Sjchu break; 2422435Sjchu } 2423435Sjchu 2424435Sjchu return (B_TRUE); 2425435Sjchu } 2426435Sjchu 24272053Sschwartz uint64_t 24282053Sschwartz px_get_rng_parent_hi_mask(px_t *px_p) 24292053Sschwartz { 24302053Sschwartz pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 24312053Sschwartz uint64_t mask; 24322053Sschwartz 24332053Sschwartz switch (PX_CHIP_TYPE(pxu_p)) { 24342053Sschwartz case PX_CHIP_OBERON: 24352053Sschwartz mask = OBERON_RANGE_PROP_MASK; 24362053Sschwartz break; 24372053Sschwartz case PX_CHIP_FIRE: 24382053Sschwartz mask = PX_RANGE_PROP_MASK; 24392053Sschwartz break; 24402053Sschwartz default: 24412053Sschwartz mask = PX_RANGE_PROP_MASK; 24422053Sschwartz } 24432053Sschwartz 24442053Sschwartz return (mask); 24452053Sschwartz } 24462053Sschwartz 2447435Sjchu /* 24481772Sjl139090 * fetch chip's range propery's value 24491772Sjl139090 */ 24501772Sjl139090 uint64_t 24511772Sjl139090 px_get_range_prop(px_t *px_p, px_ranges_t *rp, int bank) 24521772Sjl139090 { 24531772Sjl139090 uint64_t mask, range_prop; 24541772Sjl139090 24552053Sschwartz mask = px_get_rng_parent_hi_mask(px_p); 24561772Sjl139090 range_prop = (((uint64_t)(rp[bank].parent_high & mask)) << 32) | 24571772Sjl139090 rp[bank].parent_low; 24581772Sjl139090 24591772Sjl139090 return (range_prop); 24601772Sjl139090 } 24611772Sjl139090 24621772Sjl139090 /* 2463435Sjchu * add cpr callback 2464435Sjchu */ 2465435Sjchu void 2466435Sjchu px_cpr_add_callb(px_t *px_p) 2467435Sjchu { 2468435Sjchu px_p->px_cprcb_id = callb_add(px_cpr_callb, (void *)px_p, 2469435Sjchu CB_CL_CPR_POST_USER, "px_cpr"); 2470435Sjchu } 2471435Sjchu 2472435Sjchu /* 2473435Sjchu * remove cpr callback 2474435Sjchu */ 2475435Sjchu void 2476435Sjchu px_cpr_rem_callb(px_t *px_p) 2477435Sjchu { 2478435Sjchu (void) callb_delete(px_p->px_cprcb_id); 2479435Sjchu } 24801531Skini 24811531Skini /*ARGSUSED*/ 24821772Sjl139090 static uint_t 24831772Sjl139090 px_hp_intr(caddr_t arg1, caddr_t arg2) 24841772Sjl139090 { 2485*4701Sgovinda px_t *px_p = (px_t *)arg1; 2486*4701Sgovinda pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 2487*4701Sgovinda int rval; 24881772Sjl139090 24891772Sjl139090 rval = pciehpc_intr(px_p->px_dip); 24901772Sjl139090 24911772Sjl139090 #ifdef DEBUG 24921772Sjl139090 if (rval == DDI_INTR_UNCLAIMED) 24931772Sjl139090 cmn_err(CE_WARN, "%s%d: UNCLAIMED intr\n", 24941772Sjl139090 ddi_driver_name(px_p->px_dip), 24951772Sjl139090 ddi_get_instance(px_p->px_dip)); 24961772Sjl139090 #endif 24971772Sjl139090 2498*4701Sgovinda /* Set the interrupt state to idle */ 2499*4701Sgovinda if (px_lib_intr_setstate(px_p->px_dip, 2500*4701Sgovinda pxu_p->hp_sysino, INTR_IDLE_STATE) != DDI_SUCCESS) 2501*4701Sgovinda return (DDI_INTR_UNCLAIMED); 2502*4701Sgovinda 25031772Sjl139090 return (rval); 25041772Sjl139090 } 25051772Sjl139090 25061531Skini int 25071531Skini px_lib_hotplug_init(dev_info_t *dip, void *arg) 25081531Skini { 25091772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 2510*4701Sgovinda pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 25111772Sjl139090 uint64_t ret; 25121772Sjl139090 25131772Sjl139090 if ((ret = hvio_hotplug_init(dip, arg)) == DDI_SUCCESS) { 25141772Sjl139090 if (px_lib_intr_devino_to_sysino(px_p->px_dip, 2515*4701Sgovinda px_p->px_inos[PX_INTR_HOTPLUG], &pxu_p->hp_sysino) != 25161772Sjl139090 DDI_SUCCESS) { 25171772Sjl139090 #ifdef DEBUG 25181772Sjl139090 cmn_err(CE_WARN, "%s%d: devino_to_sysino fails\n", 25191772Sjl139090 ddi_driver_name(px_p->px_dip), 25201772Sjl139090 ddi_get_instance(px_p->px_dip)); 25211772Sjl139090 #endif 25221772Sjl139090 return (DDI_FAILURE); 25231772Sjl139090 } 25241772Sjl139090 2525*4701Sgovinda VERIFY(add_ivintr(pxu_p->hp_sysino, PX_PCIEHP_PIL, 25262973Sgovinda (intrfunc)px_hp_intr, (caddr_t)px_p, NULL, NULL) == 0); 25273953Sscarter 25283953Sscarter px_ib_intr_enable(px_p, intr_dist_cpuid(), 25293953Sscarter px_p->px_inos[PX_INTR_HOTPLUG]); 25301772Sjl139090 } 25311772Sjl139090 25321772Sjl139090 return (ret); 25331531Skini } 25341531Skini 25351531Skini void 25361531Skini px_lib_hotplug_uninit(dev_info_t *dip) 25371531Skini { 25381772Sjl139090 if (hvio_hotplug_uninit(dip) == DDI_SUCCESS) { 25391772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 2540*4701Sgovinda pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 25411772Sjl139090 25423953Sscarter px_ib_intr_disable(px_p->px_ib_p, 25433953Sscarter px_p->px_inos[PX_INTR_HOTPLUG], IB_INTR_WAIT); 25443953Sscarter 2545*4701Sgovinda VERIFY(rem_ivintr(pxu_p->hp_sysino, PX_PCIEHP_PIL) == 0); 25461772Sjl139090 } 25471531Skini } 25482476Sdwoods 25493953Sscarter /* 25503953Sscarter * px_hp_intr_redist() - sun4u only, HP interrupt redistribution 25513953Sscarter */ 25523953Sscarter void 25533953Sscarter px_hp_intr_redist(px_t *px_p) 25543953Sscarter { 25553953Sscarter if (px_p && (px_p->px_dev_caps & PX_HOTPLUG_CAPABLE)) { 25563953Sscarter px_ib_intr_dist_en(px_p->px_dip, intr_dist_cpuid(), 25573953Sscarter px_p->px_inos[PX_INTR_HOTPLUG], B_FALSE); 25583953Sscarter } 25593953Sscarter } 25603953Sscarter 25612476Sdwoods boolean_t 25622476Sdwoods px_lib_is_in_drain_state(px_t *px_p) 25632476Sdwoods { 25642476Sdwoods pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 25652476Sdwoods caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 25662476Sdwoods uint64_t drain_status; 25672476Sdwoods 25682476Sdwoods if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) { 25692476Sdwoods drain_status = CSR_BR(csr_base, DRAIN_CONTROL_STATUS, DRAIN); 25702476Sdwoods } else { 25712476Sdwoods drain_status = CSR_BR(csr_base, TLU_STATUS, DRAIN); 25722476Sdwoods } 25732476Sdwoods 25742476Sdwoods return (drain_status); 25752476Sdwoods } 25763613Set142600 25773613Set142600 pcie_req_id_t 25783613Set142600 px_lib_get_bdf(px_t *px_p) 25793613Set142600 { 25803613Set142600 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 25813613Set142600 caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 25823613Set142600 pcie_req_id_t bdf; 25833613Set142600 25843613Set142600 bdf = CSR_BR(csr_base, DMC_PCI_EXPRESS_CONFIGURATION, REQ_ID); 25853613Set142600 25863613Set142600 return (bdf); 25873613Set142600 } 2588