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 /* 22*11596SJason.Beloro@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/types.h> 270Sstevel@tonic-gate #include <sys/kmem.h> 280Sstevel@tonic-gate #include <sys/conf.h> 290Sstevel@tonic-gate #include <sys/ddi.h> 300Sstevel@tonic-gate #include <sys/sunddi.h> 316313Skrishnae #include <sys/sunndi.h> 3227Sjchu #include <sys/fm/protocol.h> 3327Sjchu #include <sys/fm/util.h> 340Sstevel@tonic-gate #include <sys/modctl.h> 350Sstevel@tonic-gate #include <sys/disp.h> 360Sstevel@tonic-gate #include <sys/stat.h> 370Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 380Sstevel@tonic-gate #include <sys/vmem.h> 390Sstevel@tonic-gate #include <sys/iommutsb.h> 400Sstevel@tonic-gate #include <sys/cpuvar.h> 4127Sjchu #include <sys/ivintr.h> 42383Set142600 #include <sys/byteorder.h> 433623Sjchu #include <sys/spl.h> 440Sstevel@tonic-gate #include <px_obj.h> 4510187SKrishna.Elango@Sun.COM #include <sys/pcie_pwr.h> 461772Sjl139090 #include "px_tools_var.h" 470Sstevel@tonic-gate #include <px_regs.h> 480Sstevel@tonic-gate #include <px_csr.h> 4927Sjchu #include <sys/machsystm.h> 500Sstevel@tonic-gate #include "px_lib4u.h" 5127Sjchu #include "px_err.h" 521772Sjl139090 #include "oberon_regs.h" 5310923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcie_hp.h> 540Sstevel@tonic-gate 550Sstevel@tonic-gate #pragma weak jbus_stst_order 560Sstevel@tonic-gate 570Sstevel@tonic-gate extern void jbus_stst_order(); 580Sstevel@tonic-gate 590Sstevel@tonic-gate ulong_t px_mmu_dvma_end = 0xfffffffful; 600Sstevel@tonic-gate uint_t px_ranges_phi_mask = 0xfffffffful; 611772Sjl139090 uint64_t *px_oberon_ubc_scratch_regs; 622276Sschwartz uint64_t px_paddr_mask; 630Sstevel@tonic-gate 640Sstevel@tonic-gate static int px_goto_l23ready(px_t *px_p); 65118Sjchu static int px_goto_l0(px_t *px_p); 66118Sjchu static int px_pre_pwron_check(px_t *px_p); 672426Sschwartz static uint32_t px_identity_init(px_t *px_p); 68435Sjchu static boolean_t px_cpr_callb(void *arg, int code); 691648Sjchu static uint_t px_cb_intr(caddr_t arg); 7027Sjchu 7127Sjchu /* 727596SAlan.Adamson@Sun.COM * ACKNAK Latency Threshold Table. 737596SAlan.Adamson@Sun.COM * See Fire PRM 2.0 section 1.2.12.2, table 1-17. 747596SAlan.Adamson@Sun.COM */ 757596SAlan.Adamson@Sun.COM int px_acknak_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE] = { 767596SAlan.Adamson@Sun.COM {0xED, 0x49, 0x43, 0x30}, 777596SAlan.Adamson@Sun.COM {0x1A0, 0x76, 0x6B, 0x48}, 787596SAlan.Adamson@Sun.COM {0x22F, 0x9A, 0x56, 0x56}, 797596SAlan.Adamson@Sun.COM {0x42F, 0x11A, 0x96, 0x96}, 807596SAlan.Adamson@Sun.COM {0x82F, 0x21A, 0x116, 0x116}, 817596SAlan.Adamson@Sun.COM {0x102F, 0x41A, 0x216, 0x216} 827596SAlan.Adamson@Sun.COM }; 837596SAlan.Adamson@Sun.COM 847596SAlan.Adamson@Sun.COM /* 857596SAlan.Adamson@Sun.COM * TxLink Replay Timer Latency Table 867596SAlan.Adamson@Sun.COM * See Fire PRM 2.0 sections 1.2.12.3, table 1-18. 877596SAlan.Adamson@Sun.COM */ 887596SAlan.Adamson@Sun.COM int px_replay_timer_table[LINK_MAX_PKT_ARR_SIZE][LINK_WIDTH_ARR_SIZE] = { 897596SAlan.Adamson@Sun.COM {0x379, 0x112, 0xFC, 0xB4}, 907596SAlan.Adamson@Sun.COM {0x618, 0x1BA, 0x192, 0x10E}, 917596SAlan.Adamson@Sun.COM {0x831, 0x242, 0x143, 0x143}, 927596SAlan.Adamson@Sun.COM {0xFB1, 0x422, 0x233, 0x233}, 937596SAlan.Adamson@Sun.COM {0x1EB0, 0x7E1, 0x412, 0x412}, 947596SAlan.Adamson@Sun.COM {0x3CB0, 0xF61, 0x7D2, 0x7D2} 957596SAlan.Adamson@Sun.COM }; 967596SAlan.Adamson@Sun.COM /* 9727Sjchu * px_lib_map_registers 9827Sjchu * 9927Sjchu * This function is called from the attach routine to map the registers 10027Sjchu * accessed by this driver. 10127Sjchu * 10227Sjchu * used by: px_attach() 10327Sjchu * 10427Sjchu * return value: DDI_FAILURE on failure 10527Sjchu */ 10627Sjchu int 10727Sjchu px_lib_map_regs(pxu_t *pxu_p, dev_info_t *dip) 10827Sjchu { 10927Sjchu ddi_device_acc_attr_t attr; 11027Sjchu px_reg_bank_t reg_bank = PX_REG_CSR; 11127Sjchu 11227Sjchu DBG(DBG_ATTACH, dip, "px_lib_map_regs: pxu_p:0x%p, dip 0x%p\n", 1136313Skrishnae pxu_p, dip); 11427Sjchu 11527Sjchu attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 11627Sjchu attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 11727Sjchu attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 11827Sjchu 11927Sjchu /* 12027Sjchu * PCI CSR Base 12127Sjchu */ 12227Sjchu if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank], 12327Sjchu 0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) { 12427Sjchu goto fail; 12527Sjchu } 12627Sjchu 12727Sjchu reg_bank++; 12827Sjchu 12927Sjchu /* 13027Sjchu * XBUS CSR Base 13127Sjchu */ 13227Sjchu if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank], 13327Sjchu 0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) { 13427Sjchu goto fail; 13527Sjchu } 13627Sjchu 13727Sjchu pxu_p->px_address[reg_bank] -= FIRE_CONTROL_STATUS; 13827Sjchu 13927Sjchu done: 14027Sjchu for (; reg_bank >= PX_REG_CSR; reg_bank--) { 14127Sjchu DBG(DBG_ATTACH, dip, "reg_bank 0x%x address 0x%p\n", 14227Sjchu reg_bank, pxu_p->px_address[reg_bank]); 14327Sjchu } 14427Sjchu 14527Sjchu return (DDI_SUCCESS); 14627Sjchu 14727Sjchu fail: 14827Sjchu cmn_err(CE_WARN, "%s%d: unable to map reg entry %d\n", 14927Sjchu ddi_driver_name(dip), ddi_get_instance(dip), reg_bank); 15027Sjchu 15127Sjchu for (reg_bank--; reg_bank >= PX_REG_CSR; reg_bank--) { 15227Sjchu pxu_p->px_address[reg_bank] = NULL; 15327Sjchu ddi_regs_map_free(&pxu_p->px_ac[reg_bank]); 15427Sjchu } 15527Sjchu 15627Sjchu return (DDI_FAILURE); 15727Sjchu } 15827Sjchu 15927Sjchu /* 16027Sjchu * px_lib_unmap_regs: 16127Sjchu * 16227Sjchu * This routine unmaps the registers mapped by map_px_registers. 16327Sjchu * 16427Sjchu * used by: px_detach(), and error conditions in px_attach() 16527Sjchu * 16627Sjchu * return value: none 16727Sjchu */ 16827Sjchu void 16927Sjchu px_lib_unmap_regs(pxu_t *pxu_p) 17027Sjchu { 17127Sjchu int i; 17227Sjchu 17327Sjchu for (i = 0; i < PX_REG_MAX; i++) { 17427Sjchu if (pxu_p->px_ac[i]) 17527Sjchu ddi_regs_map_free(&pxu_p->px_ac[i]); 17627Sjchu } 17727Sjchu } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate int 1800Sstevel@tonic-gate px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl) 1810Sstevel@tonic-gate { 1822509Sschwartz 1832509Sschwartz caddr_t xbc_csr_base, csr_base; 1840Sstevel@tonic-gate px_dvma_range_prop_t px_dvma_range; 1852509Sschwartz pxu_t *pxu_p; 1862509Sschwartz uint8_t chip_mask; 1872509Sschwartz px_t *px_p = DIP_TO_STATE(dip); 1882509Sschwartz px_chip_type_t chip_type = px_identity_init(px_p); 1890Sstevel@tonic-gate 1902426Sschwartz DBG(DBG_ATTACH, dip, "px_lib_dev_init: dip 0x%p", dip); 1912426Sschwartz 1922426Sschwartz if (chip_type == PX_CHIP_UNIDENTIFIED) { 1932426Sschwartz cmn_err(CE_WARN, "%s%d: Unrecognized Hardware Version\n", 1942426Sschwartz NAMEINST(dip)); 1950Sstevel@tonic-gate return (DDI_FAILURE); 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1982509Sschwartz chip_mask = BITMASK(chip_type); 1992426Sschwartz px_paddr_mask = (chip_type == PX_CHIP_FIRE) ? MMU_FIRE_PADDR_MASK : 2002426Sschwartz MMU_OBERON_PADDR_MASK; 2012426Sschwartz 2020Sstevel@tonic-gate /* 2030Sstevel@tonic-gate * Allocate platform specific structure and link it to 2040Sstevel@tonic-gate * the px state structure. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate pxu_p = kmem_zalloc(sizeof (pxu_t), KM_SLEEP); 2072426Sschwartz pxu_p->chip_type = chip_type; 2080Sstevel@tonic-gate pxu_p->portid = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2090Sstevel@tonic-gate "portid", -1); 2100Sstevel@tonic-gate 21127Sjchu /* Map in the registers */ 21227Sjchu if (px_lib_map_regs(pxu_p, dip) == DDI_FAILURE) { 21327Sjchu kmem_free(pxu_p, sizeof (pxu_t)); 21427Sjchu 21527Sjchu return (DDI_FAILURE); 21627Sjchu } 21727Sjchu 21827Sjchu xbc_csr_base = (caddr_t)pxu_p->px_address[PX_REG_XBC]; 21927Sjchu csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 22027Sjchu 2210Sstevel@tonic-gate pxu_p->tsb_cookie = iommu_tsb_alloc(pxu_p->portid); 2220Sstevel@tonic-gate pxu_p->tsb_size = iommu_tsb_cookie_to_size(pxu_p->tsb_cookie); 2230Sstevel@tonic-gate pxu_p->tsb_vaddr = iommu_tsb_cookie_to_va(pxu_p->tsb_cookie); 2240Sstevel@tonic-gate 2251772Sjl139090 pxu_p->tsb_paddr = va_to_pa(pxu_p->tsb_vaddr); 2261772Sjl139090 2270Sstevel@tonic-gate /* 2280Sstevel@tonic-gate * Create "virtual-dma" property to support child devices 2290Sstevel@tonic-gate * needing to know DVMA range. 2300Sstevel@tonic-gate */ 2310Sstevel@tonic-gate px_dvma_range.dvma_base = (uint32_t)px_mmu_dvma_end + 1 2320Sstevel@tonic-gate - ((pxu_p->tsb_size >> 3) << MMU_PAGE_SHIFT); 2330Sstevel@tonic-gate px_dvma_range.dvma_len = (uint32_t) 2340Sstevel@tonic-gate px_mmu_dvma_end - px_dvma_range.dvma_base + 1; 2350Sstevel@tonic-gate 2365328Sdanice (void) ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, 2375328Sdanice "virtual-dma", (int *)&px_dvma_range, 2385328Sdanice sizeof (px_dvma_range_prop_t) / sizeof (int)); 2390Sstevel@tonic-gate /* 2400Sstevel@tonic-gate * Initilize all fire hardware specific blocks. 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate hvio_cb_init(xbc_csr_base, pxu_p); 2430Sstevel@tonic-gate hvio_ib_init(csr_base, pxu_p); 2440Sstevel@tonic-gate hvio_pec_init(csr_base, pxu_p); 2450Sstevel@tonic-gate hvio_mmu_init(csr_base, pxu_p); 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate px_p->px_plat_p = (void *)pxu_p; 2480Sstevel@tonic-gate 24927Sjchu /* 25027Sjchu * Initialize all the interrupt handlers 25127Sjchu */ 2521772Sjl139090 switch (PX_CHIP_TYPE(pxu_p)) { 2531772Sjl139090 case PX_CHIP_OBERON: 2542044Sjj156685 /* 2552044Sjj156685 * Oberon hotplug uses SPARE3 field in ILU Error Log Enable 2562044Sjj156685 * register to indicate the status of leaf reset, 2572044Sjj156685 * we need to preserve the value of this bit, and keep it in 2582044Sjj156685 * px_ilu_log_mask to reflect the state of the bit 2592044Sjj156685 */ 2602044Sjj156685 if (CSR_BR(csr_base, ILU_ERROR_LOG_ENABLE, SPARE3)) 2612044Sjj156685 px_ilu_log_mask |= (1ull << 2622044Sjj156685 ILU_ERROR_LOG_ENABLE_SPARE3); 2632044Sjj156685 else 2642044Sjj156685 px_ilu_log_mask &= ~(1ull << 2652044Sjj156685 ILU_ERROR_LOG_ENABLE_SPARE3); 2662509Sschwartz 2672509Sschwartz px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE); 2681772Sjl139090 break; 2691772Sjl139090 2701772Sjl139090 case PX_CHIP_FIRE: 2712509Sschwartz px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_ENABLE); 2721772Sjl139090 break; 2732509Sschwartz 2741772Sjl139090 default: 2751772Sjl139090 cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n", 2761772Sjl139090 ddi_driver_name(dip), ddi_get_instance(dip)); 2771772Sjl139090 return (DDI_FAILURE); 2781772Sjl139090 } 27927Sjchu 2800Sstevel@tonic-gate /* Initilize device handle */ 2810Sstevel@tonic-gate *dev_hdl = (devhandle_t)csr_base; 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "px_lib_dev_init: dev_hdl 0x%llx\n", *dev_hdl); 2840Sstevel@tonic-gate 285*11596SJason.Beloro@Sun.COM /* Sun4u always support fixed interrupt */ 286*11596SJason.Beloro@Sun.COM px_p->px_supp_intr_types |= DDI_INTR_TYPE_FIXED; 287*11596SJason.Beloro@Sun.COM 2880Sstevel@tonic-gate return (DDI_SUCCESS); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate int 2920Sstevel@tonic-gate px_lib_dev_fini(dev_info_t *dip) 2930Sstevel@tonic-gate { 2942509Sschwartz caddr_t csr_base; 2952509Sschwartz uint8_t chip_mask; 2962509Sschwartz px_t *px_p = DIP_TO_STATE(dip); 2972509Sschwartz pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate DBG(DBG_DETACH, dip, "px_lib_dev_fini: dip 0x%p\n", dip); 3000Sstevel@tonic-gate 30127Sjchu /* 30227Sjchu * Deinitialize all the interrupt handlers 30327Sjchu */ 3041772Sjl139090 switch (PX_CHIP_TYPE(pxu_p)) { 3051772Sjl139090 case PX_CHIP_OBERON: 3062509Sschwartz case PX_CHIP_FIRE: 3072509Sschwartz chip_mask = BITMASK(PX_CHIP_TYPE(pxu_p)); 3082509Sschwartz csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 3092509Sschwartz px_err_reg_setup_pcie(chip_mask, csr_base, PX_ERR_DISABLE); 3101772Sjl139090 break; 3112509Sschwartz 3121772Sjl139090 default: 3131772Sjl139090 cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n", 3141772Sjl139090 ddi_driver_name(dip), ddi_get_instance(dip)); 3151772Sjl139090 return (DDI_FAILURE); 3161772Sjl139090 } 31727Sjchu 3180Sstevel@tonic-gate iommu_tsb_free(pxu_p->tsb_cookie); 3190Sstevel@tonic-gate 32027Sjchu px_lib_unmap_regs((pxu_t *)px_p->px_plat_p); 32127Sjchu kmem_free(px_p->px_plat_p, sizeof (pxu_t)); 3220Sstevel@tonic-gate px_p->px_plat_p = NULL; 3235328Sdanice (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "virtual-dma"); 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate return (DDI_SUCCESS); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /*ARGSUSED*/ 3290Sstevel@tonic-gate int 3300Sstevel@tonic-gate px_lib_intr_devino_to_sysino(dev_info_t *dip, devino_t devino, 3310Sstevel@tonic-gate sysino_t *sysino) 3320Sstevel@tonic-gate { 3330Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 3340Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 3350Sstevel@tonic-gate uint64_t ret; 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: dip 0x%p " 3380Sstevel@tonic-gate "devino 0x%x\n", dip, devino); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if ((ret = hvio_intr_devino_to_sysino(DIP_TO_HANDLE(dip), 3410Sstevel@tonic-gate pxu_p, devino, sysino)) != H_EOK) { 3420Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, 3430Sstevel@tonic-gate "hvio_intr_devino_to_sysino failed, ret 0x%lx\n", ret); 3440Sstevel@tonic-gate return (DDI_FAILURE); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: sysino 0x%llx\n", 3480Sstevel@tonic-gate *sysino); 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate return (DDI_SUCCESS); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate /*ARGSUSED*/ 3540Sstevel@tonic-gate int 3550Sstevel@tonic-gate px_lib_intr_getvalid(dev_info_t *dip, sysino_t sysino, 3560Sstevel@tonic-gate intr_valid_state_t *intr_valid_state) 3570Sstevel@tonic-gate { 3580Sstevel@tonic-gate uint64_t ret; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: dip 0x%p sysino 0x%llx\n", 3610Sstevel@tonic-gate dip, sysino); 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate if ((ret = hvio_intr_getvalid(DIP_TO_HANDLE(dip), 3640Sstevel@tonic-gate sysino, intr_valid_state)) != H_EOK) { 3650Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_getvalid failed, ret 0x%lx\n", 3660Sstevel@tonic-gate ret); 3670Sstevel@tonic-gate return (DDI_FAILURE); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: intr_valid_state 0x%x\n", 3710Sstevel@tonic-gate *intr_valid_state); 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate return (DDI_SUCCESS); 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /*ARGSUSED*/ 3770Sstevel@tonic-gate int 3780Sstevel@tonic-gate px_lib_intr_setvalid(dev_info_t *dip, sysino_t sysino, 3790Sstevel@tonic-gate intr_valid_state_t intr_valid_state) 3800Sstevel@tonic-gate { 3810Sstevel@tonic-gate uint64_t ret; 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_setvalid: dip 0x%p sysino 0x%llx " 3840Sstevel@tonic-gate "intr_valid_state 0x%x\n", dip, sysino, intr_valid_state); 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate if ((ret = hvio_intr_setvalid(DIP_TO_HANDLE(dip), 3870Sstevel@tonic-gate sysino, intr_valid_state)) != H_EOK) { 3880Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_setvalid failed, ret 0x%lx\n", 3890Sstevel@tonic-gate ret); 3900Sstevel@tonic-gate return (DDI_FAILURE); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate return (DDI_SUCCESS); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /*ARGSUSED*/ 3970Sstevel@tonic-gate int 3980Sstevel@tonic-gate px_lib_intr_getstate(dev_info_t *dip, sysino_t sysino, 3990Sstevel@tonic-gate intr_state_t *intr_state) 4000Sstevel@tonic-gate { 4010Sstevel@tonic-gate uint64_t ret; 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: dip 0x%p sysino 0x%llx\n", 4040Sstevel@tonic-gate dip, sysino); 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate if ((ret = hvio_intr_getstate(DIP_TO_HANDLE(dip), 4070Sstevel@tonic-gate sysino, intr_state)) != H_EOK) { 4080Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_getstate failed, ret 0x%lx\n", 4090Sstevel@tonic-gate ret); 4100Sstevel@tonic-gate return (DDI_FAILURE); 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: intr_state 0x%x\n", 4140Sstevel@tonic-gate *intr_state); 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate return (DDI_SUCCESS); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /*ARGSUSED*/ 4200Sstevel@tonic-gate int 4210Sstevel@tonic-gate px_lib_intr_setstate(dev_info_t *dip, sysino_t sysino, 4220Sstevel@tonic-gate intr_state_t intr_state) 4230Sstevel@tonic-gate { 4240Sstevel@tonic-gate uint64_t ret; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_setstate: dip 0x%p sysino 0x%llx " 4270Sstevel@tonic-gate "intr_state 0x%x\n", dip, sysino, intr_state); 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate if ((ret = hvio_intr_setstate(DIP_TO_HANDLE(dip), 4300Sstevel@tonic-gate sysino, intr_state)) != H_EOK) { 4310Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_setstate failed, ret 0x%lx\n", 4320Sstevel@tonic-gate ret); 4330Sstevel@tonic-gate return (DDI_FAILURE); 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate return (DDI_SUCCESS); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate /*ARGSUSED*/ 4400Sstevel@tonic-gate int 4410Sstevel@tonic-gate px_lib_intr_gettarget(dev_info_t *dip, sysino_t sysino, cpuid_t *cpuid) 4420Sstevel@tonic-gate { 4431772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 4441772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 4450Sstevel@tonic-gate uint64_t ret; 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: dip 0x%p sysino 0x%llx\n", 4480Sstevel@tonic-gate dip, sysino); 4490Sstevel@tonic-gate 4501772Sjl139090 if ((ret = hvio_intr_gettarget(DIP_TO_HANDLE(dip), pxu_p, 4510Sstevel@tonic-gate sysino, cpuid)) != H_EOK) { 4520Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_gettarget failed, ret 0x%lx\n", 4530Sstevel@tonic-gate ret); 4540Sstevel@tonic-gate return (DDI_FAILURE); 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: cpuid 0x%x\n", cpuid); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate return (DDI_SUCCESS); 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate /*ARGSUSED*/ 4630Sstevel@tonic-gate int 4640Sstevel@tonic-gate px_lib_intr_settarget(dev_info_t *dip, sysino_t sysino, cpuid_t cpuid) 4650Sstevel@tonic-gate { 4661772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 4671772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 4680Sstevel@tonic-gate uint64_t ret; 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_settarget: dip 0x%p sysino 0x%llx " 4710Sstevel@tonic-gate "cpuid 0x%x\n", dip, sysino, cpuid); 4720Sstevel@tonic-gate 4731772Sjl139090 if ((ret = hvio_intr_settarget(DIP_TO_HANDLE(dip), pxu_p, 4740Sstevel@tonic-gate sysino, cpuid)) != H_EOK) { 4750Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_settarget failed, ret 0x%lx\n", 4760Sstevel@tonic-gate ret); 4770Sstevel@tonic-gate return (DDI_FAILURE); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate return (DDI_SUCCESS); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate /*ARGSUSED*/ 4840Sstevel@tonic-gate int 4850Sstevel@tonic-gate px_lib_intr_reset(dev_info_t *dip) 4860Sstevel@tonic-gate { 4870Sstevel@tonic-gate devino_t ino; 4880Sstevel@tonic-gate sysino_t sysino; 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_reset: dip 0x%p\n", dip); 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate /* Reset all Interrupts */ 4930Sstevel@tonic-gate for (ino = 0; ino < INTERRUPT_MAPPING_ENTRIES; ino++) { 4940Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(dip, ino, 4950Sstevel@tonic-gate &sysino) != DDI_SUCCESS) 4960Sstevel@tonic-gate return (BF_FATAL); 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate if (px_lib_intr_setstate(dip, sysino, 4990Sstevel@tonic-gate INTR_IDLE_STATE) != DDI_SUCCESS) 5000Sstevel@tonic-gate return (BF_FATAL); 5010Sstevel@tonic-gate } 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate return (BF_NONE); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate /*ARGSUSED*/ 5070Sstevel@tonic-gate int 5080Sstevel@tonic-gate px_lib_iommu_map(dev_info_t *dip, tsbid_t tsbid, pages_t pages, 5091617Sgovinda io_attributes_t attr, void *addr, size_t pfn_index, int flags) 5100Sstevel@tonic-gate { 5110Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5120Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 5130Sstevel@tonic-gate uint64_t ret; 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_map: dip 0x%p tsbid 0x%llx " 5169707SDaniel.Ice@Sun.COM "pages 0x%x attr 0x%llx addr 0x%p pfn_index 0x%llx flags 0x%x\n", 5171617Sgovinda dip, tsbid, pages, attr, addr, pfn_index, flags); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate if ((ret = hvio_iommu_map(px_p->px_dev_hdl, pxu_p, tsbid, pages, 5201617Sgovinda attr, addr, pfn_index, flags)) != H_EOK) { 5210Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 5220Sstevel@tonic-gate "px_lib_iommu_map failed, ret 0x%lx\n", ret); 5230Sstevel@tonic-gate return (DDI_FAILURE); 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate return (DDI_SUCCESS); 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate /*ARGSUSED*/ 5300Sstevel@tonic-gate int 5310Sstevel@tonic-gate px_lib_iommu_demap(dev_info_t *dip, tsbid_t tsbid, pages_t pages) 5320Sstevel@tonic-gate { 5330Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5340Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 5350Sstevel@tonic-gate uint64_t ret; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_demap: dip 0x%p tsbid 0x%llx " 5380Sstevel@tonic-gate "pages 0x%x\n", dip, tsbid, pages); 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate if ((ret = hvio_iommu_demap(px_p->px_dev_hdl, pxu_p, tsbid, pages)) 5410Sstevel@tonic-gate != H_EOK) { 5420Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 5430Sstevel@tonic-gate "px_lib_iommu_demap failed, ret 0x%lx\n", ret); 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate return (DDI_FAILURE); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate return (DDI_SUCCESS); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate /*ARGSUSED*/ 5520Sstevel@tonic-gate int 5531617Sgovinda px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, io_attributes_t *attr_p, 5541617Sgovinda r_addr_t *r_addr_p) 5550Sstevel@tonic-gate { 5560Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5570Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 5580Sstevel@tonic-gate uint64_t ret; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: dip 0x%p tsbid 0x%llx\n", 5610Sstevel@tonic-gate dip, tsbid); 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate if ((ret = hvio_iommu_getmap(DIP_TO_HANDLE(dip), pxu_p, tsbid, 5641617Sgovinda attr_p, r_addr_p)) != H_EOK) { 5650Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 5660Sstevel@tonic-gate "hvio_iommu_getmap failed, ret 0x%lx\n", ret); 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate return ((ret == H_ENOMAP) ? DDI_DMA_NOMAPPING:DDI_FAILURE); 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate 5719707SDaniel.Ice@Sun.COM DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: attr 0x%llx " 5729707SDaniel.Ice@Sun.COM "r_addr 0x%llx\n", *attr_p, *r_addr_p); 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate return (DDI_SUCCESS); 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate /* 5790Sstevel@tonic-gate * Checks dma attributes against system bypass ranges 5800Sstevel@tonic-gate * The bypass range is determined by the hardware. Return them so the 5810Sstevel@tonic-gate * common code can do generic checking against them. 5820Sstevel@tonic-gate */ 5830Sstevel@tonic-gate /*ARGSUSED*/ 5840Sstevel@tonic-gate int 5851772Sjl139090 px_lib_dma_bypass_rngchk(dev_info_t *dip, ddi_dma_attr_t *attr_p, 5861772Sjl139090 uint64_t *lo_p, uint64_t *hi_p) 5870Sstevel@tonic-gate { 5881772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 5891772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 5901772Sjl139090 5911772Sjl139090 *lo_p = hvio_get_bypass_base(pxu_p); 5921772Sjl139090 *hi_p = hvio_get_bypass_end(pxu_p); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate return (DDI_SUCCESS); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate /*ARGSUSED*/ 5990Sstevel@tonic-gate int 6001617Sgovinda px_lib_iommu_getbypass(dev_info_t *dip, r_addr_t ra, io_attributes_t attr, 6011617Sgovinda io_addr_t *io_addr_p) 6020Sstevel@tonic-gate { 6030Sstevel@tonic-gate uint64_t ret; 6041772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 6051772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: dip 0x%p ra 0x%llx " 6089707SDaniel.Ice@Sun.COM "attr 0x%llx\n", dip, ra, attr); 6090Sstevel@tonic-gate 6101772Sjl139090 if ((ret = hvio_iommu_getbypass(DIP_TO_HANDLE(dip), pxu_p, ra, 6111772Sjl139090 attr, io_addr_p)) != H_EOK) { 6120Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 6130Sstevel@tonic-gate "hvio_iommu_getbypass failed, ret 0x%lx\n", ret); 6140Sstevel@tonic-gate return (DDI_FAILURE); 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: io_addr 0x%llx\n", 6180Sstevel@tonic-gate *io_addr_p); 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate return (DDI_SUCCESS); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6248691SLida.Horn@Sun.COM * Returns any needed IO address bit(s) for relaxed ordering in IOMMU 6258691SLida.Horn@Sun.COM * bypass mode. 6268691SLida.Horn@Sun.COM */ 6278691SLida.Horn@Sun.COM uint64_t 6288691SLida.Horn@Sun.COM px_lib_ro_bypass(dev_info_t *dip, io_attributes_t attr, uint64_t ioaddr) 6298691SLida.Horn@Sun.COM { 6308691SLida.Horn@Sun.COM px_t *px_p = DIP_TO_STATE(dip); 6318691SLida.Horn@Sun.COM pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 6328691SLida.Horn@Sun.COM 6338691SLida.Horn@Sun.COM if ((PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) && (attr & PCI_MAP_ATTR_RO)) 6348691SLida.Horn@Sun.COM return (MMU_OBERON_BYPASS_RO | ioaddr); 6358691SLida.Horn@Sun.COM else 6368691SLida.Horn@Sun.COM return (ioaddr); 6378691SLida.Horn@Sun.COM } 6388691SLida.Horn@Sun.COM 6398691SLida.Horn@Sun.COM /* 6400Sstevel@tonic-gate * bus dma sync entry point. 6410Sstevel@tonic-gate */ 6420Sstevel@tonic-gate /*ARGSUSED*/ 6430Sstevel@tonic-gate int 6440Sstevel@tonic-gate px_lib_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, 6451617Sgovinda off_t off, size_t len, uint_t cache_flags) 6460Sstevel@tonic-gate { 6470Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 6481772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 6491772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_dma_sync: dip 0x%p rdip 0x%p " 6520Sstevel@tonic-gate "handle 0x%llx off 0x%x len 0x%x flags 0x%x\n", 6530Sstevel@tonic-gate dip, rdip, handle, off, len, cache_flags); 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate /* 6561772Sjl139090 * No flush needed for Oberon 6571772Sjl139090 */ 6581772Sjl139090 if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) 6591772Sjl139090 return (DDI_SUCCESS); 6601772Sjl139090 6611772Sjl139090 /* 6620Sstevel@tonic-gate * jbus_stst_order is found only in certain cpu modules. 6630Sstevel@tonic-gate * Just return success if not present. 6640Sstevel@tonic-gate */ 6650Sstevel@tonic-gate if (&jbus_stst_order == NULL) 6660Sstevel@tonic-gate return (DDI_SUCCESS); 6670Sstevel@tonic-gate 668909Segillett if (!(mp->dmai_flags & PX_DMAI_FLAGS_INUSE)) { 66927Sjchu cmn_err(CE_WARN, "%s%d: Unbound dma handle %p.", 67027Sjchu ddi_driver_name(rdip), ddi_get_instance(rdip), (void *)mp); 67127Sjchu 6720Sstevel@tonic-gate return (DDI_FAILURE); 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 675909Segillett if (mp->dmai_flags & PX_DMAI_FLAGS_NOSYNC) 6760Sstevel@tonic-gate return (DDI_SUCCESS); 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate /* 6790Sstevel@tonic-gate * No flush needed when sending data from memory to device. 6800Sstevel@tonic-gate * Nothing to do to "sync" memory to what device would already see. 6810Sstevel@tonic-gate */ 6820Sstevel@tonic-gate if (!(mp->dmai_rflags & DDI_DMA_READ) || 6830Sstevel@tonic-gate ((cache_flags & PX_DMA_SYNC_DDI_FLAGS) == DDI_DMA_SYNC_FORDEV)) 6840Sstevel@tonic-gate return (DDI_SUCCESS); 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate /* 6870Sstevel@tonic-gate * Perform necessary cpu workaround to ensure jbus ordering. 6880Sstevel@tonic-gate * CPU's internal "invalidate FIFOs" are flushed. 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate #if !defined(lint) 6920Sstevel@tonic-gate kpreempt_disable(); 6930Sstevel@tonic-gate #endif 6940Sstevel@tonic-gate jbus_stst_order(); 6950Sstevel@tonic-gate #if !defined(lint) 6960Sstevel@tonic-gate kpreempt_enable(); 6970Sstevel@tonic-gate #endif 6980Sstevel@tonic-gate return (DDI_SUCCESS); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate /* 7020Sstevel@tonic-gate * MSIQ Functions: 7030Sstevel@tonic-gate */ 7040Sstevel@tonic-gate /*ARGSUSED*/ 7050Sstevel@tonic-gate int 7060Sstevel@tonic-gate px_lib_msiq_init(dev_info_t *dip) 7070Sstevel@tonic-gate { 7080Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 7090Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 7100Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 7110Sstevel@tonic-gate px_dvma_addr_t pg_index; 7127403SAlan.Adamson@Sun.COM size_t q_sz = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t); 7130Sstevel@tonic-gate size_t size; 7147403SAlan.Adamson@Sun.COM int i, ret; 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_init: dip 0x%p\n", dip); 7170Sstevel@tonic-gate 7187403SAlan.Adamson@Sun.COM /* must aligned on q_sz (happens to be !!! page) boundary */ 7197403SAlan.Adamson@Sun.COM ASSERT(q_sz == 8 * 1024); 7207403SAlan.Adamson@Sun.COM 7210Sstevel@tonic-gate /* 7220Sstevel@tonic-gate * Map the EQ memory into the Fire MMU (has to be 512KB aligned) 7230Sstevel@tonic-gate * and then initialize the base address register. 7240Sstevel@tonic-gate * 7250Sstevel@tonic-gate * Allocate entries from Fire IOMMU so that the resulting address 7260Sstevel@tonic-gate * is properly aligned. Calculate the index of the first allocated 7270Sstevel@tonic-gate * entry. Note: The size of the mapping is assumed to be a multiple 7280Sstevel@tonic-gate * of the page size. 7290Sstevel@tonic-gate */ 7307403SAlan.Adamson@Sun.COM size = msiq_state_p->msiq_cnt * q_sz; 7317403SAlan.Adamson@Sun.COM 7327403SAlan.Adamson@Sun.COM msiq_state_p->msiq_buf_p = kmem_zalloc(size, KM_SLEEP); 7337403SAlan.Adamson@Sun.COM 7347403SAlan.Adamson@Sun.COM for (i = 0; i < msiq_state_p->msiq_cnt; i++) 7357403SAlan.Adamson@Sun.COM msiq_state_p->msiq_p[i].msiq_base_p = (msiqhead_t *) 7367403SAlan.Adamson@Sun.COM ((caddr_t)msiq_state_p->msiq_buf_p + (i * q_sz)); 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate pxu_p->msiq_mapped_p = vmem_xalloc(px_p->px_mmu_p->mmu_dvma_map, 7390Sstevel@tonic-gate size, (512 * 1024), 0, 0, NULL, NULL, VM_NOSLEEP | VM_BESTFIT); 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate if (pxu_p->msiq_mapped_p == NULL) 7420Sstevel@tonic-gate return (DDI_FAILURE); 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p, 7450Sstevel@tonic-gate MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p)); 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate if ((ret = px_lib_iommu_map(px_p->px_dip, PCI_TSBID(0, pg_index), 7482755Segillett MMU_BTOP(size), PCI_MAP_ATTR_WRITE, msiq_state_p->msiq_buf_p, 7492755Segillett 0, MMU_MAP_BUF)) != DDI_SUCCESS) { 7500Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 7516983Sanbui "px_lib_msiq_init: px_lib_iommu_map failed, " 7526983Sanbui "ret 0x%lx\n", ret); 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate (void) px_lib_msiq_fini(dip); 7550Sstevel@tonic-gate return (DDI_FAILURE); 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7587124Sanbui if ((ret = hvio_msiq_init(DIP_TO_HANDLE(dip), 7597124Sanbui pxu_p)) != H_EOK) { 7607124Sanbui DBG(DBG_LIB_MSIQ, dip, 7617124Sanbui "hvio_msiq_init failed, ret 0x%lx\n", ret); 7627124Sanbui 7637124Sanbui (void) px_lib_msiq_fini(dip); 7647124Sanbui return (DDI_FAILURE); 7657124Sanbui } 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate return (DDI_SUCCESS); 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate /*ARGSUSED*/ 7710Sstevel@tonic-gate int 7720Sstevel@tonic-gate px_lib_msiq_fini(dev_info_t *dip) 7730Sstevel@tonic-gate { 7740Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 7750Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 7760Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 7770Sstevel@tonic-gate px_dvma_addr_t pg_index; 7780Sstevel@tonic-gate size_t size; 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_fini: dip 0x%p\n", dip); 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate /* 7830Sstevel@tonic-gate * Unmap and free the EQ memory that had been mapped 7840Sstevel@tonic-gate * into the Fire IOMMU. 7850Sstevel@tonic-gate */ 7860Sstevel@tonic-gate size = msiq_state_p->msiq_cnt * 7870Sstevel@tonic-gate msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t); 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p, 7900Sstevel@tonic-gate MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p)); 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate (void) px_lib_iommu_demap(px_p->px_dip, 7930Sstevel@tonic-gate PCI_TSBID(0, pg_index), MMU_BTOP(size)); 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate /* Free the entries from the Fire MMU */ 7960Sstevel@tonic-gate vmem_xfree(px_p->px_mmu_p->mmu_dvma_map, 7970Sstevel@tonic-gate (void *)pxu_p->msiq_mapped_p, size); 7980Sstevel@tonic-gate 7997403SAlan.Adamson@Sun.COM kmem_free(msiq_state_p->msiq_buf_p, msiq_state_p->msiq_cnt * 8007403SAlan.Adamson@Sun.COM msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t)); 8017403SAlan.Adamson@Sun.COM 8020Sstevel@tonic-gate return (DDI_SUCCESS); 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate /*ARGSUSED*/ 8060Sstevel@tonic-gate int 8070Sstevel@tonic-gate px_lib_msiq_info(dev_info_t *dip, msiqid_t msiq_id, r_addr_t *ra_p, 8080Sstevel@tonic-gate uint_t *msiq_rec_cnt_p) 8090Sstevel@tonic-gate { 8100Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 8110Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 8120Sstevel@tonic-gate size_t msiq_size; 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: dip 0x%p msiq_id 0x%x\n", 8150Sstevel@tonic-gate dip, msiq_id); 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t); 8182755Segillett ra_p = (r_addr_t *)((caddr_t)msiq_state_p->msiq_buf_p + 8192755Segillett (msiq_id * msiq_size)); 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate *msiq_rec_cnt_p = msiq_state_p->msiq_rec_cnt; 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: ra_p 0x%p msiq_rec_cnt 0x%x\n", 8240Sstevel@tonic-gate ra_p, *msiq_rec_cnt_p); 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate return (DDI_SUCCESS); 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate /*ARGSUSED*/ 8300Sstevel@tonic-gate int 8310Sstevel@tonic-gate px_lib_msiq_getvalid(dev_info_t *dip, msiqid_t msiq_id, 8320Sstevel@tonic-gate pci_msiq_valid_state_t *msiq_valid_state) 8330Sstevel@tonic-gate { 8340Sstevel@tonic-gate uint64_t ret; 8350Sstevel@tonic-gate 8360Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: dip 0x%p msiq_id 0x%x\n", 8370Sstevel@tonic-gate dip, msiq_id); 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate if ((ret = hvio_msiq_getvalid(DIP_TO_HANDLE(dip), 8400Sstevel@tonic-gate msiq_id, msiq_valid_state)) != H_EOK) { 8410Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8420Sstevel@tonic-gate "hvio_msiq_getvalid failed, ret 0x%lx\n", ret); 8430Sstevel@tonic-gate return (DDI_FAILURE); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: msiq_valid_state 0x%x\n", 8470Sstevel@tonic-gate *msiq_valid_state); 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_setvalid(dev_info_t *dip, msiqid_t msiq_id, 8550Sstevel@tonic-gate pci_msiq_valid_state_t msiq_valid_state) 8560Sstevel@tonic-gate { 8570Sstevel@tonic-gate uint64_t ret; 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setvalid: dip 0x%p msiq_id 0x%x " 8600Sstevel@tonic-gate "msiq_valid_state 0x%x\n", dip, msiq_id, msiq_valid_state); 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate if ((ret = hvio_msiq_setvalid(DIP_TO_HANDLE(dip), 8630Sstevel@tonic-gate msiq_id, msiq_valid_state)) != H_EOK) { 8640Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8650Sstevel@tonic-gate "hvio_msiq_setvalid failed, ret 0x%lx\n", ret); 8660Sstevel@tonic-gate return (DDI_FAILURE); 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate return (DDI_SUCCESS); 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate /*ARGSUSED*/ 8730Sstevel@tonic-gate int 8740Sstevel@tonic-gate px_lib_msiq_getstate(dev_info_t *dip, msiqid_t msiq_id, 8750Sstevel@tonic-gate pci_msiq_state_t *msiq_state) 8760Sstevel@tonic-gate { 8770Sstevel@tonic-gate uint64_t ret; 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: dip 0x%p msiq_id 0x%x\n", 8800Sstevel@tonic-gate dip, msiq_id); 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate if ((ret = hvio_msiq_getstate(DIP_TO_HANDLE(dip), 8830Sstevel@tonic-gate msiq_id, msiq_state)) != H_EOK) { 8840Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8850Sstevel@tonic-gate "hvio_msiq_getstate failed, ret 0x%lx\n", ret); 8860Sstevel@tonic-gate return (DDI_FAILURE); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: msiq_state 0x%x\n", 8900Sstevel@tonic-gate *msiq_state); 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_setstate(dev_info_t *dip, msiqid_t msiq_id, 8980Sstevel@tonic-gate pci_msiq_state_t msiq_state) 8990Sstevel@tonic-gate { 9000Sstevel@tonic-gate uint64_t ret; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setstate: dip 0x%p msiq_id 0x%x " 9030Sstevel@tonic-gate "msiq_state 0x%x\n", dip, msiq_id, msiq_state); 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate if ((ret = hvio_msiq_setstate(DIP_TO_HANDLE(dip), 9060Sstevel@tonic-gate msiq_id, msiq_state)) != H_EOK) { 9070Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 9080Sstevel@tonic-gate "hvio_msiq_setstate failed, ret 0x%lx\n", ret); 9090Sstevel@tonic-gate return (DDI_FAILURE); 9100Sstevel@tonic-gate } 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate return (DDI_SUCCESS); 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate /*ARGSUSED*/ 9160Sstevel@tonic-gate int 9170Sstevel@tonic-gate px_lib_msiq_gethead(dev_info_t *dip, msiqid_t msiq_id, 9180Sstevel@tonic-gate msiqhead_t *msiq_head) 9190Sstevel@tonic-gate { 9200Sstevel@tonic-gate uint64_t ret; 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: dip 0x%p msiq_id 0x%x\n", 9230Sstevel@tonic-gate dip, msiq_id); 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate if ((ret = hvio_msiq_gethead(DIP_TO_HANDLE(dip), 9260Sstevel@tonic-gate msiq_id, msiq_head)) != H_EOK) { 9270Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 9280Sstevel@tonic-gate "hvio_msiq_gethead failed, ret 0x%lx\n", ret); 9290Sstevel@tonic-gate return (DDI_FAILURE); 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: msiq_head 0x%x\n", 9330Sstevel@tonic-gate *msiq_head); 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate return (DDI_SUCCESS); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate /*ARGSUSED*/ 9390Sstevel@tonic-gate int 9400Sstevel@tonic-gate px_lib_msiq_sethead(dev_info_t *dip, msiqid_t msiq_id, 9410Sstevel@tonic-gate msiqhead_t msiq_head) 9420Sstevel@tonic-gate { 9430Sstevel@tonic-gate uint64_t ret; 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_sethead: dip 0x%p msiq_id 0x%x " 9460Sstevel@tonic-gate "msiq_head 0x%x\n", dip, msiq_id, msiq_head); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate if ((ret = hvio_msiq_sethead(DIP_TO_HANDLE(dip), 9490Sstevel@tonic-gate msiq_id, msiq_head)) != H_EOK) { 9500Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 9510Sstevel@tonic-gate "hvio_msiq_sethead failed, ret 0x%lx\n", ret); 9520Sstevel@tonic-gate return (DDI_FAILURE); 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate return (DDI_SUCCESS); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate /*ARGSUSED*/ 9590Sstevel@tonic-gate int 9600Sstevel@tonic-gate px_lib_msiq_gettail(dev_info_t *dip, msiqid_t msiq_id, 9610Sstevel@tonic-gate msiqtail_t *msiq_tail) 9620Sstevel@tonic-gate { 9630Sstevel@tonic-gate uint64_t ret; 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: dip 0x%p msiq_id 0x%x\n", 9660Sstevel@tonic-gate dip, msiq_id); 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate if ((ret = hvio_msiq_gettail(DIP_TO_HANDLE(dip), 9690Sstevel@tonic-gate msiq_id, msiq_tail)) != H_EOK) { 9700Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 9710Sstevel@tonic-gate "hvio_msiq_gettail failed, ret 0x%lx\n", ret); 9720Sstevel@tonic-gate return (DDI_FAILURE); 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: msiq_tail 0x%x\n", 9760Sstevel@tonic-gate *msiq_tail); 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate return (DDI_SUCCESS); 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate /*ARGSUSED*/ 9820Sstevel@tonic-gate void 9832588Segillett px_lib_get_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p, 9842588Segillett msiq_rec_t *msiq_rec_p) 9850Sstevel@tonic-gate { 9862588Segillett eq_rec_t *eq_rec_p = (eq_rec_t *)msiq_head_p; 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p eq_rec_p 0x%p\n", 9890Sstevel@tonic-gate dip, eq_rec_p); 9900Sstevel@tonic-gate 991287Smg140465 if (!eq_rec_p->eq_rec_fmt_type) { 992287Smg140465 /* Set msiq_rec_type to zero */ 993287Smg140465 msiq_rec_p->msiq_rec_type = 0; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate return; 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: EQ RECORD, " 9990Sstevel@tonic-gate "eq_rec_rid 0x%llx eq_rec_fmt_type 0x%llx " 10000Sstevel@tonic-gate "eq_rec_len 0x%llx eq_rec_addr0 0x%llx " 10010Sstevel@tonic-gate "eq_rec_addr1 0x%llx eq_rec_data0 0x%llx " 10020Sstevel@tonic-gate "eq_rec_data1 0x%llx\n", eq_rec_p->eq_rec_rid, 10030Sstevel@tonic-gate eq_rec_p->eq_rec_fmt_type, eq_rec_p->eq_rec_len, 10040Sstevel@tonic-gate eq_rec_p->eq_rec_addr0, eq_rec_p->eq_rec_addr1, 10050Sstevel@tonic-gate eq_rec_p->eq_rec_data0, eq_rec_p->eq_rec_data1); 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate /* 10080Sstevel@tonic-gate * Only upper 4 bits of eq_rec_fmt_type is used 10090Sstevel@tonic-gate * to identify the EQ record type. 10100Sstevel@tonic-gate */ 10110Sstevel@tonic-gate switch (eq_rec_p->eq_rec_fmt_type >> 3) { 10120Sstevel@tonic-gate case EQ_REC_MSI32: 10130Sstevel@tonic-gate msiq_rec_p->msiq_rec_type = MSI32_REC; 10140Sstevel@tonic-gate 1015225Sess msiq_rec_p->msiq_rec_data.msi.msi_data = 1016225Sess eq_rec_p->eq_rec_data0; 10170Sstevel@tonic-gate break; 10180Sstevel@tonic-gate case EQ_REC_MSI64: 10190Sstevel@tonic-gate msiq_rec_p->msiq_rec_type = MSI64_REC; 10200Sstevel@tonic-gate 1021225Sess msiq_rec_p->msiq_rec_data.msi.msi_data = 1022225Sess eq_rec_p->eq_rec_data0; 10230Sstevel@tonic-gate break; 10240Sstevel@tonic-gate case EQ_REC_MSG: 10250Sstevel@tonic-gate msiq_rec_p->msiq_rec_type = MSG_REC; 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate msiq_rec_p->msiq_rec_data.msg.msg_route = 10280Sstevel@tonic-gate eq_rec_p->eq_rec_fmt_type & 7; 10290Sstevel@tonic-gate msiq_rec_p->msiq_rec_data.msg.msg_targ = eq_rec_p->eq_rec_rid; 10300Sstevel@tonic-gate msiq_rec_p->msiq_rec_data.msg.msg_code = eq_rec_p->eq_rec_data0; 10310Sstevel@tonic-gate break; 10320Sstevel@tonic-gate default: 10330Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_lib_get_msiq_rec: " 1034671Skrishnae "0x%x is an unknown EQ record type", 10350Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 1036671Skrishnae (int)eq_rec_p->eq_rec_fmt_type); 10370Sstevel@tonic-gate break; 10380Sstevel@tonic-gate } 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate msiq_rec_p->msiq_rec_rid = eq_rec_p->eq_rec_rid; 10410Sstevel@tonic-gate msiq_rec_p->msiq_rec_msi_addr = ((eq_rec_p->eq_rec_addr1 << 16) | 10420Sstevel@tonic-gate (eq_rec_p->eq_rec_addr0 << 2)); 10432973Sgovinda } 10442973Sgovinda 10452973Sgovinda /*ARGSUSED*/ 10462973Sgovinda void 10472973Sgovinda px_lib_clr_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p) 10482973Sgovinda { 10492973Sgovinda eq_rec_t *eq_rec_p = (eq_rec_t *)msiq_head_p; 10502973Sgovinda 10512973Sgovinda DBG(DBG_LIB_MSIQ, dip, "px_lib_clr_msiq_rec: dip 0x%p eq_rec_p 0x%p\n", 10522973Sgovinda dip, eq_rec_p); 10532973Sgovinda 10542973Sgovinda if (eq_rec_p->eq_rec_fmt_type) { 10552973Sgovinda /* Zero out eq_rec_fmt_type field */ 10562973Sgovinda eq_rec_p->eq_rec_fmt_type = 0; 10572973Sgovinda } 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate /* 10610Sstevel@tonic-gate * MSI Functions: 10620Sstevel@tonic-gate */ 10630Sstevel@tonic-gate /*ARGSUSED*/ 10640Sstevel@tonic-gate int 10650Sstevel@tonic-gate px_lib_msi_init(dev_info_t *dip) 10660Sstevel@tonic-gate { 10670Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 10680Sstevel@tonic-gate px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 10690Sstevel@tonic-gate uint64_t ret; 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_init: dip 0x%p\n", dip); 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate if ((ret = hvio_msi_init(DIP_TO_HANDLE(dip), 10740Sstevel@tonic-gate msi_state_p->msi_addr32, msi_state_p->msi_addr64)) != H_EOK) { 10750Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msi_init failed, ret 0x%lx\n", 10760Sstevel@tonic-gate ret); 10770Sstevel@tonic-gate return (DDI_FAILURE); 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate return (DDI_SUCCESS); 10810Sstevel@tonic-gate } 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate /*ARGSUSED*/ 10840Sstevel@tonic-gate int 10850Sstevel@tonic-gate px_lib_msi_getmsiq(dev_info_t *dip, msinum_t msi_num, 10860Sstevel@tonic-gate msiqid_t *msiq_id) 10870Sstevel@tonic-gate { 10880Sstevel@tonic-gate uint64_t ret; 10890Sstevel@tonic-gate 10900Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: dip 0x%p msi_num 0x%x\n", 10910Sstevel@tonic-gate dip, msi_num); 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate if ((ret = hvio_msi_getmsiq(DIP_TO_HANDLE(dip), 10940Sstevel@tonic-gate msi_num, msiq_id)) != H_EOK) { 10950Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10960Sstevel@tonic-gate "hvio_msi_getmsiq failed, ret 0x%lx\n", ret); 10970Sstevel@tonic-gate return (DDI_FAILURE); 10980Sstevel@tonic-gate } 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: msiq_id 0x%x\n", 11010Sstevel@tonic-gate *msiq_id); 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_setmsiq(dev_info_t *dip, msinum_t msi_num, 11090Sstevel@tonic-gate msiqid_t msiq_id, msi_type_t msitype) 11100Sstevel@tonic-gate { 11110Sstevel@tonic-gate uint64_t ret; 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_setmsiq: dip 0x%p msi_num 0x%x " 11140Sstevel@tonic-gate "msq_id 0x%x\n", dip, msi_num, msiq_id); 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate if ((ret = hvio_msi_setmsiq(DIP_TO_HANDLE(dip), 11170Sstevel@tonic-gate msi_num, msiq_id)) != H_EOK) { 11180Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 11190Sstevel@tonic-gate "hvio_msi_setmsiq failed, ret 0x%lx\n", ret); 11200Sstevel@tonic-gate return (DDI_FAILURE); 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate return (DDI_SUCCESS); 11240Sstevel@tonic-gate } 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate /*ARGSUSED*/ 11270Sstevel@tonic-gate int 11280Sstevel@tonic-gate px_lib_msi_getvalid(dev_info_t *dip, msinum_t msi_num, 11290Sstevel@tonic-gate pci_msi_valid_state_t *msi_valid_state) 11300Sstevel@tonic-gate { 11310Sstevel@tonic-gate uint64_t ret; 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: dip 0x%p msi_num 0x%x\n", 11340Sstevel@tonic-gate dip, msi_num); 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate if ((ret = hvio_msi_getvalid(DIP_TO_HANDLE(dip), 11370Sstevel@tonic-gate msi_num, msi_valid_state)) != H_EOK) { 11380Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 11390Sstevel@tonic-gate "hvio_msi_getvalid failed, ret 0x%lx\n", ret); 11400Sstevel@tonic-gate return (DDI_FAILURE); 11410Sstevel@tonic-gate } 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: msiq_id 0x%x\n", 11440Sstevel@tonic-gate *msi_valid_state); 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate return (DDI_SUCCESS); 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate /*ARGSUSED*/ 11500Sstevel@tonic-gate int 11510Sstevel@tonic-gate px_lib_msi_setvalid(dev_info_t *dip, msinum_t msi_num, 11520Sstevel@tonic-gate pci_msi_valid_state_t msi_valid_state) 11530Sstevel@tonic-gate { 11540Sstevel@tonic-gate uint64_t ret; 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_setvalid: dip 0x%p msi_num 0x%x " 11570Sstevel@tonic-gate "msi_valid_state 0x%x\n", dip, msi_num, msi_valid_state); 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate if ((ret = hvio_msi_setvalid(DIP_TO_HANDLE(dip), 11600Sstevel@tonic-gate msi_num, msi_valid_state)) != H_EOK) { 11610Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 11620Sstevel@tonic-gate "hvio_msi_setvalid failed, ret 0x%lx\n", ret); 11630Sstevel@tonic-gate return (DDI_FAILURE); 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate return (DDI_SUCCESS); 11670Sstevel@tonic-gate } 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate /*ARGSUSED*/ 11700Sstevel@tonic-gate int 11710Sstevel@tonic-gate px_lib_msi_getstate(dev_info_t *dip, msinum_t msi_num, 11720Sstevel@tonic-gate pci_msi_state_t *msi_state) 11730Sstevel@tonic-gate { 11740Sstevel@tonic-gate uint64_t ret; 11750Sstevel@tonic-gate 11760Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: dip 0x%p msi_num 0x%x\n", 11770Sstevel@tonic-gate dip, msi_num); 11780Sstevel@tonic-gate 11790Sstevel@tonic-gate if ((ret = hvio_msi_getstate(DIP_TO_HANDLE(dip), 11800Sstevel@tonic-gate msi_num, msi_state)) != H_EOK) { 11810Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 11820Sstevel@tonic-gate "hvio_msi_getstate failed, ret 0x%lx\n", ret); 11830Sstevel@tonic-gate return (DDI_FAILURE); 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: msi_state 0x%x\n", 11870Sstevel@tonic-gate *msi_state); 11880Sstevel@tonic-gate 11890Sstevel@tonic-gate return (DDI_SUCCESS); 11900Sstevel@tonic-gate } 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate /*ARGSUSED*/ 11930Sstevel@tonic-gate int 11940Sstevel@tonic-gate px_lib_msi_setstate(dev_info_t *dip, msinum_t msi_num, 11950Sstevel@tonic-gate pci_msi_state_t msi_state) 11960Sstevel@tonic-gate { 11970Sstevel@tonic-gate uint64_t ret; 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_setstate: dip 0x%p msi_num 0x%x " 12000Sstevel@tonic-gate "msi_state 0x%x\n", dip, msi_num, msi_state); 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate if ((ret = hvio_msi_setstate(DIP_TO_HANDLE(dip), 12030Sstevel@tonic-gate msi_num, msi_state)) != H_EOK) { 12040Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 12050Sstevel@tonic-gate "hvio_msi_setstate failed, ret 0x%lx\n", ret); 12060Sstevel@tonic-gate return (DDI_FAILURE); 12070Sstevel@tonic-gate } 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate return (DDI_SUCCESS); 12100Sstevel@tonic-gate } 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate /* 12130Sstevel@tonic-gate * MSG Functions: 12140Sstevel@tonic-gate */ 12150Sstevel@tonic-gate /*ARGSUSED*/ 12160Sstevel@tonic-gate int 12170Sstevel@tonic-gate px_lib_msg_getmsiq(dev_info_t *dip, pcie_msg_type_t msg_type, 12180Sstevel@tonic-gate msiqid_t *msiq_id) 12190Sstevel@tonic-gate { 12200Sstevel@tonic-gate uint64_t ret; 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msg_getmsiq: dip 0x%p msg_type 0x%x\n", 12230Sstevel@tonic-gate dip, msg_type); 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate if ((ret = hvio_msg_getmsiq(DIP_TO_HANDLE(dip), 12260Sstevel@tonic-gate msg_type, msiq_id)) != H_EOK) { 12270Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 12280Sstevel@tonic-gate "hvio_msg_getmsiq failed, ret 0x%lx\n", ret); 12290Sstevel@tonic-gate return (DDI_FAILURE); 12300Sstevel@tonic-gate } 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msg_getmsiq: msiq_id 0x%x\n", 12330Sstevel@tonic-gate *msiq_id); 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate return (DDI_SUCCESS); 12360Sstevel@tonic-gate } 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate /*ARGSUSED*/ 12390Sstevel@tonic-gate int 12400Sstevel@tonic-gate px_lib_msg_setmsiq(dev_info_t *dip, pcie_msg_type_t msg_type, 12410Sstevel@tonic-gate msiqid_t msiq_id) 12420Sstevel@tonic-gate { 12430Sstevel@tonic-gate uint64_t ret; 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msi_setstate: dip 0x%p msg_type 0x%x " 12460Sstevel@tonic-gate "msiq_id 0x%x\n", dip, msg_type, msiq_id); 12470Sstevel@tonic-gate 12480Sstevel@tonic-gate if ((ret = hvio_msg_setmsiq(DIP_TO_HANDLE(dip), 12490Sstevel@tonic-gate msg_type, msiq_id)) != H_EOK) { 12500Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 12510Sstevel@tonic-gate "hvio_msg_setmsiq failed, ret 0x%lx\n", ret); 12520Sstevel@tonic-gate return (DDI_FAILURE); 12530Sstevel@tonic-gate } 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate return (DDI_SUCCESS); 12560Sstevel@tonic-gate } 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate /*ARGSUSED*/ 12590Sstevel@tonic-gate int 12600Sstevel@tonic-gate px_lib_msg_getvalid(dev_info_t *dip, pcie_msg_type_t msg_type, 12610Sstevel@tonic-gate pcie_msg_valid_state_t *msg_valid_state) 12620Sstevel@tonic-gate { 12630Sstevel@tonic-gate uint64_t ret; 12640Sstevel@tonic-gate 12650Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msg_getvalid: dip 0x%p msg_type 0x%x\n", 12660Sstevel@tonic-gate dip, msg_type); 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate if ((ret = hvio_msg_getvalid(DIP_TO_HANDLE(dip), msg_type, 12690Sstevel@tonic-gate msg_valid_state)) != H_EOK) { 12700Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 12710Sstevel@tonic-gate "hvio_msg_getvalid failed, ret 0x%lx\n", ret); 12720Sstevel@tonic-gate return (DDI_FAILURE); 12730Sstevel@tonic-gate } 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msg_getvalid: msg_valid_state 0x%x\n", 12760Sstevel@tonic-gate *msg_valid_state); 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate return (DDI_SUCCESS); 12790Sstevel@tonic-gate } 12800Sstevel@tonic-gate 12810Sstevel@tonic-gate /*ARGSUSED*/ 12820Sstevel@tonic-gate int 12830Sstevel@tonic-gate px_lib_msg_setvalid(dev_info_t *dip, pcie_msg_type_t msg_type, 12840Sstevel@tonic-gate pcie_msg_valid_state_t msg_valid_state) 12850Sstevel@tonic-gate { 12860Sstevel@tonic-gate uint64_t ret; 12870Sstevel@tonic-gate 12880Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msg_setvalid: dip 0x%p msg_type 0x%x " 12890Sstevel@tonic-gate "msg_valid_state 0x%x\n", dip, msg_type, msg_valid_state); 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate if ((ret = hvio_msg_setvalid(DIP_TO_HANDLE(dip), msg_type, 12920Sstevel@tonic-gate msg_valid_state)) != H_EOK) { 12930Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 12940Sstevel@tonic-gate "hvio_msg_setvalid failed, ret 0x%lx\n", ret); 12950Sstevel@tonic-gate return (DDI_FAILURE); 12960Sstevel@tonic-gate } 12970Sstevel@tonic-gate 12980Sstevel@tonic-gate return (DDI_SUCCESS); 12990Sstevel@tonic-gate } 13000Sstevel@tonic-gate 1301*11596SJason.Beloro@Sun.COM /*ARGSUSED*/ 1302*11596SJason.Beloro@Sun.COM void 1303*11596SJason.Beloro@Sun.COM px_panic_domain(px_t *px_p, pcie_req_id_t bdf) 1304*11596SJason.Beloro@Sun.COM { 1305*11596SJason.Beloro@Sun.COM } 1306*11596SJason.Beloro@Sun.COM 13070Sstevel@tonic-gate /* 13080Sstevel@tonic-gate * Suspend/Resume Functions: 13090Sstevel@tonic-gate * Currently unsupported by hypervisor 13100Sstevel@tonic-gate */ 13110Sstevel@tonic-gate int 13120Sstevel@tonic-gate px_lib_suspend(dev_info_t *dip) 13130Sstevel@tonic-gate { 13140Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 13150Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 13161648Sjchu px_cb_t *cb_p = PX2CB(px_p); 13170Sstevel@tonic-gate devhandle_t dev_hdl, xbus_dev_hdl; 13181648Sjchu uint64_t ret = H_EOK; 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate DBG(DBG_DETACH, dip, "px_lib_suspend: dip 0x%p\n", dip); 13210Sstevel@tonic-gate 132227Sjchu dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR]; 132327Sjchu xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC]; 13240Sstevel@tonic-gate 13251648Sjchu if ((ret = hvio_suspend(dev_hdl, pxu_p)) != H_EOK) 13261648Sjchu goto fail; 13271648Sjchu 13281648Sjchu if (--cb_p->attachcnt == 0) { 13291648Sjchu ret = hvio_cb_suspend(xbus_dev_hdl, pxu_p); 13301648Sjchu if (ret != H_EOK) 13311648Sjchu cb_p->attachcnt++; 13320Sstevel@tonic-gate } 13333274Set142600 pxu_p->cpr_flag = PX_ENTERED_CPR; 13340Sstevel@tonic-gate 13351648Sjchu fail: 13360Sstevel@tonic-gate return ((ret != H_EOK) ? DDI_FAILURE: DDI_SUCCESS); 13370Sstevel@tonic-gate } 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate void 13400Sstevel@tonic-gate px_lib_resume(dev_info_t *dip) 13410Sstevel@tonic-gate { 13420Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 13430Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 13441648Sjchu px_cb_t *cb_p = PX2CB(px_p); 13450Sstevel@tonic-gate devhandle_t dev_hdl, xbus_dev_hdl; 13460Sstevel@tonic-gate devino_t pec_ino = px_p->px_inos[PX_INTR_PEC]; 13470Sstevel@tonic-gate devino_t xbc_ino = px_p->px_inos[PX_INTR_XBC]; 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "px_lib_resume: dip 0x%p\n", dip); 13500Sstevel@tonic-gate 135127Sjchu dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR]; 135227Sjchu xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC]; 13530Sstevel@tonic-gate 13541648Sjchu if (++cb_p->attachcnt == 1) 13550Sstevel@tonic-gate hvio_cb_resume(dev_hdl, xbus_dev_hdl, xbc_ino, pxu_p); 13560Sstevel@tonic-gate 13571648Sjchu hvio_resume(dev_hdl, pec_ino, pxu_p); 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate 13601772Sjl139090 /* 13611772Sjl139090 * Generate a unique Oberon UBC ID based on the Logicial System Board and 13621772Sjl139090 * the IO Channel from the portid property field. 13631772Sjl139090 */ 13641772Sjl139090 static uint64_t 13651772Sjl139090 oberon_get_ubc_id(dev_info_t *dip) 13661772Sjl139090 { 13671772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 13681772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 13691772Sjl139090 uint64_t ubc_id; 13701772Sjl139090 13711772Sjl139090 /* 13721772Sjl139090 * Generate a unique 6 bit UBC ID using the 2 IO_Channel#[1:0] bits and 13731772Sjl139090 * the 4 LSB_ID[3:0] bits from the Oberon's portid property. 13741772Sjl139090 */ 13751772Sjl139090 ubc_id = (((pxu_p->portid >> OBERON_PORT_ID_IOC) & 13761772Sjl139090 OBERON_PORT_ID_IOC_MASK) | (((pxu_p->portid >> 13771772Sjl139090 OBERON_PORT_ID_LSB) & OBERON_PORT_ID_LSB_MASK) 13781772Sjl139090 << OBERON_UBC_ID_LSB)); 13791772Sjl139090 13801772Sjl139090 return (ubc_id); 13811772Sjl139090 } 13821772Sjl139090 13831772Sjl139090 /* 13841772Sjl139090 * Oberon does not have a UBC scratch register, so alloc an array of scratch 13851772Sjl139090 * registers when needed and use a unique UBC ID as an index. This code 13861772Sjl139090 * can be simplified if we use a pre-allocated array. They are currently 13871772Sjl139090 * being dynamically allocated because it's only needed by the Oberon. 13881772Sjl139090 */ 13891772Sjl139090 static void 13901772Sjl139090 oberon_set_cb(dev_info_t *dip, uint64_t val) 13911772Sjl139090 { 13921772Sjl139090 uint64_t ubc_id; 13931772Sjl139090 13941772Sjl139090 if (px_oberon_ubc_scratch_regs == NULL) 13951772Sjl139090 px_oberon_ubc_scratch_regs = 13961772Sjl139090 (uint64_t *)kmem_zalloc(sizeof (uint64_t)* 13971772Sjl139090 OBERON_UBC_ID_MAX, KM_SLEEP); 13981772Sjl139090 13991772Sjl139090 ubc_id = oberon_get_ubc_id(dip); 14001772Sjl139090 14011772Sjl139090 px_oberon_ubc_scratch_regs[ubc_id] = val; 14021772Sjl139090 14031772Sjl139090 /* 14041772Sjl139090 * Check if any scratch registers are still in use. If all scratch 14051772Sjl139090 * registers are currently set to zero, then deallocate the scratch 14061772Sjl139090 * register array. 14071772Sjl139090 */ 14081772Sjl139090 for (ubc_id = 0; ubc_id < OBERON_UBC_ID_MAX; ubc_id++) { 14091772Sjl139090 if (px_oberon_ubc_scratch_regs[ubc_id] != NULL) 14101772Sjl139090 return; 14111772Sjl139090 } 14121772Sjl139090 14131772Sjl139090 /* 14141772Sjl139090 * All scratch registers are set to zero so deallocate the scratch 14151772Sjl139090 * register array and set the pointer to NULL. 14161772Sjl139090 */ 14171772Sjl139090 kmem_free(px_oberon_ubc_scratch_regs, 14181772Sjl139090 (sizeof (uint64_t)*OBERON_UBC_ID_MAX)); 14191772Sjl139090 14201772Sjl139090 px_oberon_ubc_scratch_regs = NULL; 14211772Sjl139090 } 14221772Sjl139090 14231772Sjl139090 /* 14241772Sjl139090 * Oberon does not have a UBC scratch register, so use an allocated array of 14251772Sjl139090 * scratch registers and use the unique UBC ID as an index into that array. 14261772Sjl139090 */ 14271772Sjl139090 static uint64_t 14281772Sjl139090 oberon_get_cb(dev_info_t *dip) 14291772Sjl139090 { 14301772Sjl139090 uint64_t ubc_id; 14311772Sjl139090 14321772Sjl139090 if (px_oberon_ubc_scratch_regs == NULL) 14331772Sjl139090 return (0); 14341772Sjl139090 14351772Sjl139090 ubc_id = oberon_get_ubc_id(dip); 14361772Sjl139090 14371772Sjl139090 return (px_oberon_ubc_scratch_regs[ubc_id]); 14381772Sjl139090 } 14391772Sjl139090 14401772Sjl139090 /* 14411772Sjl139090 * Misc Functions: 14421772Sjl139090 * Currently unsupported by hypervisor 14431772Sjl139090 */ 14441772Sjl139090 static uint64_t 14451772Sjl139090 px_get_cb(dev_info_t *dip) 14461772Sjl139090 { 14471772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 14481772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 14491772Sjl139090 14501772Sjl139090 /* 14511772Sjl139090 * Oberon does not currently have Scratchpad registers. 14521772Sjl139090 */ 14531772Sjl139090 if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) 14541772Sjl139090 return (oberon_get_cb(dip)); 14551772Sjl139090 14561772Sjl139090 return (CSR_XR((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1)); 14571772Sjl139090 } 14581772Sjl139090 14591772Sjl139090 static void 14601772Sjl139090 px_set_cb(dev_info_t *dip, uint64_t val) 14611772Sjl139090 { 14621772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 14631772Sjl139090 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 14641772Sjl139090 14651772Sjl139090 /* 14661772Sjl139090 * Oberon does not currently have Scratchpad registers. 14671772Sjl139090 */ 14681772Sjl139090 if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) { 14691772Sjl139090 oberon_set_cb(dip, val); 14701772Sjl139090 return; 14711772Sjl139090 } 14721772Sjl139090 14731772Sjl139090 CSR_XS((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1, val); 14741772Sjl139090 } 14751772Sjl139090 14760Sstevel@tonic-gate /*ARGSUSED*/ 14770Sstevel@tonic-gate int 14780Sstevel@tonic-gate px_lib_map_vconfig(dev_info_t *dip, 14790Sstevel@tonic-gate ddi_map_req_t *mp, pci_config_offset_t off, 14800Sstevel@tonic-gate pci_regspec_t *rp, caddr_t *addrp) 14810Sstevel@tonic-gate { 14820Sstevel@tonic-gate /* 14830Sstevel@tonic-gate * No special config space access services in this layer. 14840Sstevel@tonic-gate */ 14850Sstevel@tonic-gate return (DDI_FAILURE); 14860Sstevel@tonic-gate } 14870Sstevel@tonic-gate 1488624Sschwartz void 1489677Sjchu px_lib_map_attr_check(ddi_map_req_t *mp) 1490677Sjchu { 1491677Sjchu ddi_acc_hdl_t *hp = mp->map_handlep; 1492677Sjchu 1493677Sjchu /* fire does not accept byte masks from PIO store merge */ 1494677Sjchu if (hp->ah_acc.devacc_attr_dataorder == DDI_STORECACHING_OK_ACC) 1495677Sjchu hp->ah_acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1496677Sjchu } 1497677Sjchu 14983274Set142600 /* This function is called only by poke, caut put and pxtool poke. */ 1499677Sjchu void 15003274Set142600 px_lib_clr_errs(px_t *px_p, dev_info_t *rdip, uint64_t addr) 150127Sjchu { 1502624Sschwartz px_pec_t *pec_p = px_p->px_pec_p; 150327Sjchu dev_info_t *rpdip = px_p->px_dip; 15043274Set142600 int rc_err, fab_err, i; 150527Sjchu int acctype = pec_p->pec_safeacc_type; 150627Sjchu ddi_fm_error_t derr; 150710923SEvan.Yan@Sun.COM pci_ranges_t *ranges_p; 15083274Set142600 int range_len; 15093274Set142600 uint32_t addr_high, addr_low; 15109921SKrishna.Elango@Sun.COM pcie_req_id_t bdf = PCIE_INVALID_BDF; 151127Sjchu 151227Sjchu /* Create the derr */ 151327Sjchu bzero(&derr, sizeof (ddi_fm_error_t)); 151427Sjchu derr.fme_version = DDI_FME_VERSION; 151527Sjchu derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 151627Sjchu derr.fme_flag = acctype; 151727Sjchu 151827Sjchu if (acctype == DDI_FM_ERR_EXPECTED) { 151927Sjchu derr.fme_status = DDI_FM_NONFATAL; 152027Sjchu ndi_fm_acc_err_set(pec_p->pec_acc_hdl, &derr); 152127Sjchu } 152227Sjchu 15236313Skrishnae if (px_fm_enter(px_p) != DDI_SUCCESS) 15246313Skrishnae return; 152527Sjchu 152627Sjchu /* send ereport/handle/clear fire registers */ 15273274Set142600 rc_err = px_err_cmn_intr(px_p, &derr, PX_LIB_CALL, PX_FM_BLOCK_ALL); 15283274Set142600 15293274Set142600 /* Figure out if this is a cfg or mem32 access */ 15303274Set142600 addr_high = (uint32_t)(addr >> 32); 15313274Set142600 addr_low = (uint32_t)addr; 153210923SEvan.Yan@Sun.COM range_len = px_p->px_ranges_length / sizeof (pci_ranges_t); 15333274Set142600 i = 0; 15343274Set142600 for (ranges_p = px_p->px_ranges_p; i < range_len; i++, ranges_p++) { 15353274Set142600 if (ranges_p->parent_high == addr_high) { 15363274Set142600 switch (ranges_p->child_high & PCI_ADDR_MASK) { 15373274Set142600 case PCI_ADDR_CONFIG: 15383274Set142600 bdf = (pcie_req_id_t)(addr_low >> 12); 15393274Set142600 addr_low = 0; 15403274Set142600 break; 15413274Set142600 case PCI_ADDR_MEM32: 15423274Set142600 if (rdip) 15436313Skrishnae bdf = PCI_GET_BDF(rdip); 15443274Set142600 else 15459921SKrishna.Elango@Sun.COM bdf = PCIE_INVALID_BDF; 15463274Set142600 break; 15473274Set142600 } 15483274Set142600 break; 15493274Set142600 } 15503274Set142600 } 15513274Set142600 1552*11596SJason.Beloro@Sun.COM (void) px_rp_en_q(px_p, bdf, addr_low, NULL); 15533274Set142600 15543274Set142600 /* 15553274Set142600 * XXX - Current code scans the fabric for all px_tool accesses. 15563274Set142600 * In future, do not scan fabric for px_tool access to IO Root Nexus 15573274Set142600 */ 15586313Skrishnae fab_err = px_scan_fabric(px_p, rpdip, &derr); 15596313Skrishnae 15606313Skrishnae px_err_panic(rc_err, PX_RC, fab_err, B_TRUE); 15616313Skrishnae px_fm_exit(px_p); 15626313Skrishnae px_err_panic(rc_err, PX_RC, fab_err, B_FALSE); 156327Sjchu } 156427Sjchu 15650Sstevel@tonic-gate #ifdef DEBUG 15660Sstevel@tonic-gate int px_peekfault_cnt = 0; 15670Sstevel@tonic-gate int px_pokefault_cnt = 0; 15680Sstevel@tonic-gate #endif /* DEBUG */ 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate /*ARGSUSED*/ 15710Sstevel@tonic-gate static int 15720Sstevel@tonic-gate px_lib_do_poke(dev_info_t *dip, dev_info_t *rdip, 15730Sstevel@tonic-gate peekpoke_ctlops_t *in_args) 15740Sstevel@tonic-gate { 15750Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 15760Sstevel@tonic-gate px_pec_t *pec_p = px_p->px_pec_p; 15770Sstevel@tonic-gate int err = DDI_SUCCESS; 15780Sstevel@tonic-gate on_trap_data_t otd; 15790Sstevel@tonic-gate 15800Sstevel@tonic-gate mutex_enter(&pec_p->pec_pokefault_mutex); 15810Sstevel@tonic-gate pec_p->pec_ontrap_data = &otd; 158227Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_POKE; 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate /* Set up protected environment. */ 15850Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 15860Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 15870Sstevel@tonic-gate 15880Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&poke_fault; 15890Sstevel@tonic-gate err = do_poke(in_args->size, (void *)in_args->dev_addr, 15900Sstevel@tonic-gate (void *)in_args->host_addr); 15910Sstevel@tonic-gate otd.ot_trampoline = tramp; 15920Sstevel@tonic-gate } else 15930Sstevel@tonic-gate err = DDI_FAILURE; 15940Sstevel@tonic-gate 15953274Set142600 px_lib_clr_errs(px_p, rdip, in_args->dev_addr); 159627Sjchu 15970Sstevel@tonic-gate if (otd.ot_trap & OT_DATA_ACCESS) 15980Sstevel@tonic-gate err = DDI_FAILURE; 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate /* Take down protected environment. */ 16010Sstevel@tonic-gate no_trap(); 16020Sstevel@tonic-gate 16030Sstevel@tonic-gate pec_p->pec_ontrap_data = NULL; 160427Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 16050Sstevel@tonic-gate mutex_exit(&pec_p->pec_pokefault_mutex); 16060Sstevel@tonic-gate 16070Sstevel@tonic-gate #ifdef DEBUG 16080Sstevel@tonic-gate if (err == DDI_FAILURE) 16090Sstevel@tonic-gate px_pokefault_cnt++; 16100Sstevel@tonic-gate #endif 16110Sstevel@tonic-gate return (err); 16120Sstevel@tonic-gate } 16130Sstevel@tonic-gate 16140Sstevel@tonic-gate /*ARGSUSED*/ 16150Sstevel@tonic-gate static int 16160Sstevel@tonic-gate px_lib_do_caut_put(dev_info_t *dip, dev_info_t *rdip, 16170Sstevel@tonic-gate peekpoke_ctlops_t *cautacc_ctlops_arg) 16180Sstevel@tonic-gate { 16190Sstevel@tonic-gate size_t size = cautacc_ctlops_arg->size; 16200Sstevel@tonic-gate uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 16210Sstevel@tonic-gate uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 16220Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 16230Sstevel@tonic-gate size_t repcount = cautacc_ctlops_arg->repcount; 16240Sstevel@tonic-gate uint_t flags = cautacc_ctlops_arg->flags; 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 16270Sstevel@tonic-gate px_pec_t *pec_p = px_p->px_pec_p; 16280Sstevel@tonic-gate int err = DDI_SUCCESS; 16290Sstevel@tonic-gate 163027Sjchu /* 163127Sjchu * Note that i_ndi_busop_access_enter ends up grabbing the pokefault 163227Sjchu * mutex. 163327Sjchu */ 16340Sstevel@tonic-gate i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 16350Sstevel@tonic-gate 163627Sjchu pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap; 163727Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED; 163827Sjchu hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 16390Sstevel@tonic-gate 16400Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 16410Sstevel@tonic-gate for (; repcount; repcount--) { 16420Sstevel@tonic-gate switch (size) { 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate case sizeof (uint8_t): 16450Sstevel@tonic-gate i_ddi_put8(hp, (uint8_t *)dev_addr, 16460Sstevel@tonic-gate *(uint8_t *)host_addr); 16470Sstevel@tonic-gate break; 16480Sstevel@tonic-gate 16490Sstevel@tonic-gate case sizeof (uint16_t): 16500Sstevel@tonic-gate i_ddi_put16(hp, (uint16_t *)dev_addr, 16510Sstevel@tonic-gate *(uint16_t *)host_addr); 16520Sstevel@tonic-gate break; 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate case sizeof (uint32_t): 16550Sstevel@tonic-gate i_ddi_put32(hp, (uint32_t *)dev_addr, 16560Sstevel@tonic-gate *(uint32_t *)host_addr); 16570Sstevel@tonic-gate break; 16580Sstevel@tonic-gate 16590Sstevel@tonic-gate case sizeof (uint64_t): 16600Sstevel@tonic-gate i_ddi_put64(hp, (uint64_t *)dev_addr, 16610Sstevel@tonic-gate *(uint64_t *)host_addr); 16620Sstevel@tonic-gate break; 16630Sstevel@tonic-gate } 16640Sstevel@tonic-gate 16650Sstevel@tonic-gate host_addr += size; 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 16680Sstevel@tonic-gate dev_addr += size; 16690Sstevel@tonic-gate 16703274Set142600 px_lib_clr_errs(px_p, rdip, dev_addr); 167127Sjchu 16720Sstevel@tonic-gate if (pec_p->pec_ontrap_data->ot_trap & OT_DATA_ACCESS) { 16730Sstevel@tonic-gate err = DDI_FAILURE; 16740Sstevel@tonic-gate #ifdef DEBUG 16750Sstevel@tonic-gate px_pokefault_cnt++; 16760Sstevel@tonic-gate #endif 16770Sstevel@tonic-gate break; 16780Sstevel@tonic-gate } 16790Sstevel@tonic-gate } 16800Sstevel@tonic-gate } 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate i_ddi_notrap((ddi_acc_handle_t)hp); 16830Sstevel@tonic-gate pec_p->pec_ontrap_data = NULL; 168427Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 16850Sstevel@tonic-gate i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 16860Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 16870Sstevel@tonic-gate 16880Sstevel@tonic-gate return (err); 16890Sstevel@tonic-gate } 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate int 16930Sstevel@tonic-gate px_lib_ctlops_poke(dev_info_t *dip, dev_info_t *rdip, 16940Sstevel@tonic-gate peekpoke_ctlops_t *in_args) 16950Sstevel@tonic-gate { 16960Sstevel@tonic-gate return (in_args->handle ? px_lib_do_caut_put(dip, rdip, in_args) : 16970Sstevel@tonic-gate px_lib_do_poke(dip, rdip, in_args)); 16980Sstevel@tonic-gate } 16990Sstevel@tonic-gate 17000Sstevel@tonic-gate 17010Sstevel@tonic-gate /*ARGSUSED*/ 17020Sstevel@tonic-gate static int 17030Sstevel@tonic-gate px_lib_do_peek(dev_info_t *dip, peekpoke_ctlops_t *in_args) 17040Sstevel@tonic-gate { 170527Sjchu px_t *px_p = DIP_TO_STATE(dip); 170627Sjchu px_pec_t *pec_p = px_p->px_pec_p; 17070Sstevel@tonic-gate int err = DDI_SUCCESS; 17080Sstevel@tonic-gate on_trap_data_t otd; 17090Sstevel@tonic-gate 171027Sjchu mutex_enter(&pec_p->pec_pokefault_mutex); 1711*11596SJason.Beloro@Sun.COM if (px_fm_enter(px_p) != DDI_SUCCESS) { 1712*11596SJason.Beloro@Sun.COM mutex_exit(&pec_p->pec_pokefault_mutex); 17136313Skrishnae return (DDI_FAILURE); 1714*11596SJason.Beloro@Sun.COM } 171527Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK; 17166313Skrishnae px_fm_exit(px_p); 171727Sjchu 17180Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 17190Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 17200Sstevel@tonic-gate 17210Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&peek_fault; 17220Sstevel@tonic-gate err = do_peek(in_args->size, (void *)in_args->dev_addr, 17230Sstevel@tonic-gate (void *)in_args->host_addr); 17240Sstevel@tonic-gate otd.ot_trampoline = tramp; 17250Sstevel@tonic-gate } else 17260Sstevel@tonic-gate err = DDI_FAILURE; 17270Sstevel@tonic-gate 17280Sstevel@tonic-gate no_trap(); 172927Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 173027Sjchu mutex_exit(&pec_p->pec_pokefault_mutex); 17310Sstevel@tonic-gate 17320Sstevel@tonic-gate #ifdef DEBUG 17330Sstevel@tonic-gate if (err == DDI_FAILURE) 17340Sstevel@tonic-gate px_peekfault_cnt++; 17350Sstevel@tonic-gate #endif 17360Sstevel@tonic-gate return (err); 17370Sstevel@tonic-gate } 17380Sstevel@tonic-gate 17390Sstevel@tonic-gate 17400Sstevel@tonic-gate static int 17410Sstevel@tonic-gate px_lib_do_caut_get(dev_info_t *dip, peekpoke_ctlops_t *cautacc_ctlops_arg) 17420Sstevel@tonic-gate { 17430Sstevel@tonic-gate size_t size = cautacc_ctlops_arg->size; 17440Sstevel@tonic-gate uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 17450Sstevel@tonic-gate uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 17460Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 17470Sstevel@tonic-gate size_t repcount = cautacc_ctlops_arg->repcount; 17480Sstevel@tonic-gate uint_t flags = cautacc_ctlops_arg->flags; 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 17510Sstevel@tonic-gate px_pec_t *pec_p = px_p->px_pec_p; 17520Sstevel@tonic-gate int err = DDI_SUCCESS; 17530Sstevel@tonic-gate 175427Sjchu /* 175527Sjchu * Note that i_ndi_busop_access_enter ends up grabbing the pokefault 175627Sjchu * mutex. 175727Sjchu */ 175827Sjchu i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 175927Sjchu 176027Sjchu pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap; 176127Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED; 17620Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 17630Sstevel@tonic-gate 17640Sstevel@tonic-gate if (repcount == 1) { 17650Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 17660Sstevel@tonic-gate i_ddi_caut_get(size, (void *)dev_addr, 17670Sstevel@tonic-gate (void *)host_addr); 17680Sstevel@tonic-gate } else { 17690Sstevel@tonic-gate int i; 17700Sstevel@tonic-gate uint8_t *ff_addr = (uint8_t *)host_addr; 17710Sstevel@tonic-gate for (i = 0; i < size; i++) 17720Sstevel@tonic-gate *ff_addr++ = 0xff; 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate err = DDI_FAILURE; 17750Sstevel@tonic-gate #ifdef DEBUG 17760Sstevel@tonic-gate px_peekfault_cnt++; 17770Sstevel@tonic-gate #endif 17780Sstevel@tonic-gate } 17790Sstevel@tonic-gate } else { 17800Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 17810Sstevel@tonic-gate for (; repcount; repcount--) { 17820Sstevel@tonic-gate i_ddi_caut_get(size, (void *)dev_addr, 17830Sstevel@tonic-gate (void *)host_addr); 17840Sstevel@tonic-gate 17850Sstevel@tonic-gate host_addr += size; 17860Sstevel@tonic-gate 17870Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 17880Sstevel@tonic-gate dev_addr += size; 17890Sstevel@tonic-gate } 17900Sstevel@tonic-gate } else { 17910Sstevel@tonic-gate err = DDI_FAILURE; 17920Sstevel@tonic-gate #ifdef DEBUG 17930Sstevel@tonic-gate px_peekfault_cnt++; 17940Sstevel@tonic-gate #endif 17950Sstevel@tonic-gate } 17960Sstevel@tonic-gate } 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate i_ddi_notrap((ddi_acc_handle_t)hp); 17990Sstevel@tonic-gate pec_p->pec_ontrap_data = NULL; 180027Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 18010Sstevel@tonic-gate i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 18020Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 18030Sstevel@tonic-gate 18040Sstevel@tonic-gate return (err); 18050Sstevel@tonic-gate } 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate /*ARGSUSED*/ 18080Sstevel@tonic-gate int 18090Sstevel@tonic-gate px_lib_ctlops_peek(dev_info_t *dip, dev_info_t *rdip, 18100Sstevel@tonic-gate peekpoke_ctlops_t *in_args, void *result) 18110Sstevel@tonic-gate { 18120Sstevel@tonic-gate result = (void *)in_args->host_addr; 18130Sstevel@tonic-gate return (in_args->handle ? px_lib_do_caut_get(dip, in_args) : 18140Sstevel@tonic-gate px_lib_do_peek(dip, in_args)); 18150Sstevel@tonic-gate } 1816118Sjchu 18170Sstevel@tonic-gate /* 18180Sstevel@tonic-gate * implements PPM interface 18190Sstevel@tonic-gate */ 18200Sstevel@tonic-gate int 18210Sstevel@tonic-gate px_lib_pmctl(int cmd, px_t *px_p) 18220Sstevel@tonic-gate { 18230Sstevel@tonic-gate ASSERT((cmd & ~PPMREQ_MASK) == PPMREQ); 18240Sstevel@tonic-gate switch (cmd) { 18250Sstevel@tonic-gate case PPMREQ_PRE_PWR_OFF: 18260Sstevel@tonic-gate /* 18270Sstevel@tonic-gate * Currently there is no device power management for 18280Sstevel@tonic-gate * the root complex (fire). When there is we need to make 18290Sstevel@tonic-gate * sure that it is at full power before trying to send the 18300Sstevel@tonic-gate * PME_Turn_Off message. 18310Sstevel@tonic-gate */ 18320Sstevel@tonic-gate DBG(DBG_PWR, px_p->px_dip, 18330Sstevel@tonic-gate "ioctl: request to send PME_Turn_Off\n"); 18340Sstevel@tonic-gate return (px_goto_l23ready(px_p)); 18350Sstevel@tonic-gate 18360Sstevel@tonic-gate case PPMREQ_PRE_PWR_ON: 1837118Sjchu DBG(DBG_PWR, px_p->px_dip, "ioctl: PRE_PWR_ON request\n"); 1838118Sjchu return (px_pre_pwron_check(px_p)); 1839118Sjchu 18400Sstevel@tonic-gate case PPMREQ_POST_PWR_ON: 1841118Sjchu DBG(DBG_PWR, px_p->px_dip, "ioctl: POST_PWR_ON request\n"); 1842118Sjchu return (px_goto_l0(px_p)); 18430Sstevel@tonic-gate 18440Sstevel@tonic-gate default: 18450Sstevel@tonic-gate return (DDI_FAILURE); 18460Sstevel@tonic-gate } 18470Sstevel@tonic-gate } 18480Sstevel@tonic-gate 18490Sstevel@tonic-gate /* 18500Sstevel@tonic-gate * sends PME_Turn_Off message to put the link in L2/L3 ready state. 18510Sstevel@tonic-gate * called by px_ioctl. 18520Sstevel@tonic-gate * returns DDI_SUCCESS or DDI_FAILURE 18530Sstevel@tonic-gate * 1. Wait for link to be in L1 state (link status reg) 18540Sstevel@tonic-gate * 2. write to PME_Turn_off reg to boradcast 18550Sstevel@tonic-gate * 3. set timeout 18560Sstevel@tonic-gate * 4. If timeout, return failure. 18570Sstevel@tonic-gate * 5. If PM_TO_Ack, wait till link is in L2/L3 ready 18580Sstevel@tonic-gate */ 18590Sstevel@tonic-gate static int 18600Sstevel@tonic-gate px_goto_l23ready(px_t *px_p) 18610Sstevel@tonic-gate { 18620Sstevel@tonic-gate pcie_pwr_t *pwr_p; 186327Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 186427Sjchu caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 18650Sstevel@tonic-gate int ret = DDI_SUCCESS; 18660Sstevel@tonic-gate clock_t end, timeleft; 1867118Sjchu int mutex_held = 1; 18680Sstevel@tonic-gate 18690Sstevel@tonic-gate /* If no PM info, return failure */ 18700Sstevel@tonic-gate if (!PCIE_PMINFO(px_p->px_dip) || 18710Sstevel@tonic-gate !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) 18720Sstevel@tonic-gate return (DDI_FAILURE); 18730Sstevel@tonic-gate 18740Sstevel@tonic-gate mutex_enter(&pwr_p->pwr_lock); 1875118Sjchu mutex_enter(&px_p->px_l23ready_lock); 18760Sstevel@tonic-gate /* Clear the PME_To_ACK receieved flag */ 1877118Sjchu px_p->px_pm_flags &= ~PX_PMETOACK_RECVD; 1878287Smg140465 /* 1879287Smg140465 * When P25 is the downstream device, after receiving 1880287Smg140465 * PME_To_ACK, fire will go to Detect state, which causes 1881287Smg140465 * the link down event. Inform FMA that this is expected. 1882287Smg140465 * In case of all other cards complaint with the pci express 1883287Smg140465 * spec, this will happen when the power is re-applied. FMA 1884287Smg140465 * code will clear this flag after one instance of LDN. Since 1885287Smg140465 * there will not be a LDN event for the spec compliant cards, 1886287Smg140465 * we need to clear the flag after receiving PME_To_ACK. 1887287Smg140465 */ 1888287Smg140465 px_p->px_pm_flags |= PX_LDN_EXPECTED; 18890Sstevel@tonic-gate if (px_send_pme_turnoff(csr_base) != DDI_SUCCESS) { 18900Sstevel@tonic-gate ret = DDI_FAILURE; 18910Sstevel@tonic-gate goto l23ready_done; 18920Sstevel@tonic-gate } 1893118Sjchu px_p->px_pm_flags |= PX_PME_TURNOFF_PENDING; 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate end = ddi_get_lbolt() + drv_usectohz(px_pme_to_ack_timeout); 1896118Sjchu while (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { 1897118Sjchu timeleft = cv_timedwait(&px_p->px_l23ready_cv, 1898118Sjchu &px_p->px_l23ready_lock, end); 18990Sstevel@tonic-gate /* 19000Sstevel@tonic-gate * if cv_timedwait returns -1, it is either 19010Sstevel@tonic-gate * 1) timed out or 19020Sstevel@tonic-gate * 2) there was a pre-mature wakeup but by the time 19030Sstevel@tonic-gate * cv_timedwait is called again end < lbolt i.e. 19040Sstevel@tonic-gate * end is in the past. 19050Sstevel@tonic-gate * 3) By the time we make first cv_timedwait call, 19060Sstevel@tonic-gate * end < lbolt is true. 19070Sstevel@tonic-gate */ 19080Sstevel@tonic-gate if (timeleft == -1) 19090Sstevel@tonic-gate break; 19100Sstevel@tonic-gate } 1911118Sjchu if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { 19120Sstevel@tonic-gate /* 19130Sstevel@tonic-gate * Either timedout or interrupt didn't get a 19140Sstevel@tonic-gate * chance to grab the mutex and set the flag. 19150Sstevel@tonic-gate * release the mutex and delay for sometime. 19160Sstevel@tonic-gate * This will 1) give a chance for interrupt to 19170Sstevel@tonic-gate * set the flag 2) creates a delay between two 19180Sstevel@tonic-gate * consequetive requests. 19190Sstevel@tonic-gate */ 1920118Sjchu mutex_exit(&px_p->px_l23ready_lock); 19211147Sjchu delay(drv_usectohz(50 * PX_MSEC_TO_USEC)); 1922118Sjchu mutex_held = 0; 1923118Sjchu if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { 19240Sstevel@tonic-gate ret = DDI_FAILURE; 19250Sstevel@tonic-gate DBG(DBG_PWR, px_p->px_dip, " Timed out while waiting" 19260Sstevel@tonic-gate " for PME_TO_ACK\n"); 19270Sstevel@tonic-gate } 19280Sstevel@tonic-gate } 1929287Smg140465 px_p->px_pm_flags &= 1930287Smg140465 ~(PX_PME_TURNOFF_PENDING | PX_PMETOACK_RECVD | PX_LDN_EXPECTED); 19310Sstevel@tonic-gate 19320Sstevel@tonic-gate l23ready_done: 1933118Sjchu if (mutex_held) 1934118Sjchu mutex_exit(&px_p->px_l23ready_lock); 1935118Sjchu /* 1936118Sjchu * Wait till link is in L1 idle, if sending PME_Turn_Off 1937118Sjchu * was succesful. 1938118Sjchu */ 1939118Sjchu if (ret == DDI_SUCCESS) { 1940118Sjchu if (px_link_wait4l1idle(csr_base) != DDI_SUCCESS) { 1941118Sjchu DBG(DBG_PWR, px_p->px_dip, " Link is not at L1" 1942287Smg140465 " even though we received PME_To_ACK.\n"); 1943287Smg140465 /* 1944287Smg140465 * Workaround for hardware bug with P25. 1945287Smg140465 * Due to a hardware bug with P25, link state 1946287Smg140465 * will be Detect state rather than L1 after 1947287Smg140465 * link is transitioned to L23Ready state. Since 1948287Smg140465 * we don't know whether link is L23ready state 1949287Smg140465 * without Fire's state being L1_idle, we delay 1950287Smg140465 * here just to make sure that we wait till link 1951287Smg140465 * is transitioned to L23Ready state. 1952287Smg140465 */ 19531147Sjchu delay(drv_usectohz(100 * PX_MSEC_TO_USEC)); 1954287Smg140465 } 1955287Smg140465 pwr_p->pwr_link_lvl = PM_LEVEL_L3; 1956118Sjchu 1957118Sjchu } 19580Sstevel@tonic-gate mutex_exit(&pwr_p->pwr_lock); 19590Sstevel@tonic-gate return (ret); 19600Sstevel@tonic-gate } 19610Sstevel@tonic-gate 1962118Sjchu /* 1963118Sjchu * Message interrupt handler intended to be shared for both 1964118Sjchu * PME and PME_TO_ACK msg handling, currently only handles 1965118Sjchu * PME_To_ACK message. 1966118Sjchu */ 1967118Sjchu uint_t 1968118Sjchu px_pmeq_intr(caddr_t arg) 1969118Sjchu { 1970118Sjchu px_t *px_p = (px_t *)arg; 1971118Sjchu 1972287Smg140465 DBG(DBG_PWR, px_p->px_dip, " PME_To_ACK received \n"); 1973118Sjchu mutex_enter(&px_p->px_l23ready_lock); 1974118Sjchu cv_broadcast(&px_p->px_l23ready_cv); 1975118Sjchu if (px_p->px_pm_flags & PX_PME_TURNOFF_PENDING) { 1976118Sjchu px_p->px_pm_flags |= PX_PMETOACK_RECVD; 1977118Sjchu } else { 1978118Sjchu /* 1979118Sjchu * This maybe the second ack received. If so then, 1980118Sjchu * we should be receiving it during wait4L1 stage. 1981118Sjchu */ 1982118Sjchu px_p->px_pmetoack_ignored++; 1983118Sjchu } 1984118Sjchu mutex_exit(&px_p->px_l23ready_lock); 1985118Sjchu return (DDI_INTR_CLAIMED); 1986118Sjchu } 1987118Sjchu 1988118Sjchu static int 1989118Sjchu px_pre_pwron_check(px_t *px_p) 1990118Sjchu { 1991118Sjchu pcie_pwr_t *pwr_p; 1992118Sjchu 1993118Sjchu /* If no PM info, return failure */ 1994118Sjchu if (!PCIE_PMINFO(px_p->px_dip) || 1995118Sjchu !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) 1996118Sjchu return (DDI_FAILURE); 1997118Sjchu 1998287Smg140465 /* 1999287Smg140465 * For the spec compliant downstream cards link down 2000287Smg140465 * is expected when the device is powered on. 2001287Smg140465 */ 2002287Smg140465 px_p->px_pm_flags |= PX_LDN_EXPECTED; 2003118Sjchu return (pwr_p->pwr_link_lvl == PM_LEVEL_L3 ? DDI_SUCCESS : DDI_FAILURE); 2004118Sjchu } 2005118Sjchu 2006118Sjchu static int 2007118Sjchu px_goto_l0(px_t *px_p) 2008118Sjchu { 2009118Sjchu pcie_pwr_t *pwr_p; 2010118Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 2011118Sjchu caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 2012118Sjchu int ret = DDI_SUCCESS; 20131147Sjchu uint64_t time_spent = 0; 2014118Sjchu 2015118Sjchu /* If no PM info, return failure */ 2016118Sjchu if (!PCIE_PMINFO(px_p->px_dip) || 2017118Sjchu !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) 2018118Sjchu return (DDI_FAILURE); 2019118Sjchu 2020118Sjchu mutex_enter(&pwr_p->pwr_lock); 2021287Smg140465 /* 20221147Sjchu * The following link retrain activity will cause LDN and LUP event. 20231147Sjchu * Receiving LDN prior to receiving LUP is expected, not an error in 20241147Sjchu * this case. Receiving LUP indicates link is fully up to support 20251147Sjchu * powering up down stream device, and of course any further LDN and 20261147Sjchu * LUP outside this context will be error. 2027287Smg140465 */ 20281147Sjchu px_p->px_lup_pending = 1; 2029118Sjchu if (px_link_retrain(csr_base) != DDI_SUCCESS) { 2030118Sjchu ret = DDI_FAILURE; 2031118Sjchu goto l0_done; 2032118Sjchu } 2033118Sjchu 20341147Sjchu /* LUP event takes the order of 15ms amount of time to occur */ 20351147Sjchu for (; px_p->px_lup_pending && (time_spent < px_lup_poll_to); 20361147Sjchu time_spent += px_lup_poll_interval) 20371147Sjchu drv_usecwait(px_lup_poll_interval); 20381147Sjchu if (px_p->px_lup_pending) 20391147Sjchu ret = DDI_FAILURE; 2040118Sjchu l0_done: 2041287Smg140465 px_enable_detect_quiet(csr_base); 2042118Sjchu if (ret == DDI_SUCCESS) 2043287Smg140465 pwr_p->pwr_link_lvl = PM_LEVEL_L0; 2044118Sjchu mutex_exit(&pwr_p->pwr_lock); 2045118Sjchu return (ret); 2046118Sjchu } 2047118Sjchu 20480Sstevel@tonic-gate /* 20490Sstevel@tonic-gate * Extract the drivers binding name to identify which chip we're binding to. 20500Sstevel@tonic-gate * Whenever a new bus bridge is created, the driver alias entry should be 20510Sstevel@tonic-gate * added here to identify the device if needed. If a device isn't added, 20520Sstevel@tonic-gate * the identity defaults to PX_CHIP_UNIDENTIFIED. 20530Sstevel@tonic-gate */ 20540Sstevel@tonic-gate static uint32_t 20552426Sschwartz px_identity_init(px_t *px_p) 20560Sstevel@tonic-gate { 20570Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 20580Sstevel@tonic-gate char *name = ddi_binding_name(dip); 20590Sstevel@tonic-gate uint32_t revision = 0; 20600Sstevel@tonic-gate 20610Sstevel@tonic-gate revision = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 20620Sstevel@tonic-gate "module-revision#", 0); 20630Sstevel@tonic-gate 20640Sstevel@tonic-gate /* Check for Fire driver binding name */ 20652426Sschwartz if (strcmp(name, "pciex108e,80f0") == 0) { 20662426Sschwartz DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: " 20672426Sschwartz "(FIRE), module-revision %d\n", NAMEINST(dip), 20682426Sschwartz revision); 20692426Sschwartz 20702426Sschwartz return ((revision >= FIRE_MOD_REV_20) ? 20712426Sschwartz PX_CHIP_FIRE : PX_CHIP_UNIDENTIFIED); 20720Sstevel@tonic-gate } 20730Sstevel@tonic-gate 20741772Sjl139090 /* Check for Oberon driver binding name */ 20751772Sjl139090 if (strcmp(name, "pciex108e,80f8") == 0) { 20762426Sschwartz DBG(DBG_ATTACH, dip, "px_identity_init: %s%d: " 20772426Sschwartz "(OBERON), module-revision %d\n", NAMEINST(dip), 20782426Sschwartz revision); 20792426Sschwartz 20802426Sschwartz return (PX_CHIP_OBERON); 20811772Sjl139090 } 20821772Sjl139090 20830Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "%s%d: Unknown PCI Express Host bridge %s %x\n", 20840Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), name, revision); 20850Sstevel@tonic-gate 20860Sstevel@tonic-gate return (PX_CHIP_UNIDENTIFIED); 20870Sstevel@tonic-gate } 208827Sjchu 208927Sjchu int 209027Sjchu px_err_add_intr(px_fault_t *px_fault_p) 209127Sjchu { 209227Sjchu dev_info_t *dip = px_fault_p->px_fh_dip; 209327Sjchu px_t *px_p = DIP_TO_STATE(dip); 209427Sjchu 209527Sjchu VERIFY(add_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL, 20962973Sgovinda (intrfunc)px_fault_p->px_err_func, (caddr_t)px_fault_p, 20972973Sgovinda NULL, NULL) == 0); 209827Sjchu 209927Sjchu px_ib_intr_enable(px_p, intr_dist_cpuid(), px_fault_p->px_intr_ino); 210027Sjchu 210127Sjchu return (DDI_SUCCESS); 210227Sjchu } 210327Sjchu 210427Sjchu void 210527Sjchu px_err_rem_intr(px_fault_t *px_fault_p) 210627Sjchu { 210727Sjchu dev_info_t *dip = px_fault_p->px_fh_dip; 210827Sjchu px_t *px_p = DIP_TO_STATE(dip); 210927Sjchu 211027Sjchu px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino, 21116313Skrishnae IB_INTR_WAIT); 2112965Sgovinda 21132973Sgovinda VERIFY(rem_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL) == 0); 211427Sjchu } 211527Sjchu 21161648Sjchu /* 21173623Sjchu * px_cb_intr_redist() - sun4u only, CB interrupt redistribution 21183623Sjchu */ 21193623Sjchu void 21203623Sjchu px_cb_intr_redist(void *arg) 21213623Sjchu { 21223623Sjchu px_cb_t *cb_p = (px_cb_t *)arg; 21233623Sjchu px_cb_list_t *pxl; 21243623Sjchu px_t *pxp = NULL; 21253623Sjchu px_fault_t *f_p = NULL; 21263623Sjchu uint32_t new_cpuid; 21273623Sjchu intr_valid_state_t enabled = 0; 21283623Sjchu 21293623Sjchu mutex_enter(&cb_p->cb_mutex); 21303623Sjchu 21313623Sjchu pxl = cb_p->pxl; 21323623Sjchu if (!pxl) 21333623Sjchu goto cb_done; 21343623Sjchu 21353623Sjchu pxp = pxl->pxp; 21363623Sjchu f_p = &pxp->px_cb_fault; 21373623Sjchu for (; pxl && (f_p->px_fh_sysino != cb_p->sysino); ) { 21383623Sjchu pxl = pxl->next; 21393623Sjchu pxp = pxl->pxp; 21403623Sjchu f_p = &pxp->px_cb_fault; 21413623Sjchu } 21423623Sjchu if (pxl == NULL) 21433623Sjchu goto cb_done; 21443623Sjchu 21453623Sjchu new_cpuid = intr_dist_cpuid(); 21463623Sjchu if (new_cpuid == cb_p->cpuid) 21473623Sjchu goto cb_done; 21483623Sjchu 21493623Sjchu if ((px_lib_intr_getvalid(pxp->px_dip, f_p->px_fh_sysino, &enabled) 21503623Sjchu != DDI_SUCCESS) || !enabled) { 21513623Sjchu DBG(DBG_IB, pxp->px_dip, "px_cb_intr_redist: CB not enabled, " 21523623Sjchu "sysino(0x%x)\n", f_p->px_fh_sysino); 21533623Sjchu goto cb_done; 21543623Sjchu } 21553623Sjchu 21563623Sjchu PX_INTR_DISABLE(pxp->px_dip, f_p->px_fh_sysino); 21573623Sjchu 21583623Sjchu cb_p->cpuid = new_cpuid; 21593623Sjchu cb_p->sysino = f_p->px_fh_sysino; 21603623Sjchu PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid); 21613623Sjchu 21623623Sjchu cb_done: 21633623Sjchu mutex_exit(&cb_p->cb_mutex); 21643623Sjchu } 21653623Sjchu 21663623Sjchu /* 21671648Sjchu * px_cb_add_intr() - Called from attach(9E) to create CB if not yet 21681648Sjchu * created, to add CB interrupt vector always, but enable only once. 21691648Sjchu */ 21701648Sjchu int 21711648Sjchu px_cb_add_intr(px_fault_t *fault_p) 21721648Sjchu { 21731648Sjchu px_t *px_p = DIP_TO_STATE(fault_p->px_fh_dip); 21741648Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 21751772Sjl139090 px_cb_t *cb_p = (px_cb_t *)px_get_cb(fault_p->px_fh_dip); 21761648Sjchu px_cb_list_t *pxl, *pxl_new; 21773623Sjchu boolean_t is_proxy = B_FALSE; 21783623Sjchu 21793623Sjchu /* create cb */ 21801648Sjchu if (cb_p == NULL) { 21811648Sjchu cb_p = kmem_zalloc(sizeof (px_cb_t), KM_SLEEP); 21823623Sjchu 21833623Sjchu mutex_init(&cb_p->cb_mutex, NULL, MUTEX_DRIVER, 21843623Sjchu (void *) ipltospl(FM_ERR_PIL)); 21853623Sjchu 21861648Sjchu cb_p->px_cb_func = px_cb_intr; 21871648Sjchu pxu_p->px_cb_p = cb_p; 21881772Sjl139090 px_set_cb(fault_p->px_fh_dip, (uint64_t)cb_p); 21892509Sschwartz 21902509Sschwartz /* px_lib_dev_init allows only FIRE and OBERON */ 21912509Sschwartz px_err_reg_enable( 21922509Sschwartz (pxu_p->chip_type == PX_CHIP_FIRE) ? 21936313Skrishnae PX_ERR_JBC : PX_ERR_UBC, 21942509Sschwartz pxu_p->px_address[PX_REG_XBC]); 21951648Sjchu } else 21961648Sjchu pxu_p->px_cb_p = cb_p; 21971648Sjchu 21983623Sjchu /* register cb interrupt */ 21991648Sjchu VERIFY(add_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL, 22002973Sgovinda (intrfunc)cb_p->px_cb_func, (caddr_t)cb_p, NULL, NULL) == 0); 22011648Sjchu 22023623Sjchu 22033623Sjchu /* update cb list */ 22043623Sjchu mutex_enter(&cb_p->cb_mutex); 22051648Sjchu if (cb_p->pxl == NULL) { 22063623Sjchu is_proxy = B_TRUE; 22071648Sjchu pxl = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP); 22081648Sjchu pxl->pxp = px_p; 22091648Sjchu cb_p->pxl = pxl; 22101648Sjchu cb_p->sysino = fault_p->px_fh_sysino; 22113623Sjchu cb_p->cpuid = intr_dist_cpuid(); 22121648Sjchu } else { 22131648Sjchu /* 22141648Sjchu * Find the last pxl or 22153623Sjchu * stop short at encountering a redundent entry, or 22161648Sjchu * both. 22171648Sjchu */ 22181648Sjchu pxl = cb_p->pxl; 22196313Skrishnae for (; !(pxl->pxp == px_p) && pxl->next; pxl = pxl->next) {}; 22203623Sjchu ASSERT(pxl->pxp != px_p); 22211648Sjchu 22221648Sjchu /* add to linked list */ 22231648Sjchu pxl_new = kmem_zalloc(sizeof (px_cb_list_t), KM_SLEEP); 22241648Sjchu pxl_new->pxp = px_p; 22251648Sjchu pxl->next = pxl_new; 22261648Sjchu } 22271648Sjchu cb_p->attachcnt++; 22281648Sjchu mutex_exit(&cb_p->cb_mutex); 22291648Sjchu 22303623Sjchu if (is_proxy) { 22313623Sjchu /* add to interrupt redistribution list */ 22323623Sjchu intr_dist_add(px_cb_intr_redist, cb_p); 22333623Sjchu 22343623Sjchu /* enable cb hw interrupt */ 22353623Sjchu px_ib_intr_enable(px_p, cb_p->cpuid, fault_p->px_intr_ino); 22363623Sjchu } 22373623Sjchu 22381648Sjchu return (DDI_SUCCESS); 22391648Sjchu } 22401648Sjchu 22411648Sjchu /* 22421648Sjchu * px_cb_rem_intr() - Called from detach(9E) to remove its CB 22431648Sjchu * interrupt vector, to shift proxy to the next available px, 22441648Sjchu * or disable CB interrupt when itself is the last. 22451648Sjchu */ 22461648Sjchu void 22471648Sjchu px_cb_rem_intr(px_fault_t *fault_p) 22481648Sjchu { 22491648Sjchu px_t *px_p = DIP_TO_STATE(fault_p->px_fh_dip), *pxp; 22501648Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 22511648Sjchu px_cb_t *cb_p = PX2CB(px_p); 22521648Sjchu px_cb_list_t *pxl, *prev; 22531648Sjchu px_fault_t *f_p; 22541648Sjchu 22551648Sjchu ASSERT(cb_p->pxl); 22561648Sjchu 22573623Sjchu /* find and remove this px, and update cb list */ 22581648Sjchu mutex_enter(&cb_p->cb_mutex); 22591648Sjchu 22601648Sjchu pxl = cb_p->pxl; 22611648Sjchu if (pxl->pxp == px_p) { 22621648Sjchu cb_p->pxl = pxl->next; 22631648Sjchu } else { 22641648Sjchu prev = pxl; 22651648Sjchu pxl = pxl->next; 22666313Skrishnae for (; pxl && (pxl->pxp != px_p); prev = pxl, pxl = pxl->next) { 22676313Skrishnae }; 22681648Sjchu if (!pxl) { 22691648Sjchu cmn_err(CE_WARN, "px_cb_rem_intr: can't find px_p 0x%p " 22701650Sjchu "in registered CB list.", (void *)px_p); 22713623Sjchu mutex_exit(&cb_p->cb_mutex); 22721648Sjchu return; 22731648Sjchu } 22741648Sjchu prev->next = pxl->next; 22751648Sjchu } 22763623Sjchu pxu_p->px_cb_p = NULL; 22773623Sjchu cb_p->attachcnt--; 22781648Sjchu kmem_free(pxl, sizeof (px_cb_list_t)); 22793623Sjchu mutex_exit(&cb_p->cb_mutex); 22803623Sjchu 22813623Sjchu /* disable cb hw interrupt */ 22823623Sjchu if (fault_p->px_fh_sysino == cb_p->sysino) 22831648Sjchu px_ib_intr_disable(px_p->px_ib_p, fault_p->px_intr_ino, 22841648Sjchu IB_INTR_WAIT); 22851648Sjchu 22863623Sjchu /* if last px, remove from interrupt redistribution list */ 22873623Sjchu if (cb_p->pxl == NULL) 22883623Sjchu intr_dist_rem(px_cb_intr_redist, cb_p); 22893623Sjchu 22903623Sjchu /* de-register interrupt */ 22913623Sjchu VERIFY(rem_ivintr(fault_p->px_fh_sysino, PX_ERR_PIL) == 0); 22923623Sjchu 22933623Sjchu /* if not last px, assign next px to manage cb */ 22943623Sjchu mutex_enter(&cb_p->cb_mutex); 22953623Sjchu if (cb_p->pxl) { 22963623Sjchu if (fault_p->px_fh_sysino == cb_p->sysino) { 22971648Sjchu pxp = cb_p->pxl->pxp; 22981648Sjchu f_p = &pxp->px_cb_fault; 22991648Sjchu cb_p->sysino = f_p->px_fh_sysino; 23001648Sjchu 23011648Sjchu PX_INTR_ENABLE(pxp->px_dip, cb_p->sysino, cb_p->cpuid); 23021650Sjchu (void) px_lib_intr_setstate(pxp->px_dip, cb_p->sysino, 23031648Sjchu INTR_IDLE_STATE); 23041648Sjchu } 23051648Sjchu mutex_exit(&cb_p->cb_mutex); 23061648Sjchu return; 23071648Sjchu } 23083623Sjchu 23093623Sjchu /* clean up after the last px */ 23101648Sjchu mutex_exit(&cb_p->cb_mutex); 23111648Sjchu 23122509Sschwartz /* px_lib_dev_init allows only FIRE and OBERON */ 23132509Sschwartz px_err_reg_disable( 23142509Sschwartz (pxu_p->chip_type == PX_CHIP_FIRE) ? PX_ERR_JBC : PX_ERR_UBC, 23152509Sschwartz pxu_p->px_address[PX_REG_XBC]); 23162509Sschwartz 23171648Sjchu mutex_destroy(&cb_p->cb_mutex); 23181772Sjl139090 px_set_cb(fault_p->px_fh_dip, 0ull); 23191648Sjchu kmem_free(cb_p, sizeof (px_cb_t)); 23201648Sjchu } 23211648Sjchu 23221648Sjchu /* 23231648Sjchu * px_cb_intr() - sun4u only, CB interrupt dispatcher 23241648Sjchu */ 23251648Sjchu uint_t 23261648Sjchu px_cb_intr(caddr_t arg) 23271648Sjchu { 23281648Sjchu px_cb_t *cb_p = (px_cb_t *)arg; 23293623Sjchu px_t *pxp; 23303623Sjchu px_fault_t *f_p; 23313623Sjchu int ret; 23323354Sjl139090 23331648Sjchu mutex_enter(&cb_p->cb_mutex); 23341648Sjchu 23353623Sjchu if (!cb_p->pxl) { 23361648Sjchu mutex_exit(&cb_p->cb_mutex); 23373623Sjchu return (DDI_INTR_UNCLAIMED); 23381648Sjchu } 23391648Sjchu 23403623Sjchu pxp = cb_p->pxl->pxp; 23413623Sjchu f_p = &pxp->px_cb_fault; 23423623Sjchu 23433623Sjchu ret = f_p->px_err_func((caddr_t)f_p); 23441648Sjchu 23451648Sjchu mutex_exit(&cb_p->cb_mutex); 23463623Sjchu return (ret); 23471648Sjchu } 23481648Sjchu 23493623Sjchu #ifdef FMA 235027Sjchu void 235127Sjchu px_fill_rc_status(px_fault_t *px_fault_p, pciex_rc_error_regs_t *rc_status) 235227Sjchu { 235327Sjchu /* populate the rc_status by reading the registers - TBD */ 235427Sjchu } 235527Sjchu #endif /* FMA */ 2356383Set142600 2357383Set142600 /* 2358435Sjchu * cpr callback 2359435Sjchu * 2360435Sjchu * disable fabric error msg interrupt prior to suspending 2361435Sjchu * all device drivers; re-enable fabric error msg interrupt 2362435Sjchu * after all devices are resumed. 2363435Sjchu */ 2364435Sjchu static boolean_t 2365435Sjchu px_cpr_callb(void *arg, int code) 2366435Sjchu { 2367435Sjchu px_t *px_p = (px_t *)arg; 2368435Sjchu px_ib_t *ib_p = px_p->px_ib_p; 2369435Sjchu px_pec_t *pec_p = px_p->px_pec_p; 2370435Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 2371435Sjchu caddr_t csr_base; 2372435Sjchu devino_t ce_ino, nf_ino, f_ino; 23732973Sgovinda px_ino_t *ce_ino_p, *nf_ino_p, *f_ino_p; 2374435Sjchu uint64_t imu_log_enable, imu_intr_enable; 2375435Sjchu uint64_t imu_log_mask, imu_intr_mask; 2376435Sjchu 2377435Sjchu ce_ino = px_msiqid_to_devino(px_p, pec_p->pec_corr_msg_msiq_id); 2378435Sjchu nf_ino = px_msiqid_to_devino(px_p, pec_p->pec_non_fatal_msg_msiq_id); 2379435Sjchu f_ino = px_msiqid_to_devino(px_p, pec_p->pec_fatal_msg_msiq_id); 2380435Sjchu csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 2381435Sjchu 2382435Sjchu imu_log_enable = CSR_XR(csr_base, IMU_ERROR_LOG_ENABLE); 2383435Sjchu imu_intr_enable = CSR_XR(csr_base, IMU_INTERRUPT_ENABLE); 2384435Sjchu 2385435Sjchu imu_log_mask = BITMASK(IMU_ERROR_LOG_ENABLE_FATAL_MES_NOT_EN_LOG_EN) | 2386435Sjchu BITMASK(IMU_ERROR_LOG_ENABLE_NONFATAL_MES_NOT_EN_LOG_EN) | 2387435Sjchu BITMASK(IMU_ERROR_LOG_ENABLE_COR_MES_NOT_EN_LOG_EN); 2388435Sjchu 2389435Sjchu imu_intr_mask = 2390435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_S_INT_EN) | 2391435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_S_INT_EN) | 2392435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_S_INT_EN) | 2393435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_P_INT_EN) | 2394435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_P_INT_EN) | 2395435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_P_INT_EN); 2396435Sjchu 2397435Sjchu switch (code) { 2398435Sjchu case CB_CODE_CPR_CHKPT: 2399435Sjchu /* disable imu rbne on corr/nonfatal/fatal errors */ 2400435Sjchu CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE, 2401435Sjchu imu_log_enable & (~imu_log_mask)); 2402435Sjchu 2403435Sjchu CSR_XS(csr_base, IMU_INTERRUPT_ENABLE, 2404435Sjchu imu_intr_enable & (~imu_intr_mask)); 2405435Sjchu 2406435Sjchu /* disable CORR intr mapping */ 2407435Sjchu px_ib_intr_disable(ib_p, ce_ino, IB_INTR_NOWAIT); 2408435Sjchu 2409435Sjchu /* disable NON FATAL intr mapping */ 2410435Sjchu px_ib_intr_disable(ib_p, nf_ino, IB_INTR_NOWAIT); 2411435Sjchu 2412435Sjchu /* disable FATAL intr mapping */ 2413435Sjchu px_ib_intr_disable(ib_p, f_ino, IB_INTR_NOWAIT); 2414435Sjchu 2415435Sjchu break; 2416435Sjchu 2417435Sjchu case CB_CODE_CPR_RESUME: 24183274Set142600 pxu_p->cpr_flag = PX_NOT_CPR; 2419435Sjchu mutex_enter(&ib_p->ib_ino_lst_mutex); 2420435Sjchu 2421435Sjchu ce_ino_p = px_ib_locate_ino(ib_p, ce_ino); 2422435Sjchu nf_ino_p = px_ib_locate_ino(ib_p, nf_ino); 2423435Sjchu f_ino_p = px_ib_locate_ino(ib_p, f_ino); 2424435Sjchu 2425435Sjchu /* enable CORR intr mapping */ 2426435Sjchu if (ce_ino_p) 2427435Sjchu px_ib_intr_enable(px_p, ce_ino_p->ino_cpuid, ce_ino); 2428435Sjchu else 2429435Sjchu cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to " 2430435Sjchu "reenable PCIe Correctable msg intr.\n"); 2431435Sjchu 2432435Sjchu /* enable NON FATAL intr mapping */ 2433435Sjchu if (nf_ino_p) 2434435Sjchu px_ib_intr_enable(px_p, nf_ino_p->ino_cpuid, nf_ino); 2435435Sjchu else 2436435Sjchu cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to " 2437435Sjchu "reenable PCIe Non Fatal msg intr.\n"); 2438435Sjchu 2439435Sjchu /* enable FATAL intr mapping */ 2440435Sjchu if (f_ino_p) 2441435Sjchu px_ib_intr_enable(px_p, f_ino_p->ino_cpuid, f_ino); 2442435Sjchu else 2443435Sjchu cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to " 2444435Sjchu "reenable PCIe Fatal msg intr.\n"); 2445435Sjchu 2446435Sjchu mutex_exit(&ib_p->ib_ino_lst_mutex); 2447435Sjchu 2448435Sjchu /* enable corr/nonfatal/fatal not enable error */ 2449435Sjchu CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE, (imu_log_enable | 2450435Sjchu (imu_log_mask & px_imu_log_mask))); 2451435Sjchu CSR_XS(csr_base, IMU_INTERRUPT_ENABLE, (imu_intr_enable | 2452435Sjchu (imu_intr_mask & px_imu_intr_mask))); 2453435Sjchu 2454435Sjchu break; 2455435Sjchu } 2456435Sjchu 2457435Sjchu return (B_TRUE); 2458435Sjchu } 2459435Sjchu 24602053Sschwartz uint64_t 24612053Sschwartz px_get_rng_parent_hi_mask(px_t *px_p) 24622053Sschwartz { 24632053Sschwartz pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 24642053Sschwartz uint64_t mask; 24652053Sschwartz 24662053Sschwartz switch (PX_CHIP_TYPE(pxu_p)) { 24672053Sschwartz case PX_CHIP_OBERON: 24682053Sschwartz mask = OBERON_RANGE_PROP_MASK; 24692053Sschwartz break; 24702053Sschwartz case PX_CHIP_FIRE: 24712053Sschwartz mask = PX_RANGE_PROP_MASK; 24722053Sschwartz break; 24732053Sschwartz default: 24742053Sschwartz mask = PX_RANGE_PROP_MASK; 24752053Sschwartz } 24762053Sschwartz 24772053Sschwartz return (mask); 24782053Sschwartz } 24792053Sschwartz 2480435Sjchu /* 24811772Sjl139090 * fetch chip's range propery's value 24821772Sjl139090 */ 24831772Sjl139090 uint64_t 248410923SEvan.Yan@Sun.COM px_get_range_prop(px_t *px_p, pci_ranges_t *rp, int bank) 24851772Sjl139090 { 24861772Sjl139090 uint64_t mask, range_prop; 24871772Sjl139090 24882053Sschwartz mask = px_get_rng_parent_hi_mask(px_p); 24891772Sjl139090 range_prop = (((uint64_t)(rp[bank].parent_high & mask)) << 32) | 24906313Skrishnae rp[bank].parent_low; 24911772Sjl139090 24921772Sjl139090 return (range_prop); 24931772Sjl139090 } 24941772Sjl139090 24951772Sjl139090 /* 249611245SZhijun.Fu@Sun.COM * fetch the config space base addr of the root complex 249711245SZhijun.Fu@Sun.COM * note this depends on px structure being initialized 249811245SZhijun.Fu@Sun.COM */ 249911245SZhijun.Fu@Sun.COM uint64_t 250011245SZhijun.Fu@Sun.COM px_lib_get_cfgacc_base(dev_info_t *dip) 250111245SZhijun.Fu@Sun.COM { 250211245SZhijun.Fu@Sun.COM int instance = DIP_TO_INST(dip); 250311245SZhijun.Fu@Sun.COM px_t *px_p = INST_TO_STATE(instance); 250411245SZhijun.Fu@Sun.COM pci_ranges_t *rp = px_p->px_ranges_p; 250511245SZhijun.Fu@Sun.COM int bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG); 250611245SZhijun.Fu@Sun.COM 250711245SZhijun.Fu@Sun.COM /* Get Fire's Physical Base Address */ 250811245SZhijun.Fu@Sun.COM return (px_get_range_prop(px_p, rp, bank)); 250911245SZhijun.Fu@Sun.COM } 251011245SZhijun.Fu@Sun.COM 251111245SZhijun.Fu@Sun.COM /* 2512435Sjchu * add cpr callback 2513435Sjchu */ 2514435Sjchu void 2515435Sjchu px_cpr_add_callb(px_t *px_p) 2516435Sjchu { 2517435Sjchu px_p->px_cprcb_id = callb_add(px_cpr_callb, (void *)px_p, 25186313Skrishnae CB_CL_CPR_POST_USER, "px_cpr"); 2519435Sjchu } 2520435Sjchu 2521435Sjchu /* 2522435Sjchu * remove cpr callback 2523435Sjchu */ 2524435Sjchu void 2525435Sjchu px_cpr_rem_callb(px_t *px_p) 2526435Sjchu { 2527435Sjchu (void) callb_delete(px_p->px_cprcb_id); 2528435Sjchu } 25291531Skini 25301531Skini /*ARGSUSED*/ 25311772Sjl139090 static uint_t 25321772Sjl139090 px_hp_intr(caddr_t arg1, caddr_t arg2) 25331772Sjl139090 { 253410923SEvan.Yan@Sun.COM px_t *px_p = (px_t *)arg1; 253510923SEvan.Yan@Sun.COM pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 253610923SEvan.Yan@Sun.COM int rval; 253710923SEvan.Yan@Sun.COM 253810923SEvan.Yan@Sun.COM rval = pcie_intr(px_p->px_dip); 25391772Sjl139090 25401772Sjl139090 #ifdef DEBUG 25411772Sjl139090 if (rval == DDI_INTR_UNCLAIMED) 25426313Skrishnae cmn_err(CE_WARN, "%s%d: UNCLAIMED intr\n", 25436313Skrishnae ddi_driver_name(px_p->px_dip), 25446313Skrishnae ddi_get_instance(px_p->px_dip)); 25451772Sjl139090 #endif 25461772Sjl139090 25474701Sgovinda /* Set the interrupt state to idle */ 25484701Sgovinda if (px_lib_intr_setstate(px_p->px_dip, 25494701Sgovinda pxu_p->hp_sysino, INTR_IDLE_STATE) != DDI_SUCCESS) 25504701Sgovinda return (DDI_INTR_UNCLAIMED); 25514701Sgovinda 25521772Sjl139090 return (rval); 25531772Sjl139090 } 25541772Sjl139090 25551531Skini int 25561531Skini px_lib_hotplug_init(dev_info_t *dip, void *arg) 25571531Skini { 25581772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 25594701Sgovinda pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 25601772Sjl139090 uint64_t ret; 25611772Sjl139090 256210923SEvan.Yan@Sun.COM if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 256310923SEvan.Yan@Sun.COM "hotplug-capable") == 0) 256410923SEvan.Yan@Sun.COM return (DDI_FAILURE); 256510923SEvan.Yan@Sun.COM 25661772Sjl139090 if ((ret = hvio_hotplug_init(dip, arg)) == DDI_SUCCESS) { 25671772Sjl139090 if (px_lib_intr_devino_to_sysino(px_p->px_dip, 25684701Sgovinda px_p->px_inos[PX_INTR_HOTPLUG], &pxu_p->hp_sysino) != 25691772Sjl139090 DDI_SUCCESS) { 25701772Sjl139090 #ifdef DEBUG 25711772Sjl139090 cmn_err(CE_WARN, "%s%d: devino_to_sysino fails\n", 25721772Sjl139090 ddi_driver_name(px_p->px_dip), 25731772Sjl139090 ddi_get_instance(px_p->px_dip)); 25741772Sjl139090 #endif 25751772Sjl139090 return (DDI_FAILURE); 25761772Sjl139090 } 25771772Sjl139090 257810923SEvan.Yan@Sun.COM VERIFY(add_ivintr(pxu_p->hp_sysino, PCIE_INTR_PRI, 25792973Sgovinda (intrfunc)px_hp_intr, (caddr_t)px_p, NULL, NULL) == 0); 25803953Sscarter 25813953Sscarter px_ib_intr_enable(px_p, intr_dist_cpuid(), 25823953Sscarter px_p->px_inos[PX_INTR_HOTPLUG]); 25831772Sjl139090 } 25841772Sjl139090 25851772Sjl139090 return (ret); 25861531Skini } 25871531Skini 25881531Skini void 25891531Skini px_lib_hotplug_uninit(dev_info_t *dip) 25901531Skini { 25911772Sjl139090 if (hvio_hotplug_uninit(dip) == DDI_SUCCESS) { 25921772Sjl139090 px_t *px_p = DIP_TO_STATE(dip); 25934701Sgovinda pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 25941772Sjl139090 25953953Sscarter px_ib_intr_disable(px_p->px_ib_p, 25963953Sscarter px_p->px_inos[PX_INTR_HOTPLUG], IB_INTR_WAIT); 25973953Sscarter 259810923SEvan.Yan@Sun.COM VERIFY(rem_ivintr(pxu_p->hp_sysino, PCIE_INTR_PRI) == 0); 25991772Sjl139090 } 26001531Skini } 26012476Sdwoods 26023953Sscarter /* 26033953Sscarter * px_hp_intr_redist() - sun4u only, HP interrupt redistribution 26043953Sscarter */ 26053953Sscarter void 26063953Sscarter px_hp_intr_redist(px_t *px_p) 26073953Sscarter { 260810923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(px_p->px_dip); 260910923SEvan.Yan@Sun.COM 261010923SEvan.Yan@Sun.COM if (px_p && PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) { 26113953Sscarter px_ib_intr_dist_en(px_p->px_dip, intr_dist_cpuid(), 26123953Sscarter px_p->px_inos[PX_INTR_HOTPLUG], B_FALSE); 26133953Sscarter } 26143953Sscarter } 26153953Sscarter 26162476Sdwoods boolean_t 26172476Sdwoods px_lib_is_in_drain_state(px_t *px_p) 26182476Sdwoods { 26192476Sdwoods pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 26202476Sdwoods caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 26212476Sdwoods uint64_t drain_status; 26222476Sdwoods 26232476Sdwoods if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) { 26242476Sdwoods drain_status = CSR_BR(csr_base, DRAIN_CONTROL_STATUS, DRAIN); 26252476Sdwoods } else { 26262476Sdwoods drain_status = CSR_BR(csr_base, TLU_STATUS, DRAIN); 26272476Sdwoods } 26282476Sdwoods 26292476Sdwoods return (drain_status); 26302476Sdwoods } 26313613Set142600 26323613Set142600 pcie_req_id_t 26333613Set142600 px_lib_get_bdf(px_t *px_p) 26343613Set142600 { 26353613Set142600 pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 26363613Set142600 caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 26373613Set142600 pcie_req_id_t bdf; 26383613Set142600 26393613Set142600 bdf = CSR_BR(csr_base, DMC_PCI_EXPRESS_CONFIGURATION, REQ_ID); 26403613Set142600 26413613Set142600 return (bdf); 26423613Set142600 } 26437596SAlan.Adamson@Sun.COM 26447596SAlan.Adamson@Sun.COM /*ARGSUSED*/ 26457596SAlan.Adamson@Sun.COM int 26467596SAlan.Adamson@Sun.COM px_lib_get_root_complex_mps(px_t *px_p, dev_info_t *dip, int *mps) 26477596SAlan.Adamson@Sun.COM { 26487596SAlan.Adamson@Sun.COM pxu_t *pxu_p; 26497596SAlan.Adamson@Sun.COM caddr_t csr_base; 26507596SAlan.Adamson@Sun.COM 26517596SAlan.Adamson@Sun.COM pxu_p = (pxu_t *)px_p->px_plat_p; 26527596SAlan.Adamson@Sun.COM 26537596SAlan.Adamson@Sun.COM if (pxu_p == NULL) 26547596SAlan.Adamson@Sun.COM return (DDI_FAILURE); 26557596SAlan.Adamson@Sun.COM 26567596SAlan.Adamson@Sun.COM csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 26577596SAlan.Adamson@Sun.COM 26587596SAlan.Adamson@Sun.COM 26597596SAlan.Adamson@Sun.COM *mps = CSR_XR(csr_base, TLU_DEVICE_CAPABILITIES) & 26607596SAlan.Adamson@Sun.COM TLU_DEVICE_CAPABILITIES_MPS_MASK; 26617596SAlan.Adamson@Sun.COM 26627596SAlan.Adamson@Sun.COM return (DDI_SUCCESS); 26637596SAlan.Adamson@Sun.COM } 26647596SAlan.Adamson@Sun.COM 26657596SAlan.Adamson@Sun.COM /*ARGSUSED*/ 26667596SAlan.Adamson@Sun.COM int 26677596SAlan.Adamson@Sun.COM px_lib_set_root_complex_mps(px_t *px_p, dev_info_t *dip, int mps) 26687596SAlan.Adamson@Sun.COM { 26697596SAlan.Adamson@Sun.COM pxu_t *pxu_p; 26707596SAlan.Adamson@Sun.COM caddr_t csr_base; 26717596SAlan.Adamson@Sun.COM uint64_t dev_ctrl; 26727596SAlan.Adamson@Sun.COM int link_width, val; 26737596SAlan.Adamson@Sun.COM px_chip_type_t chip_type = px_identity_init(px_p); 26747596SAlan.Adamson@Sun.COM 26757596SAlan.Adamson@Sun.COM pxu_p = (pxu_t *)px_p->px_plat_p; 26767596SAlan.Adamson@Sun.COM 26777596SAlan.Adamson@Sun.COM if (pxu_p == NULL) 26787596SAlan.Adamson@Sun.COM return (DDI_FAILURE); 26797596SAlan.Adamson@Sun.COM 26807596SAlan.Adamson@Sun.COM csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 26817596SAlan.Adamson@Sun.COM 26827596SAlan.Adamson@Sun.COM dev_ctrl = CSR_XR(csr_base, TLU_DEVICE_CONTROL); 26837596SAlan.Adamson@Sun.COM dev_ctrl |= (mps << TLU_DEVICE_CONTROL_MPS); 26847596SAlan.Adamson@Sun.COM 26857596SAlan.Adamson@Sun.COM CSR_XS(csr_base, TLU_DEVICE_CONTROL, dev_ctrl); 26867596SAlan.Adamson@Sun.COM 26877596SAlan.Adamson@Sun.COM link_width = CSR_FR(csr_base, TLU_LINK_STATUS, WIDTH); 26887596SAlan.Adamson@Sun.COM 26897596SAlan.Adamson@Sun.COM /* 26907596SAlan.Adamson@Sun.COM * Convert link_width to match timer array configuration. 26917596SAlan.Adamson@Sun.COM */ 26927596SAlan.Adamson@Sun.COM switch (link_width) { 26937596SAlan.Adamson@Sun.COM case 1: 26947596SAlan.Adamson@Sun.COM link_width = 0; 26957596SAlan.Adamson@Sun.COM break; 26967596SAlan.Adamson@Sun.COM case 4: 26977596SAlan.Adamson@Sun.COM link_width = 1; 26987596SAlan.Adamson@Sun.COM break; 26997596SAlan.Adamson@Sun.COM case 8: 27007596SAlan.Adamson@Sun.COM link_width = 2; 27017596SAlan.Adamson@Sun.COM break; 27027596SAlan.Adamson@Sun.COM case 16: 27037596SAlan.Adamson@Sun.COM link_width = 3; 27047596SAlan.Adamson@Sun.COM break; 27057596SAlan.Adamson@Sun.COM default: 27067596SAlan.Adamson@Sun.COM link_width = 0; 27077596SAlan.Adamson@Sun.COM } 27087596SAlan.Adamson@Sun.COM 27097596SAlan.Adamson@Sun.COM val = px_replay_timer_table[mps][link_width]; 27107596SAlan.Adamson@Sun.COM CSR_XS(csr_base, LPU_TXLINK_REPLAY_TIMER_THRESHOLD, val); 27117596SAlan.Adamson@Sun.COM 27127596SAlan.Adamson@Sun.COM if (chip_type == PX_CHIP_OBERON) 27137596SAlan.Adamson@Sun.COM return (DDI_SUCCESS); 27147596SAlan.Adamson@Sun.COM 27157596SAlan.Adamson@Sun.COM val = px_acknak_timer_table[mps][link_width]; 27167596SAlan.Adamson@Sun.COM CSR_XS(csr_base, LPU_TXLINK_FREQUENT_NAK_LATENCY_TIMER_THRESHOLD, val); 27177596SAlan.Adamson@Sun.COM 27187596SAlan.Adamson@Sun.COM return (DDI_SUCCESS); 27197596SAlan.Adamson@Sun.COM } 2720*11596SJason.Beloro@Sun.COM 2721*11596SJason.Beloro@Sun.COM /*ARGSUSED*/ 2722*11596SJason.Beloro@Sun.COM int 2723*11596SJason.Beloro@Sun.COM px_lib_fabric_sync(dev_info_t *dip) 2724*11596SJason.Beloro@Sun.COM { 2725*11596SJason.Beloro@Sun.COM /* an no-op on sun4u platform */ 2726*11596SJason.Beloro@Sun.COM return (DDI_SUCCESS); 2727*11596SJason.Beloro@Sun.COM } 2728