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 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/kmem.h> 310Sstevel@tonic-gate #include <sys/conf.h> 320Sstevel@tonic-gate #include <sys/ddi.h> 330Sstevel@tonic-gate #include <sys/sunddi.h> 3427Sjchu #include <sys/fm/protocol.h> 3527Sjchu #include <sys/fm/util.h> 360Sstevel@tonic-gate #include <sys/modctl.h> 370Sstevel@tonic-gate #include <sys/disp.h> 380Sstevel@tonic-gate #include <sys/stat.h> 390Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 400Sstevel@tonic-gate #include <sys/vmem.h> 410Sstevel@tonic-gate #include <sys/iommutsb.h> 420Sstevel@tonic-gate #include <sys/cpuvar.h> 4327Sjchu #include <sys/ivintr.h> 44383Set142600 #include <sys/byteorder.h> 450Sstevel@tonic-gate #include <px_obj.h> 460Sstevel@tonic-gate #include <pcie_pwr.h> 470Sstevel@tonic-gate #include "px_tools_var.h" 480Sstevel@tonic-gate #include <px_regs.h> 490Sstevel@tonic-gate #include <px_csr.h> 5027Sjchu #include <sys/machsystm.h> 510Sstevel@tonic-gate #include "px_lib4u.h" 5227Sjchu #include "px_err.h" 530Sstevel@tonic-gate 540Sstevel@tonic-gate #pragma weak jbus_stst_order 550Sstevel@tonic-gate 560Sstevel@tonic-gate extern void jbus_stst_order(); 570Sstevel@tonic-gate 580Sstevel@tonic-gate ulong_t px_mmu_dvma_end = 0xfffffffful; 590Sstevel@tonic-gate uint_t px_ranges_phi_mask = 0xfffffffful; 600Sstevel@tonic-gate 610Sstevel@tonic-gate static int px_goto_l23ready(px_t *px_p); 62118Sjchu static int px_goto_l0(px_t *px_p); 63118Sjchu static int px_pre_pwron_check(px_t *px_p); 640Sstevel@tonic-gate static uint32_t px_identity_chip(px_t *px_p); 6527Sjchu static void px_lib_clr_errs(px_t *px_p, px_pec_t *pec_p); 66*435Sjchu static boolean_t px_cpr_callb(void *arg, int code); 6727Sjchu 6827Sjchu /* 6927Sjchu * px_lib_map_registers 7027Sjchu * 7127Sjchu * This function is called from the attach routine to map the registers 7227Sjchu * accessed by this driver. 7327Sjchu * 7427Sjchu * used by: px_attach() 7527Sjchu * 7627Sjchu * return value: DDI_FAILURE on failure 7727Sjchu */ 7827Sjchu int 7927Sjchu px_lib_map_regs(pxu_t *pxu_p, dev_info_t *dip) 8027Sjchu { 8127Sjchu ddi_device_acc_attr_t attr; 8227Sjchu px_reg_bank_t reg_bank = PX_REG_CSR; 8327Sjchu 8427Sjchu DBG(DBG_ATTACH, dip, "px_lib_map_regs: pxu_p:0x%p, dip 0x%p\n", 8527Sjchu pxu_p, dip); 8627Sjchu 8727Sjchu attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 8827Sjchu attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 8927Sjchu attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 9027Sjchu 9127Sjchu /* 9227Sjchu * PCI CSR Base 9327Sjchu */ 9427Sjchu if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank], 9527Sjchu 0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) { 9627Sjchu goto fail; 9727Sjchu } 9827Sjchu 9927Sjchu reg_bank++; 10027Sjchu 10127Sjchu /* 10227Sjchu * XBUS CSR Base 10327Sjchu */ 10427Sjchu if (ddi_regs_map_setup(dip, reg_bank, &pxu_p->px_address[reg_bank], 10527Sjchu 0, 0, &attr, &pxu_p->px_ac[reg_bank]) != DDI_SUCCESS) { 10627Sjchu goto fail; 10727Sjchu } 10827Sjchu 10927Sjchu pxu_p->px_address[reg_bank] -= FIRE_CONTROL_STATUS; 11027Sjchu 11127Sjchu done: 11227Sjchu for (; reg_bank >= PX_REG_CSR; reg_bank--) { 11327Sjchu DBG(DBG_ATTACH, dip, "reg_bank 0x%x address 0x%p\n", 11427Sjchu reg_bank, pxu_p->px_address[reg_bank]); 11527Sjchu } 11627Sjchu 11727Sjchu return (DDI_SUCCESS); 11827Sjchu 11927Sjchu fail: 12027Sjchu cmn_err(CE_WARN, "%s%d: unable to map reg entry %d\n", 12127Sjchu ddi_driver_name(dip), ddi_get_instance(dip), reg_bank); 12227Sjchu 12327Sjchu for (reg_bank--; reg_bank >= PX_REG_CSR; reg_bank--) { 12427Sjchu pxu_p->px_address[reg_bank] = NULL; 12527Sjchu ddi_regs_map_free(&pxu_p->px_ac[reg_bank]); 12627Sjchu } 12727Sjchu 12827Sjchu return (DDI_FAILURE); 12927Sjchu } 13027Sjchu 13127Sjchu /* 13227Sjchu * px_lib_unmap_regs: 13327Sjchu * 13427Sjchu * This routine unmaps the registers mapped by map_px_registers. 13527Sjchu * 13627Sjchu * used by: px_detach(), and error conditions in px_attach() 13727Sjchu * 13827Sjchu * return value: none 13927Sjchu */ 14027Sjchu void 14127Sjchu px_lib_unmap_regs(pxu_t *pxu_p) 14227Sjchu { 14327Sjchu int i; 14427Sjchu 14527Sjchu for (i = 0; i < PX_REG_MAX; i++) { 14627Sjchu if (pxu_p->px_ac[i]) 14727Sjchu ddi_regs_map_free(&pxu_p->px_ac[i]); 14827Sjchu } 14927Sjchu } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate int 1520Sstevel@tonic-gate px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl) 1530Sstevel@tonic-gate { 1540Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 15527Sjchu caddr_t xbc_csr_base, csr_base; 1560Sstevel@tonic-gate px_dvma_range_prop_t px_dvma_range; 1570Sstevel@tonic-gate uint32_t chip_id; 1580Sstevel@tonic-gate pxu_t *pxu_p; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "px_lib_dev_init: dip 0x%p\n", dip); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate if ((chip_id = px_identity_chip(px_p)) == PX_CHIP_UNIDENTIFIED) 1630Sstevel@tonic-gate return (DDI_FAILURE); 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate switch (chip_id) { 1660Sstevel@tonic-gate case FIRE_VER_10: 167225Sess cmn_err(CE_WARN, "FIRE Hardware Version 1.0 is not supported"); 168225Sess return (DDI_FAILURE); 1690Sstevel@tonic-gate case FIRE_VER_20: 1700Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "FIRE Hardware Version 2.0\n"); 1710Sstevel@tonic-gate break; 1720Sstevel@tonic-gate default: 17327Sjchu cmn_err(CE_WARN, "%s%d: FIRE Hardware Version Unknown\n", 1740Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1750Sstevel@tonic-gate return (DDI_FAILURE); 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * Allocate platform specific structure and link it to 1800Sstevel@tonic-gate * the px state structure. 1810Sstevel@tonic-gate */ 1820Sstevel@tonic-gate pxu_p = kmem_zalloc(sizeof (pxu_t), KM_SLEEP); 1830Sstevel@tonic-gate pxu_p->chip_id = chip_id; 1840Sstevel@tonic-gate pxu_p->portid = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1850Sstevel@tonic-gate "portid", -1); 1860Sstevel@tonic-gate 18727Sjchu /* Map in the registers */ 18827Sjchu if (px_lib_map_regs(pxu_p, dip) == DDI_FAILURE) { 18927Sjchu kmem_free(pxu_p, sizeof (pxu_t)); 19027Sjchu 19127Sjchu return (DDI_FAILURE); 19227Sjchu } 19327Sjchu 19427Sjchu xbc_csr_base = (caddr_t)pxu_p->px_address[PX_REG_XBC]; 19527Sjchu csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 19627Sjchu 1970Sstevel@tonic-gate pxu_p->tsb_cookie = iommu_tsb_alloc(pxu_p->portid); 1980Sstevel@tonic-gate pxu_p->tsb_size = iommu_tsb_cookie_to_size(pxu_p->tsb_cookie); 1990Sstevel@tonic-gate pxu_p->tsb_vaddr = iommu_tsb_cookie_to_va(pxu_p->tsb_cookie); 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * Create "virtual-dma" property to support child devices 2030Sstevel@tonic-gate * needing to know DVMA range. 2040Sstevel@tonic-gate */ 2050Sstevel@tonic-gate px_dvma_range.dvma_base = (uint32_t)px_mmu_dvma_end + 1 2060Sstevel@tonic-gate - ((pxu_p->tsb_size >> 3) << MMU_PAGE_SHIFT); 2070Sstevel@tonic-gate px_dvma_range.dvma_len = (uint32_t) 2080Sstevel@tonic-gate px_mmu_dvma_end - px_dvma_range.dvma_base + 1; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 2110Sstevel@tonic-gate "virtual-dma", (caddr_t)&px_dvma_range, 2120Sstevel@tonic-gate sizeof (px_dvma_range_prop_t)); 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * Initilize all fire hardware specific blocks. 2150Sstevel@tonic-gate */ 2160Sstevel@tonic-gate hvio_cb_init(xbc_csr_base, pxu_p); 2170Sstevel@tonic-gate hvio_ib_init(csr_base, pxu_p); 2180Sstevel@tonic-gate hvio_pec_init(csr_base, pxu_p); 2190Sstevel@tonic-gate hvio_mmu_init(csr_base, pxu_p); 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate px_p->px_plat_p = (void *)pxu_p; 2220Sstevel@tonic-gate 22327Sjchu /* 22427Sjchu * Initialize all the interrupt handlers 22527Sjchu */ 22627Sjchu px_err_reg_enable(px_p, PX_ERR_JBC); 22727Sjchu px_err_reg_enable(px_p, PX_ERR_MMU); 22827Sjchu px_err_reg_enable(px_p, PX_ERR_IMU); 22927Sjchu px_err_reg_enable(px_p, PX_ERR_TLU_UE); 23027Sjchu px_err_reg_enable(px_p, PX_ERR_TLU_CE); 23127Sjchu px_err_reg_enable(px_p, PX_ERR_TLU_OE); 23227Sjchu px_err_reg_enable(px_p, PX_ERR_ILU); 23327Sjchu px_err_reg_enable(px_p, PX_ERR_LPU_LINK); 23427Sjchu px_err_reg_enable(px_p, PX_ERR_LPU_PHY); 23527Sjchu px_err_reg_enable(px_p, PX_ERR_LPU_RX); 23627Sjchu px_err_reg_enable(px_p, PX_ERR_LPU_TX); 23727Sjchu px_err_reg_enable(px_p, PX_ERR_LPU_LTSSM); 23827Sjchu px_err_reg_enable(px_p, PX_ERR_LPU_GIGABLZ); 23927Sjchu 2400Sstevel@tonic-gate /* Initilize device handle */ 2410Sstevel@tonic-gate *dev_hdl = (devhandle_t)csr_base; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "px_lib_dev_init: dev_hdl 0x%llx\n", *dev_hdl); 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate return (DDI_SUCCESS); 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate int 2490Sstevel@tonic-gate px_lib_dev_fini(dev_info_t *dip) 2500Sstevel@tonic-gate { 2510Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 2520Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate DBG(DBG_DETACH, dip, "px_lib_dev_fini: dip 0x%p\n", dip); 2550Sstevel@tonic-gate 25627Sjchu /* 25727Sjchu * Deinitialize all the interrupt handlers 25827Sjchu */ 25927Sjchu px_err_reg_disable(px_p, PX_ERR_JBC); 26027Sjchu px_err_reg_disable(px_p, PX_ERR_MMU); 26127Sjchu px_err_reg_disable(px_p, PX_ERR_IMU); 26227Sjchu px_err_reg_disable(px_p, PX_ERR_TLU_UE); 26327Sjchu px_err_reg_disable(px_p, PX_ERR_TLU_CE); 26427Sjchu px_err_reg_disable(px_p, PX_ERR_TLU_OE); 26527Sjchu px_err_reg_disable(px_p, PX_ERR_ILU); 26627Sjchu px_err_reg_disable(px_p, PX_ERR_LPU_LINK); 26727Sjchu px_err_reg_disable(px_p, PX_ERR_LPU_PHY); 26827Sjchu px_err_reg_disable(px_p, PX_ERR_LPU_RX); 26927Sjchu px_err_reg_disable(px_p, PX_ERR_LPU_TX); 27027Sjchu px_err_reg_disable(px_p, PX_ERR_LPU_LTSSM); 27127Sjchu px_err_reg_disable(px_p, PX_ERR_LPU_GIGABLZ); 27227Sjchu 2730Sstevel@tonic-gate iommu_tsb_free(pxu_p->tsb_cookie); 2740Sstevel@tonic-gate 27527Sjchu px_lib_unmap_regs((pxu_t *)px_p->px_plat_p); 27627Sjchu kmem_free(px_p->px_plat_p, sizeof (pxu_t)); 2770Sstevel@tonic-gate px_p->px_plat_p = NULL; 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate return (DDI_SUCCESS); 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate /*ARGSUSED*/ 2830Sstevel@tonic-gate int 2840Sstevel@tonic-gate px_lib_intr_devino_to_sysino(dev_info_t *dip, devino_t devino, 2850Sstevel@tonic-gate sysino_t *sysino) 2860Sstevel@tonic-gate { 2870Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 2880Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 2890Sstevel@tonic-gate uint64_t ret; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: dip 0x%p " 2920Sstevel@tonic-gate "devino 0x%x\n", dip, devino); 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate if ((ret = hvio_intr_devino_to_sysino(DIP_TO_HANDLE(dip), 2950Sstevel@tonic-gate pxu_p, devino, sysino)) != H_EOK) { 2960Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, 2970Sstevel@tonic-gate "hvio_intr_devino_to_sysino failed, ret 0x%lx\n", ret); 2980Sstevel@tonic-gate return (DDI_FAILURE); 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_devino_to_sysino: sysino 0x%llx\n", 3020Sstevel@tonic-gate *sysino); 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate return (DDI_SUCCESS); 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate /*ARGSUSED*/ 3080Sstevel@tonic-gate int 3090Sstevel@tonic-gate px_lib_intr_getvalid(dev_info_t *dip, sysino_t sysino, 3100Sstevel@tonic-gate intr_valid_state_t *intr_valid_state) 3110Sstevel@tonic-gate { 3120Sstevel@tonic-gate uint64_t ret; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: dip 0x%p sysino 0x%llx\n", 3150Sstevel@tonic-gate dip, sysino); 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate if ((ret = hvio_intr_getvalid(DIP_TO_HANDLE(dip), 3180Sstevel@tonic-gate sysino, intr_valid_state)) != H_EOK) { 3190Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_getvalid failed, ret 0x%lx\n", 3200Sstevel@tonic-gate ret); 3210Sstevel@tonic-gate return (DDI_FAILURE); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getvalid: intr_valid_state 0x%x\n", 3250Sstevel@tonic-gate *intr_valid_state); 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate return (DDI_SUCCESS); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate /*ARGSUSED*/ 3310Sstevel@tonic-gate int 3320Sstevel@tonic-gate px_lib_intr_setvalid(dev_info_t *dip, sysino_t sysino, 3330Sstevel@tonic-gate intr_valid_state_t intr_valid_state) 3340Sstevel@tonic-gate { 3350Sstevel@tonic-gate uint64_t ret; 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_setvalid: dip 0x%p sysino 0x%llx " 3380Sstevel@tonic-gate "intr_valid_state 0x%x\n", dip, sysino, intr_valid_state); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if ((ret = hvio_intr_setvalid(DIP_TO_HANDLE(dip), 3410Sstevel@tonic-gate sysino, intr_valid_state)) != H_EOK) { 3420Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_setvalid failed, ret 0x%lx\n", 3430Sstevel@tonic-gate ret); 3440Sstevel@tonic-gate return (DDI_FAILURE); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate return (DDI_SUCCESS); 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate /*ARGSUSED*/ 3510Sstevel@tonic-gate int 3520Sstevel@tonic-gate px_lib_intr_getstate(dev_info_t *dip, sysino_t sysino, 3530Sstevel@tonic-gate intr_state_t *intr_state) 3540Sstevel@tonic-gate { 3550Sstevel@tonic-gate uint64_t ret; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: dip 0x%p sysino 0x%llx\n", 3580Sstevel@tonic-gate dip, sysino); 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate if ((ret = hvio_intr_getstate(DIP_TO_HANDLE(dip), 3610Sstevel@tonic-gate sysino, intr_state)) != H_EOK) { 3620Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_getstate failed, ret 0x%lx\n", 3630Sstevel@tonic-gate ret); 3640Sstevel@tonic-gate return (DDI_FAILURE); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_getstate: intr_state 0x%x\n", 3680Sstevel@tonic-gate *intr_state); 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate return (DDI_SUCCESS); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /*ARGSUSED*/ 3740Sstevel@tonic-gate int 3750Sstevel@tonic-gate px_lib_intr_setstate(dev_info_t *dip, sysino_t sysino, 3760Sstevel@tonic-gate intr_state_t intr_state) 3770Sstevel@tonic-gate { 3780Sstevel@tonic-gate uint64_t ret; 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_setstate: dip 0x%p sysino 0x%llx " 3810Sstevel@tonic-gate "intr_state 0x%x\n", dip, sysino, intr_state); 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate if ((ret = hvio_intr_setstate(DIP_TO_HANDLE(dip), 3840Sstevel@tonic-gate sysino, intr_state)) != H_EOK) { 3850Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_setstate failed, ret 0x%lx\n", 3860Sstevel@tonic-gate ret); 3870Sstevel@tonic-gate return (DDI_FAILURE); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate return (DDI_SUCCESS); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate /*ARGSUSED*/ 3940Sstevel@tonic-gate int 3950Sstevel@tonic-gate px_lib_intr_gettarget(dev_info_t *dip, sysino_t sysino, cpuid_t *cpuid) 3960Sstevel@tonic-gate { 3970Sstevel@tonic-gate uint64_t ret; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: dip 0x%p sysino 0x%llx\n", 4000Sstevel@tonic-gate dip, sysino); 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate if ((ret = hvio_intr_gettarget(DIP_TO_HANDLE(dip), 4030Sstevel@tonic-gate sysino, cpuid)) != H_EOK) { 4040Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_gettarget failed, ret 0x%lx\n", 4050Sstevel@tonic-gate ret); 4060Sstevel@tonic-gate return (DDI_FAILURE); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: cpuid 0x%x\n", cpuid); 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate return (DDI_SUCCESS); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate /*ARGSUSED*/ 4150Sstevel@tonic-gate int 4160Sstevel@tonic-gate px_lib_intr_settarget(dev_info_t *dip, sysino_t sysino, cpuid_t cpuid) 4170Sstevel@tonic-gate { 4180Sstevel@tonic-gate uint64_t ret; 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_settarget: dip 0x%p sysino 0x%llx " 4210Sstevel@tonic-gate "cpuid 0x%x\n", dip, sysino, cpuid); 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate if ((ret = hvio_intr_settarget(DIP_TO_HANDLE(dip), 4240Sstevel@tonic-gate sysino, cpuid)) != H_EOK) { 4250Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "hvio_intr_settarget failed, ret 0x%lx\n", 4260Sstevel@tonic-gate ret); 4270Sstevel@tonic-gate return (DDI_FAILURE); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate return (DDI_SUCCESS); 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate /*ARGSUSED*/ 4340Sstevel@tonic-gate int 4350Sstevel@tonic-gate px_lib_intr_reset(dev_info_t *dip) 4360Sstevel@tonic-gate { 4370Sstevel@tonic-gate devino_t ino; 4380Sstevel@tonic-gate sysino_t sysino; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate DBG(DBG_LIB_INT, dip, "px_lib_intr_reset: dip 0x%p\n", dip); 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /* Reset all Interrupts */ 4430Sstevel@tonic-gate for (ino = 0; ino < INTERRUPT_MAPPING_ENTRIES; ino++) { 4440Sstevel@tonic-gate if (px_lib_intr_devino_to_sysino(dip, ino, 4450Sstevel@tonic-gate &sysino) != DDI_SUCCESS) 4460Sstevel@tonic-gate return (BF_FATAL); 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate if (px_lib_intr_setstate(dip, sysino, 4490Sstevel@tonic-gate INTR_IDLE_STATE) != DDI_SUCCESS) 4500Sstevel@tonic-gate return (BF_FATAL); 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate return (BF_NONE); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate /*ARGSUSED*/ 4570Sstevel@tonic-gate int 4580Sstevel@tonic-gate px_lib_iommu_map(dev_info_t *dip, tsbid_t tsbid, pages_t pages, 4590Sstevel@tonic-gate io_attributes_t io_attributes, void *addr, size_t pfn_index, 4600Sstevel@tonic-gate int flag) 4610Sstevel@tonic-gate { 4620Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 4630Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 4640Sstevel@tonic-gate uint64_t ret; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_map: dip 0x%p tsbid 0x%llx " 4670Sstevel@tonic-gate "pages 0x%x atrr 0x%x addr 0x%p pfn_index 0x%llx, flag 0x%x\n", 4680Sstevel@tonic-gate dip, tsbid, pages, io_attributes, addr, pfn_index, flag); 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate if ((ret = hvio_iommu_map(px_p->px_dev_hdl, pxu_p, tsbid, pages, 4710Sstevel@tonic-gate io_attributes, addr, pfn_index, flag)) != H_EOK) { 4720Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 4730Sstevel@tonic-gate "px_lib_iommu_map failed, ret 0x%lx\n", ret); 4740Sstevel@tonic-gate return (DDI_FAILURE); 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate return (DDI_SUCCESS); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate /*ARGSUSED*/ 4810Sstevel@tonic-gate int 4820Sstevel@tonic-gate px_lib_iommu_demap(dev_info_t *dip, tsbid_t tsbid, pages_t pages) 4830Sstevel@tonic-gate { 4840Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 4850Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 4860Sstevel@tonic-gate uint64_t ret; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_demap: dip 0x%p tsbid 0x%llx " 4890Sstevel@tonic-gate "pages 0x%x\n", dip, tsbid, pages); 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate if ((ret = hvio_iommu_demap(px_p->px_dev_hdl, pxu_p, tsbid, pages)) 4920Sstevel@tonic-gate != H_EOK) { 4930Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 4940Sstevel@tonic-gate "px_lib_iommu_demap failed, ret 0x%lx\n", ret); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate return (DDI_FAILURE); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate return (DDI_SUCCESS); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /*ARGSUSED*/ 5030Sstevel@tonic-gate int 5040Sstevel@tonic-gate px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, 5050Sstevel@tonic-gate io_attributes_t *attributes_p, r_addr_t *r_addr_p) 5060Sstevel@tonic-gate { 5070Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 5080Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 5090Sstevel@tonic-gate uint64_t ret; 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: dip 0x%p tsbid 0x%llx\n", 5120Sstevel@tonic-gate dip, tsbid); 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate if ((ret = hvio_iommu_getmap(DIP_TO_HANDLE(dip), pxu_p, tsbid, 5150Sstevel@tonic-gate attributes_p, r_addr_p)) != H_EOK) { 5160Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 5170Sstevel@tonic-gate "hvio_iommu_getmap failed, ret 0x%lx\n", ret); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate return ((ret == H_ENOMAP) ? DDI_DMA_NOMAPPING:DDI_FAILURE); 5200Sstevel@tonic-gate } 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getmap: attr 0x%x r_addr 0x%llx\n", 5230Sstevel@tonic-gate *attributes_p, *r_addr_p); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate return (DDI_SUCCESS); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate /* 5300Sstevel@tonic-gate * Checks dma attributes against system bypass ranges 5310Sstevel@tonic-gate * The bypass range is determined by the hardware. Return them so the 5320Sstevel@tonic-gate * common code can do generic checking against them. 5330Sstevel@tonic-gate */ 5340Sstevel@tonic-gate /*ARGSUSED*/ 5350Sstevel@tonic-gate int 5360Sstevel@tonic-gate px_lib_dma_bypass_rngchk(ddi_dma_attr_t *attrp, uint64_t *lo_p, uint64_t *hi_p) 5370Sstevel@tonic-gate { 5380Sstevel@tonic-gate *lo_p = MMU_BYPASS_BASE; 5390Sstevel@tonic-gate *hi_p = MMU_BYPASS_END; 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate return (DDI_SUCCESS); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate /*ARGSUSED*/ 5460Sstevel@tonic-gate int 5470Sstevel@tonic-gate px_lib_iommu_getbypass(dev_info_t *dip, r_addr_t ra, 5480Sstevel@tonic-gate io_attributes_t io_attributes, io_addr_t *io_addr_p) 5490Sstevel@tonic-gate { 5500Sstevel@tonic-gate uint64_t ret; 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: dip 0x%p ra 0x%llx " 5530Sstevel@tonic-gate "attr 0x%x\n", dip, ra, io_attributes); 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate if ((ret = hvio_iommu_getbypass(DIP_TO_HANDLE(dip), ra, 5560Sstevel@tonic-gate io_attributes, io_addr_p)) != H_EOK) { 5570Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, 5580Sstevel@tonic-gate "hvio_iommu_getbypass failed, ret 0x%lx\n", ret); 5590Sstevel@tonic-gate return (DDI_FAILURE); 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: io_addr 0x%llx\n", 5630Sstevel@tonic-gate *io_addr_p); 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate return (DDI_SUCCESS); 5660Sstevel@tonic-gate } 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate /* 5690Sstevel@tonic-gate * bus dma sync entry point. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate /*ARGSUSED*/ 5720Sstevel@tonic-gate int 5730Sstevel@tonic-gate px_lib_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, 5740Sstevel@tonic-gate off_t off, size_t len, uint_t cache_flags) 5750Sstevel@tonic-gate { 5760Sstevel@tonic-gate ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate DBG(DBG_LIB_DMA, dip, "px_lib_dma_sync: dip 0x%p rdip 0x%p " 5790Sstevel@tonic-gate "handle 0x%llx off 0x%x len 0x%x flags 0x%x\n", 5800Sstevel@tonic-gate dip, rdip, handle, off, len, cache_flags); 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate /* 5830Sstevel@tonic-gate * jbus_stst_order is found only in certain cpu modules. 5840Sstevel@tonic-gate * Just return success if not present. 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate if (&jbus_stst_order == NULL) 5870Sstevel@tonic-gate return (DDI_SUCCESS); 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate if (!(mp->dmai_flags & DMAI_FLAGS_INUSE)) { 59027Sjchu cmn_err(CE_WARN, "%s%d: Unbound dma handle %p.", 59127Sjchu ddi_driver_name(rdip), ddi_get_instance(rdip), (void *)mp); 59227Sjchu 5930Sstevel@tonic-gate return (DDI_FAILURE); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate if (mp->dmai_flags & DMAI_FLAGS_NOSYNC) 5970Sstevel@tonic-gate return (DDI_SUCCESS); 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate /* 6000Sstevel@tonic-gate * No flush needed when sending data from memory to device. 6010Sstevel@tonic-gate * Nothing to do to "sync" memory to what device would already see. 6020Sstevel@tonic-gate */ 6030Sstevel@tonic-gate if (!(mp->dmai_rflags & DDI_DMA_READ) || 6040Sstevel@tonic-gate ((cache_flags & PX_DMA_SYNC_DDI_FLAGS) == DDI_DMA_SYNC_FORDEV)) 6050Sstevel@tonic-gate return (DDI_SUCCESS); 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate /* 6080Sstevel@tonic-gate * Perform necessary cpu workaround to ensure jbus ordering. 6090Sstevel@tonic-gate * CPU's internal "invalidate FIFOs" are flushed. 6100Sstevel@tonic-gate */ 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate #if !defined(lint) 6130Sstevel@tonic-gate kpreempt_disable(); 6140Sstevel@tonic-gate #endif 6150Sstevel@tonic-gate jbus_stst_order(); 6160Sstevel@tonic-gate #if !defined(lint) 6170Sstevel@tonic-gate kpreempt_enable(); 6180Sstevel@tonic-gate #endif 6190Sstevel@tonic-gate return (DDI_SUCCESS); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate /* 6230Sstevel@tonic-gate * MSIQ Functions: 6240Sstevel@tonic-gate */ 6250Sstevel@tonic-gate /*ARGSUSED*/ 6260Sstevel@tonic-gate int 6270Sstevel@tonic-gate px_lib_msiq_init(dev_info_t *dip) 6280Sstevel@tonic-gate { 6290Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 6300Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 6310Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 6320Sstevel@tonic-gate caddr_t msiq_addr; 6330Sstevel@tonic-gate px_dvma_addr_t pg_index; 6340Sstevel@tonic-gate size_t size; 6350Sstevel@tonic-gate int ret; 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_init: dip 0x%p\n", dip); 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate /* 6400Sstevel@tonic-gate * Map the EQ memory into the Fire MMU (has to be 512KB aligned) 6410Sstevel@tonic-gate * and then initialize the base address register. 6420Sstevel@tonic-gate * 6430Sstevel@tonic-gate * Allocate entries from Fire IOMMU so that the resulting address 6440Sstevel@tonic-gate * is properly aligned. Calculate the index of the first allocated 6450Sstevel@tonic-gate * entry. Note: The size of the mapping is assumed to be a multiple 6460Sstevel@tonic-gate * of the page size. 6470Sstevel@tonic-gate */ 6480Sstevel@tonic-gate msiq_addr = (caddr_t)(((uint64_t)msiq_state_p->msiq_buf_p + 6490Sstevel@tonic-gate (MMU_PAGE_SIZE - 1)) >> MMU_PAGE_SHIFT << MMU_PAGE_SHIFT); 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate size = msiq_state_p->msiq_cnt * 6520Sstevel@tonic-gate msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t); 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate pxu_p->msiq_mapped_p = vmem_xalloc(px_p->px_mmu_p->mmu_dvma_map, 6550Sstevel@tonic-gate size, (512 * 1024), 0, 0, NULL, NULL, VM_NOSLEEP | VM_BESTFIT); 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate if (pxu_p->msiq_mapped_p == NULL) 6580Sstevel@tonic-gate return (DDI_FAILURE); 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p, 6610Sstevel@tonic-gate MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p)); 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate if ((ret = px_lib_iommu_map(px_p->px_dip, PCI_TSBID(0, pg_index), 6640Sstevel@tonic-gate MMU_BTOP(size), PCI_MAP_ATTR_WRITE, (void *)msiq_addr, 0, 6650Sstevel@tonic-gate MMU_MAP_BUF)) != DDI_SUCCESS) { 6660Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 6670Sstevel@tonic-gate "hvio_msiq_init failed, ret 0x%lx\n", ret); 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate (void) px_lib_msiq_fini(dip); 6700Sstevel@tonic-gate return (DDI_FAILURE); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate (void) hvio_msiq_init(DIP_TO_HANDLE(dip), pxu_p); 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate return (DDI_SUCCESS); 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate /*ARGSUSED*/ 6790Sstevel@tonic-gate int 6800Sstevel@tonic-gate px_lib_msiq_fini(dev_info_t *dip) 6810Sstevel@tonic-gate { 6820Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 6830Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 6840Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 6850Sstevel@tonic-gate px_dvma_addr_t pg_index; 6860Sstevel@tonic-gate size_t size; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_fini: dip 0x%p\n", dip); 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate /* 6910Sstevel@tonic-gate * Unmap and free the EQ memory that had been mapped 6920Sstevel@tonic-gate * into the Fire IOMMU. 6930Sstevel@tonic-gate */ 6940Sstevel@tonic-gate size = msiq_state_p->msiq_cnt * 6950Sstevel@tonic-gate msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t); 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate pg_index = MMU_PAGE_INDEX(px_p->px_mmu_p, 6980Sstevel@tonic-gate MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p)); 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate (void) px_lib_iommu_demap(px_p->px_dip, 7010Sstevel@tonic-gate PCI_TSBID(0, pg_index), MMU_BTOP(size)); 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate /* Free the entries from the Fire MMU */ 7040Sstevel@tonic-gate vmem_xfree(px_p->px_mmu_p->mmu_dvma_map, 7050Sstevel@tonic-gate (void *)pxu_p->msiq_mapped_p, size); 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate return (DDI_SUCCESS); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate /*ARGSUSED*/ 7110Sstevel@tonic-gate int 7120Sstevel@tonic-gate px_lib_msiq_info(dev_info_t *dip, msiqid_t msiq_id, r_addr_t *ra_p, 7130Sstevel@tonic-gate uint_t *msiq_rec_cnt_p) 7140Sstevel@tonic-gate { 7150Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 7160Sstevel@tonic-gate px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 7170Sstevel@tonic-gate uint64_t *msiq_addr; 7180Sstevel@tonic-gate size_t msiq_size; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: dip 0x%p msiq_id 0x%x\n", 7210Sstevel@tonic-gate dip, msiq_id); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate msiq_addr = (uint64_t *)(((uint64_t)msiq_state_p->msiq_buf_p + 7240Sstevel@tonic-gate (MMU_PAGE_SIZE - 1)) >> MMU_PAGE_SHIFT << MMU_PAGE_SHIFT); 7250Sstevel@tonic-gate msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t); 7260Sstevel@tonic-gate ra_p = (r_addr_t *)((caddr_t)msiq_addr + (msiq_id * msiq_size)); 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate *msiq_rec_cnt_p = msiq_state_p->msiq_rec_cnt; 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: ra_p 0x%p msiq_rec_cnt 0x%x\n", 7310Sstevel@tonic-gate ra_p, *msiq_rec_cnt_p); 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate return (DDI_SUCCESS); 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate /*ARGSUSED*/ 7370Sstevel@tonic-gate int 7380Sstevel@tonic-gate px_lib_msiq_getvalid(dev_info_t *dip, msiqid_t msiq_id, 7390Sstevel@tonic-gate pci_msiq_valid_state_t *msiq_valid_state) 7400Sstevel@tonic-gate { 7410Sstevel@tonic-gate uint64_t ret; 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: dip 0x%p msiq_id 0x%x\n", 7440Sstevel@tonic-gate dip, msiq_id); 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate if ((ret = hvio_msiq_getvalid(DIP_TO_HANDLE(dip), 7470Sstevel@tonic-gate msiq_id, msiq_valid_state)) != H_EOK) { 7480Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 7490Sstevel@tonic-gate "hvio_msiq_getvalid failed, ret 0x%lx\n", ret); 7500Sstevel@tonic-gate return (DDI_FAILURE); 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getvalid: msiq_valid_state 0x%x\n", 7540Sstevel@tonic-gate *msiq_valid_state); 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate return (DDI_SUCCESS); 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate /*ARGSUSED*/ 7600Sstevel@tonic-gate int 7610Sstevel@tonic-gate px_lib_msiq_setvalid(dev_info_t *dip, msiqid_t msiq_id, 7620Sstevel@tonic-gate pci_msiq_valid_state_t msiq_valid_state) 7630Sstevel@tonic-gate { 7640Sstevel@tonic-gate uint64_t ret; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setvalid: dip 0x%p msiq_id 0x%x " 7670Sstevel@tonic-gate "msiq_valid_state 0x%x\n", dip, msiq_id, msiq_valid_state); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate if ((ret = hvio_msiq_setvalid(DIP_TO_HANDLE(dip), 7700Sstevel@tonic-gate msiq_id, msiq_valid_state)) != H_EOK) { 7710Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 7720Sstevel@tonic-gate "hvio_msiq_setvalid failed, ret 0x%lx\n", ret); 7730Sstevel@tonic-gate return (DDI_FAILURE); 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate return (DDI_SUCCESS); 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate /*ARGSUSED*/ 7800Sstevel@tonic-gate int 7810Sstevel@tonic-gate px_lib_msiq_getstate(dev_info_t *dip, msiqid_t msiq_id, 7820Sstevel@tonic-gate pci_msiq_state_t *msiq_state) 7830Sstevel@tonic-gate { 7840Sstevel@tonic-gate uint64_t ret; 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: dip 0x%p msiq_id 0x%x\n", 7870Sstevel@tonic-gate dip, msiq_id); 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate if ((ret = hvio_msiq_getstate(DIP_TO_HANDLE(dip), 7900Sstevel@tonic-gate msiq_id, msiq_state)) != H_EOK) { 7910Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 7920Sstevel@tonic-gate "hvio_msiq_getstate failed, ret 0x%lx\n", ret); 7930Sstevel@tonic-gate return (DDI_FAILURE); 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_getstate: msiq_state 0x%x\n", 7970Sstevel@tonic-gate *msiq_state); 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate return (DDI_SUCCESS); 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate /*ARGSUSED*/ 8030Sstevel@tonic-gate int 8040Sstevel@tonic-gate px_lib_msiq_setstate(dev_info_t *dip, msiqid_t msiq_id, 8050Sstevel@tonic-gate pci_msiq_state_t msiq_state) 8060Sstevel@tonic-gate { 8070Sstevel@tonic-gate uint64_t ret; 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_setstate: dip 0x%p msiq_id 0x%x " 8100Sstevel@tonic-gate "msiq_state 0x%x\n", dip, msiq_id, msiq_state); 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate if ((ret = hvio_msiq_setstate(DIP_TO_HANDLE(dip), 8130Sstevel@tonic-gate msiq_id, msiq_state)) != H_EOK) { 8140Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8150Sstevel@tonic-gate "hvio_msiq_setstate failed, ret 0x%lx\n", ret); 8160Sstevel@tonic-gate return (DDI_FAILURE); 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate return (DDI_SUCCESS); 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate /*ARGSUSED*/ 8230Sstevel@tonic-gate int 8240Sstevel@tonic-gate px_lib_msiq_gethead(dev_info_t *dip, msiqid_t msiq_id, 8250Sstevel@tonic-gate msiqhead_t *msiq_head) 8260Sstevel@tonic-gate { 8270Sstevel@tonic-gate uint64_t ret; 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: dip 0x%p msiq_id 0x%x\n", 8300Sstevel@tonic-gate dip, msiq_id); 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate if ((ret = hvio_msiq_gethead(DIP_TO_HANDLE(dip), 8330Sstevel@tonic-gate msiq_id, msiq_head)) != H_EOK) { 8340Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8350Sstevel@tonic-gate "hvio_msiq_gethead failed, ret 0x%lx\n", ret); 8360Sstevel@tonic-gate return (DDI_FAILURE); 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gethead: msiq_head 0x%x\n", 8400Sstevel@tonic-gate *msiq_head); 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate return (DDI_SUCCESS); 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate /*ARGSUSED*/ 8460Sstevel@tonic-gate int 8470Sstevel@tonic-gate px_lib_msiq_sethead(dev_info_t *dip, msiqid_t msiq_id, 8480Sstevel@tonic-gate msiqhead_t msiq_head) 8490Sstevel@tonic-gate { 8500Sstevel@tonic-gate uint64_t ret; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_sethead: dip 0x%p msiq_id 0x%x " 8530Sstevel@tonic-gate "msiq_head 0x%x\n", dip, msiq_id, msiq_head); 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate if ((ret = hvio_msiq_sethead(DIP_TO_HANDLE(dip), 8560Sstevel@tonic-gate msiq_id, msiq_head)) != H_EOK) { 8570Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8580Sstevel@tonic-gate "hvio_msiq_sethead failed, ret 0x%lx\n", ret); 8590Sstevel@tonic-gate return (DDI_FAILURE); 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate return (DDI_SUCCESS); 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate /*ARGSUSED*/ 8660Sstevel@tonic-gate int 8670Sstevel@tonic-gate px_lib_msiq_gettail(dev_info_t *dip, msiqid_t msiq_id, 8680Sstevel@tonic-gate msiqtail_t *msiq_tail) 8690Sstevel@tonic-gate { 8700Sstevel@tonic-gate uint64_t ret; 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: dip 0x%p msiq_id 0x%x\n", 8730Sstevel@tonic-gate dip, msiq_id); 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate if ((ret = hvio_msiq_gettail(DIP_TO_HANDLE(dip), 8760Sstevel@tonic-gate msiq_id, msiq_tail)) != H_EOK) { 8770Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, 8780Sstevel@tonic-gate "hvio_msiq_gettail failed, ret 0x%lx\n", ret); 8790Sstevel@tonic-gate return (DDI_FAILURE); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_gettail: msiq_tail 0x%x\n", 8830Sstevel@tonic-gate *msiq_tail); 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate return (DDI_SUCCESS); 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate /*ARGSUSED*/ 8890Sstevel@tonic-gate void 8900Sstevel@tonic-gate px_lib_get_msiq_rec(dev_info_t *dip, px_msiq_t *msiq_p, msiq_rec_t *msiq_rec_p) 8910Sstevel@tonic-gate { 8920Sstevel@tonic-gate eq_rec_t *eq_rec_p = (eq_rec_t *)msiq_p->msiq_curr; 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p eq_rec_p 0x%p\n", 8950Sstevel@tonic-gate dip, eq_rec_p); 8960Sstevel@tonic-gate 897287Smg140465 if (!eq_rec_p->eq_rec_fmt_type) { 898287Smg140465 /* Set msiq_rec_type to zero */ 899287Smg140465 msiq_rec_p->msiq_rec_type = 0; 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate return; 9020Sstevel@tonic-gate } 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: EQ RECORD, " 9050Sstevel@tonic-gate "eq_rec_rid 0x%llx eq_rec_fmt_type 0x%llx " 9060Sstevel@tonic-gate "eq_rec_len 0x%llx eq_rec_addr0 0x%llx " 9070Sstevel@tonic-gate "eq_rec_addr1 0x%llx eq_rec_data0 0x%llx " 9080Sstevel@tonic-gate "eq_rec_data1 0x%llx\n", eq_rec_p->eq_rec_rid, 9090Sstevel@tonic-gate eq_rec_p->eq_rec_fmt_type, eq_rec_p->eq_rec_len, 9100Sstevel@tonic-gate eq_rec_p->eq_rec_addr0, eq_rec_p->eq_rec_addr1, 9110Sstevel@tonic-gate eq_rec_p->eq_rec_data0, eq_rec_p->eq_rec_data1); 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate /* 9140Sstevel@tonic-gate * Only upper 4 bits of eq_rec_fmt_type is used 9150Sstevel@tonic-gate * to identify the EQ record type. 9160Sstevel@tonic-gate */ 9170Sstevel@tonic-gate switch (eq_rec_p->eq_rec_fmt_type >> 3) { 9180Sstevel@tonic-gate case EQ_REC_MSI32: 9190Sstevel@tonic-gate msiq_rec_p->msiq_rec_type = MSI32_REC; 9200Sstevel@tonic-gate 921225Sess msiq_rec_p->msiq_rec_data.msi.msi_data = 922225Sess eq_rec_p->eq_rec_data0; 9230Sstevel@tonic-gate break; 9240Sstevel@tonic-gate case EQ_REC_MSI64: 9250Sstevel@tonic-gate msiq_rec_p->msiq_rec_type = MSI64_REC; 9260Sstevel@tonic-gate 927225Sess msiq_rec_p->msiq_rec_data.msi.msi_data = 928225Sess eq_rec_p->eq_rec_data0; 9290Sstevel@tonic-gate break; 9300Sstevel@tonic-gate case EQ_REC_MSG: 9310Sstevel@tonic-gate msiq_rec_p->msiq_rec_type = MSG_REC; 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate msiq_rec_p->msiq_rec_data.msg.msg_route = 9340Sstevel@tonic-gate eq_rec_p->eq_rec_fmt_type & 7; 9350Sstevel@tonic-gate msiq_rec_p->msiq_rec_data.msg.msg_targ = eq_rec_p->eq_rec_rid; 9360Sstevel@tonic-gate msiq_rec_p->msiq_rec_data.msg.msg_code = eq_rec_p->eq_rec_data0; 9370Sstevel@tonic-gate break; 9380Sstevel@tonic-gate default: 9390Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: px_lib_get_msiq_rec: " 9400Sstevel@tonic-gate "0x%lx is an unknown EQ record type", 9410Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 9420Sstevel@tonic-gate eq_rec_p->eq_rec_fmt_type); 9430Sstevel@tonic-gate break; 9440Sstevel@tonic-gate } 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate msiq_rec_p->msiq_rec_rid = eq_rec_p->eq_rec_rid; 9470Sstevel@tonic-gate msiq_rec_p->msiq_rec_msi_addr = ((eq_rec_p->eq_rec_addr1 << 16) | 9480Sstevel@tonic-gate (eq_rec_p->eq_rec_addr0 << 2)); 9490Sstevel@tonic-gate 950287Smg140465 /* Zero out eq_rec_fmt_type field */ 951287Smg140465 eq_rec_p->eq_rec_fmt_type = 0; 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate /* 9550Sstevel@tonic-gate * MSI Functions: 9560Sstevel@tonic-gate */ 9570Sstevel@tonic-gate /*ARGSUSED*/ 9580Sstevel@tonic-gate int 9590Sstevel@tonic-gate px_lib_msi_init(dev_info_t *dip) 9600Sstevel@tonic-gate { 9610Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 9620Sstevel@tonic-gate px_msi_state_t *msi_state_p = &px_p->px_ib_p->ib_msi_state; 9630Sstevel@tonic-gate uint64_t ret; 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_init: dip 0x%p\n", dip); 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate if ((ret = hvio_msi_init(DIP_TO_HANDLE(dip), 9680Sstevel@tonic-gate msi_state_p->msi_addr32, msi_state_p->msi_addr64)) != H_EOK) { 9690Sstevel@tonic-gate DBG(DBG_LIB_MSIQ, dip, "px_lib_msi_init failed, ret 0x%lx\n", 9700Sstevel@tonic-gate ret); 9710Sstevel@tonic-gate return (DDI_FAILURE); 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate return (DDI_SUCCESS); 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate /*ARGSUSED*/ 9780Sstevel@tonic-gate int 9790Sstevel@tonic-gate px_lib_msi_getmsiq(dev_info_t *dip, msinum_t msi_num, 9800Sstevel@tonic-gate msiqid_t *msiq_id) 9810Sstevel@tonic-gate { 9820Sstevel@tonic-gate uint64_t ret; 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: dip 0x%p msi_num 0x%x\n", 9850Sstevel@tonic-gate dip, msi_num); 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate if ((ret = hvio_msi_getmsiq(DIP_TO_HANDLE(dip), 9880Sstevel@tonic-gate msi_num, msiq_id)) != H_EOK) { 9890Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 9900Sstevel@tonic-gate "hvio_msi_getmsiq failed, ret 0x%lx\n", ret); 9910Sstevel@tonic-gate return (DDI_FAILURE); 9920Sstevel@tonic-gate } 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getmsiq: msiq_id 0x%x\n", 9950Sstevel@tonic-gate *msiq_id); 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate return (DDI_SUCCESS); 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate /*ARGSUSED*/ 10010Sstevel@tonic-gate int 10020Sstevel@tonic-gate px_lib_msi_setmsiq(dev_info_t *dip, msinum_t msi_num, 10030Sstevel@tonic-gate msiqid_t msiq_id, msi_type_t msitype) 10040Sstevel@tonic-gate { 10050Sstevel@tonic-gate uint64_t ret; 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_setmsiq: dip 0x%p msi_num 0x%x " 10080Sstevel@tonic-gate "msq_id 0x%x\n", dip, msi_num, msiq_id); 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate if ((ret = hvio_msi_setmsiq(DIP_TO_HANDLE(dip), 10110Sstevel@tonic-gate msi_num, msiq_id)) != H_EOK) { 10120Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10130Sstevel@tonic-gate "hvio_msi_setmsiq failed, ret 0x%lx\n", ret); 10140Sstevel@tonic-gate return (DDI_FAILURE); 10150Sstevel@tonic-gate } 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate return (DDI_SUCCESS); 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate /*ARGSUSED*/ 10210Sstevel@tonic-gate int 10220Sstevel@tonic-gate px_lib_msi_getvalid(dev_info_t *dip, msinum_t msi_num, 10230Sstevel@tonic-gate pci_msi_valid_state_t *msi_valid_state) 10240Sstevel@tonic-gate { 10250Sstevel@tonic-gate uint64_t ret; 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: dip 0x%p msi_num 0x%x\n", 10280Sstevel@tonic-gate dip, msi_num); 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate if ((ret = hvio_msi_getvalid(DIP_TO_HANDLE(dip), 10310Sstevel@tonic-gate msi_num, msi_valid_state)) != H_EOK) { 10320Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10330Sstevel@tonic-gate "hvio_msi_getvalid failed, ret 0x%lx\n", ret); 10340Sstevel@tonic-gate return (DDI_FAILURE); 10350Sstevel@tonic-gate } 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getvalid: msiq_id 0x%x\n", 10380Sstevel@tonic-gate *msi_valid_state); 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate return (DDI_SUCCESS); 10410Sstevel@tonic-gate } 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate /*ARGSUSED*/ 10440Sstevel@tonic-gate int 10450Sstevel@tonic-gate px_lib_msi_setvalid(dev_info_t *dip, msinum_t msi_num, 10460Sstevel@tonic-gate pci_msi_valid_state_t msi_valid_state) 10470Sstevel@tonic-gate { 10480Sstevel@tonic-gate uint64_t ret; 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_setvalid: dip 0x%p msi_num 0x%x " 10510Sstevel@tonic-gate "msi_valid_state 0x%x\n", dip, msi_num, msi_valid_state); 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate if ((ret = hvio_msi_setvalid(DIP_TO_HANDLE(dip), 10540Sstevel@tonic-gate msi_num, msi_valid_state)) != H_EOK) { 10550Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10560Sstevel@tonic-gate "hvio_msi_setvalid failed, ret 0x%lx\n", ret); 10570Sstevel@tonic-gate return (DDI_FAILURE); 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate return (DDI_SUCCESS); 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate /*ARGSUSED*/ 10640Sstevel@tonic-gate int 10650Sstevel@tonic-gate px_lib_msi_getstate(dev_info_t *dip, msinum_t msi_num, 10660Sstevel@tonic-gate pci_msi_state_t *msi_state) 10670Sstevel@tonic-gate { 10680Sstevel@tonic-gate uint64_t ret; 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: dip 0x%p msi_num 0x%x\n", 10710Sstevel@tonic-gate dip, msi_num); 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate if ((ret = hvio_msi_getstate(DIP_TO_HANDLE(dip), 10740Sstevel@tonic-gate msi_num, msi_state)) != H_EOK) { 10750Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10760Sstevel@tonic-gate "hvio_msi_getstate failed, ret 0x%lx\n", ret); 10770Sstevel@tonic-gate return (DDI_FAILURE); 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_getstate: msi_state 0x%x\n", 10810Sstevel@tonic-gate *msi_state); 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate return (DDI_SUCCESS); 10840Sstevel@tonic-gate } 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate /*ARGSUSED*/ 10870Sstevel@tonic-gate int 10880Sstevel@tonic-gate px_lib_msi_setstate(dev_info_t *dip, msinum_t msi_num, 10890Sstevel@tonic-gate pci_msi_state_t msi_state) 10900Sstevel@tonic-gate { 10910Sstevel@tonic-gate uint64_t ret; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msi_setstate: dip 0x%p msi_num 0x%x " 10940Sstevel@tonic-gate "msi_state 0x%x\n", dip, msi_num, msi_state); 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate if ((ret = hvio_msi_setstate(DIP_TO_HANDLE(dip), 10970Sstevel@tonic-gate msi_num, msi_state)) != H_EOK) { 10980Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, 10990Sstevel@tonic-gate "hvio_msi_setstate failed, ret 0x%lx\n", ret); 11000Sstevel@tonic-gate return (DDI_FAILURE); 11010Sstevel@tonic-gate } 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate return (DDI_SUCCESS); 11040Sstevel@tonic-gate } 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate /* 11070Sstevel@tonic-gate * MSG Functions: 11080Sstevel@tonic-gate */ 11090Sstevel@tonic-gate /*ARGSUSED*/ 11100Sstevel@tonic-gate int 11110Sstevel@tonic-gate px_lib_msg_getmsiq(dev_info_t *dip, pcie_msg_type_t msg_type, 11120Sstevel@tonic-gate msiqid_t *msiq_id) 11130Sstevel@tonic-gate { 11140Sstevel@tonic-gate uint64_t ret; 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msg_getmsiq: dip 0x%p msg_type 0x%x\n", 11170Sstevel@tonic-gate dip, msg_type); 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate if ((ret = hvio_msg_getmsiq(DIP_TO_HANDLE(dip), 11200Sstevel@tonic-gate msg_type, msiq_id)) != H_EOK) { 11210Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 11220Sstevel@tonic-gate "hvio_msg_getmsiq failed, ret 0x%lx\n", ret); 11230Sstevel@tonic-gate return (DDI_FAILURE); 11240Sstevel@tonic-gate } 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msg_getmsiq: msiq_id 0x%x\n", 11270Sstevel@tonic-gate *msiq_id); 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate return (DDI_SUCCESS); 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate /*ARGSUSED*/ 11330Sstevel@tonic-gate int 11340Sstevel@tonic-gate px_lib_msg_setmsiq(dev_info_t *dip, pcie_msg_type_t msg_type, 11350Sstevel@tonic-gate msiqid_t msiq_id) 11360Sstevel@tonic-gate { 11370Sstevel@tonic-gate uint64_t ret; 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msi_setstate: dip 0x%p msg_type 0x%x " 11400Sstevel@tonic-gate "msiq_id 0x%x\n", dip, msg_type, msiq_id); 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate if ((ret = hvio_msg_setmsiq(DIP_TO_HANDLE(dip), 11430Sstevel@tonic-gate msg_type, msiq_id)) != H_EOK) { 11440Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 11450Sstevel@tonic-gate "hvio_msg_setmsiq failed, ret 0x%lx\n", ret); 11460Sstevel@tonic-gate return (DDI_FAILURE); 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate return (DDI_SUCCESS); 11500Sstevel@tonic-gate } 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate /*ARGSUSED*/ 11530Sstevel@tonic-gate int 11540Sstevel@tonic-gate px_lib_msg_getvalid(dev_info_t *dip, pcie_msg_type_t msg_type, 11550Sstevel@tonic-gate pcie_msg_valid_state_t *msg_valid_state) 11560Sstevel@tonic-gate { 11570Sstevel@tonic-gate uint64_t ret; 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msg_getvalid: dip 0x%p msg_type 0x%x\n", 11600Sstevel@tonic-gate dip, msg_type); 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate if ((ret = hvio_msg_getvalid(DIP_TO_HANDLE(dip), msg_type, 11630Sstevel@tonic-gate msg_valid_state)) != H_EOK) { 11640Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 11650Sstevel@tonic-gate "hvio_msg_getvalid failed, ret 0x%lx\n", ret); 11660Sstevel@tonic-gate return (DDI_FAILURE); 11670Sstevel@tonic-gate } 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate DBG(DBG_LIB_MSI, dip, "px_lib_msg_getvalid: msg_valid_state 0x%x\n", 11700Sstevel@tonic-gate *msg_valid_state); 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate return (DDI_SUCCESS); 11730Sstevel@tonic-gate } 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate /*ARGSUSED*/ 11760Sstevel@tonic-gate int 11770Sstevel@tonic-gate px_lib_msg_setvalid(dev_info_t *dip, pcie_msg_type_t msg_type, 11780Sstevel@tonic-gate pcie_msg_valid_state_t msg_valid_state) 11790Sstevel@tonic-gate { 11800Sstevel@tonic-gate uint64_t ret; 11810Sstevel@tonic-gate 11820Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, "px_lib_msg_setvalid: dip 0x%p msg_type 0x%x " 11830Sstevel@tonic-gate "msg_valid_state 0x%x\n", dip, msg_type, msg_valid_state); 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate if ((ret = hvio_msg_setvalid(DIP_TO_HANDLE(dip), msg_type, 11860Sstevel@tonic-gate msg_valid_state)) != H_EOK) { 11870Sstevel@tonic-gate DBG(DBG_LIB_MSG, dip, 11880Sstevel@tonic-gate "hvio_msg_setvalid failed, ret 0x%lx\n", ret); 11890Sstevel@tonic-gate return (DDI_FAILURE); 11900Sstevel@tonic-gate } 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate return (DDI_SUCCESS); 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate /* 11960Sstevel@tonic-gate * Suspend/Resume Functions: 11970Sstevel@tonic-gate * Currently unsupported by hypervisor 11980Sstevel@tonic-gate */ 11990Sstevel@tonic-gate int 12000Sstevel@tonic-gate px_lib_suspend(dev_info_t *dip) 12010Sstevel@tonic-gate { 12020Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 12030Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 12040Sstevel@tonic-gate devhandle_t dev_hdl, xbus_dev_hdl; 12050Sstevel@tonic-gate uint64_t ret; 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate DBG(DBG_DETACH, dip, "px_lib_suspend: dip 0x%p\n", dip); 12080Sstevel@tonic-gate 120927Sjchu dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR]; 121027Sjchu xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC]; 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate if ((ret = hvio_suspend(dev_hdl, pxu_p)) == H_EOK) { 12130Sstevel@tonic-gate px_p->px_cb_p->xbc_attachcnt--; 12140Sstevel@tonic-gate if (px_p->px_cb_p->xbc_attachcnt == 0) 12150Sstevel@tonic-gate if ((ret = hvio_cb_suspend(xbus_dev_hdl, pxu_p)) 12160Sstevel@tonic-gate != H_EOK) 12170Sstevel@tonic-gate px_p->px_cb_p->xbc_attachcnt++; 12180Sstevel@tonic-gate } 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate return ((ret != H_EOK) ? DDI_FAILURE: DDI_SUCCESS); 12210Sstevel@tonic-gate } 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate void 12240Sstevel@tonic-gate px_lib_resume(dev_info_t *dip) 12250Sstevel@tonic-gate { 12260Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 12270Sstevel@tonic-gate pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 12280Sstevel@tonic-gate devhandle_t dev_hdl, xbus_dev_hdl; 12290Sstevel@tonic-gate devino_t pec_ino = px_p->px_inos[PX_INTR_PEC]; 12300Sstevel@tonic-gate devino_t xbc_ino = px_p->px_inos[PX_INTR_XBC]; 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "px_lib_resume: dip 0x%p\n", dip); 12330Sstevel@tonic-gate 123427Sjchu dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_CSR]; 123527Sjchu xbus_dev_hdl = (devhandle_t)pxu_p->px_address[PX_REG_XBC]; 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate px_p->px_cb_p->xbc_attachcnt++; 12380Sstevel@tonic-gate if (px_p->px_cb_p->xbc_attachcnt == 1) 12390Sstevel@tonic-gate hvio_cb_resume(dev_hdl, xbus_dev_hdl, xbc_ino, pxu_p); 12400Sstevel@tonic-gate hvio_resume(dev_hdl, pec_ino, pxu_p); 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate /* 12440Sstevel@tonic-gate * PCI tool Functions: 12450Sstevel@tonic-gate * Currently unsupported by hypervisor 12460Sstevel@tonic-gate */ 12470Sstevel@tonic-gate /*ARGSUSED*/ 12480Sstevel@tonic-gate int 12490Sstevel@tonic-gate px_lib_tools_dev_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode) 12500Sstevel@tonic-gate { 12510Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate DBG(DBG_TOOLS, dip, "px_lib_tools_dev_reg_ops: dip 0x%p arg 0x%p " 12540Sstevel@tonic-gate "cmd 0x%x mode 0x%x\n", dip, arg, cmd, mode); 12550Sstevel@tonic-gate 12560Sstevel@tonic-gate return (px_dev_reg_ops(dip, arg, cmd, mode, px_p)); 12570Sstevel@tonic-gate } 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate /*ARGSUSED*/ 12600Sstevel@tonic-gate int 12610Sstevel@tonic-gate px_lib_tools_bus_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode) 12620Sstevel@tonic-gate { 12630Sstevel@tonic-gate DBG(DBG_TOOLS, dip, "px_lib_tools_bus_reg_ops: dip 0x%p arg 0x%p " 12640Sstevel@tonic-gate "cmd 0x%x mode 0x%x\n", dip, arg, cmd, mode); 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate return (px_bus_reg_ops(dip, arg, cmd, mode)); 12670Sstevel@tonic-gate } 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate /*ARGSUSED*/ 12700Sstevel@tonic-gate int 12710Sstevel@tonic-gate px_lib_tools_intr_admn(dev_info_t *dip, void *arg, int cmd, int mode) 12720Sstevel@tonic-gate { 12730Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate DBG(DBG_TOOLS, dip, "px_lib_tools_intr_admn: dip 0x%p arg 0x%p " 12760Sstevel@tonic-gate "cmd 0x%x mode 0x%x\n", dip, arg, cmd, mode); 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate return (px_intr_admn(dip, arg, cmd, mode, px_p)); 12790Sstevel@tonic-gate } 12800Sstevel@tonic-gate 12810Sstevel@tonic-gate /* 12820Sstevel@tonic-gate * Misc Functions: 12830Sstevel@tonic-gate * Currently unsupported by hypervisor 12840Sstevel@tonic-gate */ 12850Sstevel@tonic-gate uint64_t 128627Sjchu px_lib_get_cb(dev_info_t *dip) 12870Sstevel@tonic-gate { 128827Sjchu px_t *px_p = DIP_TO_STATE(dip); 128927Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 129027Sjchu 129127Sjchu return (CSR_XR((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1)); 12920Sstevel@tonic-gate } 12930Sstevel@tonic-gate 12940Sstevel@tonic-gate void 129527Sjchu px_lib_set_cb(dev_info_t *dip, uint64_t val) 12960Sstevel@tonic-gate { 129727Sjchu px_t *px_p = DIP_TO_STATE(dip); 129827Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 129927Sjchu 130027Sjchu CSR_XS((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1, val); 13010Sstevel@tonic-gate } 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate /*ARGSUSED*/ 13040Sstevel@tonic-gate int 13050Sstevel@tonic-gate px_lib_map_vconfig(dev_info_t *dip, 13060Sstevel@tonic-gate ddi_map_req_t *mp, pci_config_offset_t off, 13070Sstevel@tonic-gate pci_regspec_t *rp, caddr_t *addrp) 13080Sstevel@tonic-gate { 13090Sstevel@tonic-gate /* 13100Sstevel@tonic-gate * No special config space access services in this layer. 13110Sstevel@tonic-gate */ 13120Sstevel@tonic-gate return (DDI_FAILURE); 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate 131527Sjchu static void 131627Sjchu px_lib_clr_errs(px_t *px_p, px_pec_t *pec_p) 131727Sjchu { 131827Sjchu dev_info_t *rpdip = px_p->px_dip; 131927Sjchu px_cb_t *cb_p = px_p->px_cb_p; 132027Sjchu int err = PX_OK, ret; 132127Sjchu int acctype = pec_p->pec_safeacc_type; 132227Sjchu ddi_fm_error_t derr; 132327Sjchu 132427Sjchu /* Create the derr */ 132527Sjchu bzero(&derr, sizeof (ddi_fm_error_t)); 132627Sjchu derr.fme_version = DDI_FME_VERSION; 132727Sjchu derr.fme_ena = fm_ena_generate(0, FM_ENA_FMT1); 132827Sjchu derr.fme_flag = acctype; 132927Sjchu 133027Sjchu if (acctype == DDI_FM_ERR_EXPECTED) { 133127Sjchu derr.fme_status = DDI_FM_NONFATAL; 133227Sjchu ndi_fm_acc_err_set(pec_p->pec_acc_hdl, &derr); 133327Sjchu } 133427Sjchu 133527Sjchu mutex_enter(&cb_p->xbc_fm_mutex); 133627Sjchu 133727Sjchu /* send ereport/handle/clear fire registers */ 133827Sjchu err = px_err_handle(px_p, &derr, PX_LIB_CALL, B_TRUE); 133927Sjchu 134027Sjchu /* Check all child devices for errors */ 134127Sjchu ret = ndi_fm_handler_dispatch(rpdip, NULL, &derr); 134227Sjchu 134327Sjchu mutex_exit(&cb_p->xbc_fm_mutex); 134427Sjchu 134527Sjchu /* 134627Sjchu * PX_FATAL_HW indicates a condition recovered from Fatal-Reset, 134727Sjchu * therefore it does not cause panic. 134827Sjchu */ 134927Sjchu if ((err & (PX_FATAL_GOS | PX_FATAL_SW)) || (ret == DDI_FM_FATAL)) 135027Sjchu fm_panic("Fatal System Port Error has occurred\n"); 135127Sjchu } 135227Sjchu 13530Sstevel@tonic-gate #ifdef DEBUG 13540Sstevel@tonic-gate int px_peekfault_cnt = 0; 13550Sstevel@tonic-gate int px_pokefault_cnt = 0; 13560Sstevel@tonic-gate #endif /* DEBUG */ 13570Sstevel@tonic-gate 13580Sstevel@tonic-gate /*ARGSUSED*/ 13590Sstevel@tonic-gate static int 13600Sstevel@tonic-gate px_lib_do_poke(dev_info_t *dip, dev_info_t *rdip, 13610Sstevel@tonic-gate peekpoke_ctlops_t *in_args) 13620Sstevel@tonic-gate { 13630Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 13640Sstevel@tonic-gate px_pec_t *pec_p = px_p->px_pec_p; 13650Sstevel@tonic-gate int err = DDI_SUCCESS; 13660Sstevel@tonic-gate on_trap_data_t otd; 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate mutex_enter(&pec_p->pec_pokefault_mutex); 13690Sstevel@tonic-gate pec_p->pec_ontrap_data = &otd; 137027Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_POKE; 13710Sstevel@tonic-gate 13720Sstevel@tonic-gate /* Set up protected environment. */ 13730Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 13740Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 13750Sstevel@tonic-gate 13760Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&poke_fault; 13770Sstevel@tonic-gate err = do_poke(in_args->size, (void *)in_args->dev_addr, 13780Sstevel@tonic-gate (void *)in_args->host_addr); 13790Sstevel@tonic-gate otd.ot_trampoline = tramp; 13800Sstevel@tonic-gate } else 13810Sstevel@tonic-gate err = DDI_FAILURE; 13820Sstevel@tonic-gate 138327Sjchu px_lib_clr_errs(px_p, pec_p); 138427Sjchu 13850Sstevel@tonic-gate if (otd.ot_trap & OT_DATA_ACCESS) 13860Sstevel@tonic-gate err = DDI_FAILURE; 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate /* Take down protected environment. */ 13890Sstevel@tonic-gate no_trap(); 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate pec_p->pec_ontrap_data = NULL; 139227Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 13930Sstevel@tonic-gate mutex_exit(&pec_p->pec_pokefault_mutex); 13940Sstevel@tonic-gate 13950Sstevel@tonic-gate #ifdef DEBUG 13960Sstevel@tonic-gate if (err == DDI_FAILURE) 13970Sstevel@tonic-gate px_pokefault_cnt++; 13980Sstevel@tonic-gate #endif 13990Sstevel@tonic-gate return (err); 14000Sstevel@tonic-gate } 14010Sstevel@tonic-gate 14020Sstevel@tonic-gate /*ARGSUSED*/ 14030Sstevel@tonic-gate static int 14040Sstevel@tonic-gate px_lib_do_caut_put(dev_info_t *dip, dev_info_t *rdip, 14050Sstevel@tonic-gate peekpoke_ctlops_t *cautacc_ctlops_arg) 14060Sstevel@tonic-gate { 14070Sstevel@tonic-gate size_t size = cautacc_ctlops_arg->size; 14080Sstevel@tonic-gate uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 14090Sstevel@tonic-gate uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 14100Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 14110Sstevel@tonic-gate size_t repcount = cautacc_ctlops_arg->repcount; 14120Sstevel@tonic-gate uint_t flags = cautacc_ctlops_arg->flags; 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 14150Sstevel@tonic-gate px_pec_t *pec_p = px_p->px_pec_p; 14160Sstevel@tonic-gate int err = DDI_SUCCESS; 14170Sstevel@tonic-gate 141827Sjchu /* 141927Sjchu * Note that i_ndi_busop_access_enter ends up grabbing the pokefault 142027Sjchu * mutex. 142127Sjchu */ 14220Sstevel@tonic-gate i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 14230Sstevel@tonic-gate 142427Sjchu pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap; 142527Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED; 142627Sjchu hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 14270Sstevel@tonic-gate 14280Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 14290Sstevel@tonic-gate for (; repcount; repcount--) { 14300Sstevel@tonic-gate switch (size) { 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate case sizeof (uint8_t): 14330Sstevel@tonic-gate i_ddi_put8(hp, (uint8_t *)dev_addr, 14340Sstevel@tonic-gate *(uint8_t *)host_addr); 14350Sstevel@tonic-gate break; 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate case sizeof (uint16_t): 14380Sstevel@tonic-gate i_ddi_put16(hp, (uint16_t *)dev_addr, 14390Sstevel@tonic-gate *(uint16_t *)host_addr); 14400Sstevel@tonic-gate break; 14410Sstevel@tonic-gate 14420Sstevel@tonic-gate case sizeof (uint32_t): 14430Sstevel@tonic-gate i_ddi_put32(hp, (uint32_t *)dev_addr, 14440Sstevel@tonic-gate *(uint32_t *)host_addr); 14450Sstevel@tonic-gate break; 14460Sstevel@tonic-gate 14470Sstevel@tonic-gate case sizeof (uint64_t): 14480Sstevel@tonic-gate i_ddi_put64(hp, (uint64_t *)dev_addr, 14490Sstevel@tonic-gate *(uint64_t *)host_addr); 14500Sstevel@tonic-gate break; 14510Sstevel@tonic-gate } 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate host_addr += size; 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 14560Sstevel@tonic-gate dev_addr += size; 14570Sstevel@tonic-gate 145827Sjchu px_lib_clr_errs(px_p, pec_p); 145927Sjchu 14600Sstevel@tonic-gate if (pec_p->pec_ontrap_data->ot_trap & OT_DATA_ACCESS) { 14610Sstevel@tonic-gate err = DDI_FAILURE; 14620Sstevel@tonic-gate #ifdef DEBUG 14630Sstevel@tonic-gate px_pokefault_cnt++; 14640Sstevel@tonic-gate #endif 14650Sstevel@tonic-gate break; 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate } 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate i_ddi_notrap((ddi_acc_handle_t)hp); 14710Sstevel@tonic-gate pec_p->pec_ontrap_data = NULL; 147227Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 14730Sstevel@tonic-gate i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 14740Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate return (err); 14770Sstevel@tonic-gate } 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate 14800Sstevel@tonic-gate int 14810Sstevel@tonic-gate px_lib_ctlops_poke(dev_info_t *dip, dev_info_t *rdip, 14820Sstevel@tonic-gate peekpoke_ctlops_t *in_args) 14830Sstevel@tonic-gate { 14840Sstevel@tonic-gate return (in_args->handle ? px_lib_do_caut_put(dip, rdip, in_args) : 14850Sstevel@tonic-gate px_lib_do_poke(dip, rdip, in_args)); 14860Sstevel@tonic-gate } 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate /*ARGSUSED*/ 14900Sstevel@tonic-gate static int 14910Sstevel@tonic-gate px_lib_do_peek(dev_info_t *dip, peekpoke_ctlops_t *in_args) 14920Sstevel@tonic-gate { 149327Sjchu px_t *px_p = DIP_TO_STATE(dip); 149427Sjchu px_pec_t *pec_p = px_p->px_pec_p; 14950Sstevel@tonic-gate int err = DDI_SUCCESS; 14960Sstevel@tonic-gate on_trap_data_t otd; 14970Sstevel@tonic-gate 149827Sjchu mutex_enter(&pec_p->pec_pokefault_mutex); 149927Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK; 150027Sjchu 15010Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 15020Sstevel@tonic-gate uintptr_t tramp = otd.ot_trampoline; 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate otd.ot_trampoline = (uintptr_t)&peek_fault; 15050Sstevel@tonic-gate err = do_peek(in_args->size, (void *)in_args->dev_addr, 15060Sstevel@tonic-gate (void *)in_args->host_addr); 15070Sstevel@tonic-gate otd.ot_trampoline = tramp; 15080Sstevel@tonic-gate } else 15090Sstevel@tonic-gate err = DDI_FAILURE; 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate no_trap(); 151227Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 151327Sjchu mutex_exit(&pec_p->pec_pokefault_mutex); 15140Sstevel@tonic-gate 15150Sstevel@tonic-gate #ifdef DEBUG 15160Sstevel@tonic-gate if (err == DDI_FAILURE) 15170Sstevel@tonic-gate px_peekfault_cnt++; 15180Sstevel@tonic-gate #endif 15190Sstevel@tonic-gate return (err); 15200Sstevel@tonic-gate } 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate static int 15240Sstevel@tonic-gate px_lib_do_caut_get(dev_info_t *dip, peekpoke_ctlops_t *cautacc_ctlops_arg) 15250Sstevel@tonic-gate { 15260Sstevel@tonic-gate size_t size = cautacc_ctlops_arg->size; 15270Sstevel@tonic-gate uintptr_t dev_addr = cautacc_ctlops_arg->dev_addr; 15280Sstevel@tonic-gate uintptr_t host_addr = cautacc_ctlops_arg->host_addr; 15290Sstevel@tonic-gate ddi_acc_impl_t *hp = (ddi_acc_impl_t *)cautacc_ctlops_arg->handle; 15300Sstevel@tonic-gate size_t repcount = cautacc_ctlops_arg->repcount; 15310Sstevel@tonic-gate uint_t flags = cautacc_ctlops_arg->flags; 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate px_t *px_p = DIP_TO_STATE(dip); 15340Sstevel@tonic-gate px_pec_t *pec_p = px_p->px_pec_p; 15350Sstevel@tonic-gate int err = DDI_SUCCESS; 15360Sstevel@tonic-gate 153727Sjchu /* 153827Sjchu * Note that i_ndi_busop_access_enter ends up grabbing the pokefault 153927Sjchu * mutex. 154027Sjchu */ 154127Sjchu i_ndi_busop_access_enter(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 154227Sjchu 154327Sjchu pec_p->pec_ontrap_data = (on_trap_data_t *)hp->ahi_err->err_ontrap; 154427Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_EXPECTED; 15450Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_EXPECTED; 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate if (repcount == 1) { 15480Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 15490Sstevel@tonic-gate i_ddi_caut_get(size, (void *)dev_addr, 15500Sstevel@tonic-gate (void *)host_addr); 15510Sstevel@tonic-gate } else { 15520Sstevel@tonic-gate int i; 15530Sstevel@tonic-gate uint8_t *ff_addr = (uint8_t *)host_addr; 15540Sstevel@tonic-gate for (i = 0; i < size; i++) 15550Sstevel@tonic-gate *ff_addr++ = 0xff; 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate err = DDI_FAILURE; 15580Sstevel@tonic-gate #ifdef DEBUG 15590Sstevel@tonic-gate px_peekfault_cnt++; 15600Sstevel@tonic-gate #endif 15610Sstevel@tonic-gate } 15620Sstevel@tonic-gate } else { 15630Sstevel@tonic-gate if (!i_ddi_ontrap((ddi_acc_handle_t)hp)) { 15640Sstevel@tonic-gate for (; repcount; repcount--) { 15650Sstevel@tonic-gate i_ddi_caut_get(size, (void *)dev_addr, 15660Sstevel@tonic-gate (void *)host_addr); 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate host_addr += size; 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate if (flags == DDI_DEV_AUTOINCR) 15710Sstevel@tonic-gate dev_addr += size; 15720Sstevel@tonic-gate } 15730Sstevel@tonic-gate } else { 15740Sstevel@tonic-gate err = DDI_FAILURE; 15750Sstevel@tonic-gate #ifdef DEBUG 15760Sstevel@tonic-gate px_peekfault_cnt++; 15770Sstevel@tonic-gate #endif 15780Sstevel@tonic-gate } 15790Sstevel@tonic-gate } 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate i_ddi_notrap((ddi_acc_handle_t)hp); 15820Sstevel@tonic-gate pec_p->pec_ontrap_data = NULL; 158327Sjchu pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 15840Sstevel@tonic-gate i_ndi_busop_access_exit(hp->ahi_common.ah_dip, (ddi_acc_handle_t)hp); 15850Sstevel@tonic-gate hp->ahi_err->err_expected = DDI_FM_ERR_UNEXPECTED; 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate return (err); 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate /*ARGSUSED*/ 15910Sstevel@tonic-gate int 15920Sstevel@tonic-gate px_lib_ctlops_peek(dev_info_t *dip, dev_info_t *rdip, 15930Sstevel@tonic-gate peekpoke_ctlops_t *in_args, void *result) 15940Sstevel@tonic-gate { 15950Sstevel@tonic-gate result = (void *)in_args->host_addr; 15960Sstevel@tonic-gate return (in_args->handle ? px_lib_do_caut_get(dip, in_args) : 15970Sstevel@tonic-gate px_lib_do_peek(dip, in_args)); 15980Sstevel@tonic-gate } 1599118Sjchu 16000Sstevel@tonic-gate /* 16010Sstevel@tonic-gate * implements PPM interface 16020Sstevel@tonic-gate */ 16030Sstevel@tonic-gate int 16040Sstevel@tonic-gate px_lib_pmctl(int cmd, px_t *px_p) 16050Sstevel@tonic-gate { 16060Sstevel@tonic-gate ASSERT((cmd & ~PPMREQ_MASK) == PPMREQ); 16070Sstevel@tonic-gate switch (cmd) { 16080Sstevel@tonic-gate case PPMREQ_PRE_PWR_OFF: 16090Sstevel@tonic-gate /* 16100Sstevel@tonic-gate * Currently there is no device power management for 16110Sstevel@tonic-gate * the root complex (fire). When there is we need to make 16120Sstevel@tonic-gate * sure that it is at full power before trying to send the 16130Sstevel@tonic-gate * PME_Turn_Off message. 16140Sstevel@tonic-gate */ 16150Sstevel@tonic-gate DBG(DBG_PWR, px_p->px_dip, 16160Sstevel@tonic-gate "ioctl: request to send PME_Turn_Off\n"); 16170Sstevel@tonic-gate return (px_goto_l23ready(px_p)); 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate case PPMREQ_PRE_PWR_ON: 1620118Sjchu DBG(DBG_PWR, px_p->px_dip, "ioctl: PRE_PWR_ON request\n"); 1621118Sjchu return (px_pre_pwron_check(px_p)); 1622118Sjchu 16230Sstevel@tonic-gate case PPMREQ_POST_PWR_ON: 1624118Sjchu DBG(DBG_PWR, px_p->px_dip, "ioctl: POST_PWR_ON request\n"); 1625118Sjchu return (px_goto_l0(px_p)); 16260Sstevel@tonic-gate 16270Sstevel@tonic-gate default: 16280Sstevel@tonic-gate return (DDI_FAILURE); 16290Sstevel@tonic-gate } 16300Sstevel@tonic-gate } 16310Sstevel@tonic-gate 1632287Smg140465 #define MSEC_TO_USEC 1000 1633287Smg140465 16340Sstevel@tonic-gate /* 16350Sstevel@tonic-gate * sends PME_Turn_Off message to put the link in L2/L3 ready state. 16360Sstevel@tonic-gate * called by px_ioctl. 16370Sstevel@tonic-gate * returns DDI_SUCCESS or DDI_FAILURE 16380Sstevel@tonic-gate * 1. Wait for link to be in L1 state (link status reg) 16390Sstevel@tonic-gate * 2. write to PME_Turn_off reg to boradcast 16400Sstevel@tonic-gate * 3. set timeout 16410Sstevel@tonic-gate * 4. If timeout, return failure. 16420Sstevel@tonic-gate * 5. If PM_TO_Ack, wait till link is in L2/L3 ready 16430Sstevel@tonic-gate */ 16440Sstevel@tonic-gate static int 16450Sstevel@tonic-gate px_goto_l23ready(px_t *px_p) 16460Sstevel@tonic-gate { 16470Sstevel@tonic-gate pcie_pwr_t *pwr_p; 164827Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 164927Sjchu caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 16500Sstevel@tonic-gate int ret = DDI_SUCCESS; 16510Sstevel@tonic-gate clock_t end, timeleft; 1652118Sjchu int mutex_held = 1; 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate /* If no PM info, return failure */ 16550Sstevel@tonic-gate if (!PCIE_PMINFO(px_p->px_dip) || 16560Sstevel@tonic-gate !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) 16570Sstevel@tonic-gate return (DDI_FAILURE); 16580Sstevel@tonic-gate 16590Sstevel@tonic-gate mutex_enter(&pwr_p->pwr_lock); 1660118Sjchu mutex_enter(&px_p->px_l23ready_lock); 16610Sstevel@tonic-gate /* Clear the PME_To_ACK receieved flag */ 1662118Sjchu px_p->px_pm_flags &= ~PX_PMETOACK_RECVD; 1663287Smg140465 /* 1664287Smg140465 * When P25 is the downstream device, after receiving 1665287Smg140465 * PME_To_ACK, fire will go to Detect state, which causes 1666287Smg140465 * the link down event. Inform FMA that this is expected. 1667287Smg140465 * In case of all other cards complaint with the pci express 1668287Smg140465 * spec, this will happen when the power is re-applied. FMA 1669287Smg140465 * code will clear this flag after one instance of LDN. Since 1670287Smg140465 * there will not be a LDN event for the spec compliant cards, 1671287Smg140465 * we need to clear the flag after receiving PME_To_ACK. 1672287Smg140465 */ 1673287Smg140465 px_p->px_pm_flags |= PX_LDN_EXPECTED; 16740Sstevel@tonic-gate if (px_send_pme_turnoff(csr_base) != DDI_SUCCESS) { 16750Sstevel@tonic-gate ret = DDI_FAILURE; 16760Sstevel@tonic-gate goto l23ready_done; 16770Sstevel@tonic-gate } 1678118Sjchu px_p->px_pm_flags |= PX_PME_TURNOFF_PENDING; 16790Sstevel@tonic-gate 16800Sstevel@tonic-gate end = ddi_get_lbolt() + drv_usectohz(px_pme_to_ack_timeout); 1681118Sjchu while (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { 1682118Sjchu timeleft = cv_timedwait(&px_p->px_l23ready_cv, 1683118Sjchu &px_p->px_l23ready_lock, end); 16840Sstevel@tonic-gate /* 16850Sstevel@tonic-gate * if cv_timedwait returns -1, it is either 16860Sstevel@tonic-gate * 1) timed out or 16870Sstevel@tonic-gate * 2) there was a pre-mature wakeup but by the time 16880Sstevel@tonic-gate * cv_timedwait is called again end < lbolt i.e. 16890Sstevel@tonic-gate * end is in the past. 16900Sstevel@tonic-gate * 3) By the time we make first cv_timedwait call, 16910Sstevel@tonic-gate * end < lbolt is true. 16920Sstevel@tonic-gate */ 16930Sstevel@tonic-gate if (timeleft == -1) 16940Sstevel@tonic-gate break; 16950Sstevel@tonic-gate } 1696118Sjchu if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { 16970Sstevel@tonic-gate /* 16980Sstevel@tonic-gate * Either timedout or interrupt didn't get a 16990Sstevel@tonic-gate * chance to grab the mutex and set the flag. 17000Sstevel@tonic-gate * release the mutex and delay for sometime. 17010Sstevel@tonic-gate * This will 1) give a chance for interrupt to 17020Sstevel@tonic-gate * set the flag 2) creates a delay between two 17030Sstevel@tonic-gate * consequetive requests. 17040Sstevel@tonic-gate */ 1705118Sjchu mutex_exit(&px_p->px_l23ready_lock); 1706287Smg140465 delay(drv_usectohz(50 * MSEC_TO_USEC)); 1707118Sjchu mutex_held = 0; 1708118Sjchu if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { 17090Sstevel@tonic-gate ret = DDI_FAILURE; 17100Sstevel@tonic-gate DBG(DBG_PWR, px_p->px_dip, " Timed out while waiting" 17110Sstevel@tonic-gate " for PME_TO_ACK\n"); 17120Sstevel@tonic-gate } 17130Sstevel@tonic-gate } 1714287Smg140465 px_p->px_pm_flags &= 1715287Smg140465 ~(PX_PME_TURNOFF_PENDING | PX_PMETOACK_RECVD | PX_LDN_EXPECTED); 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate l23ready_done: 1718118Sjchu if (mutex_held) 1719118Sjchu mutex_exit(&px_p->px_l23ready_lock); 1720118Sjchu /* 1721118Sjchu * Wait till link is in L1 idle, if sending PME_Turn_Off 1722118Sjchu * was succesful. 1723118Sjchu */ 1724118Sjchu if (ret == DDI_SUCCESS) { 1725118Sjchu if (px_link_wait4l1idle(csr_base) != DDI_SUCCESS) { 1726118Sjchu DBG(DBG_PWR, px_p->px_dip, " Link is not at L1" 1727287Smg140465 " even though we received PME_To_ACK.\n"); 1728287Smg140465 /* 1729287Smg140465 * Workaround for hardware bug with P25. 1730287Smg140465 * Due to a hardware bug with P25, link state 1731287Smg140465 * will be Detect state rather than L1 after 1732287Smg140465 * link is transitioned to L23Ready state. Since 1733287Smg140465 * we don't know whether link is L23ready state 1734287Smg140465 * without Fire's state being L1_idle, we delay 1735287Smg140465 * here just to make sure that we wait till link 1736287Smg140465 * is transitioned to L23Ready state. 1737287Smg140465 */ 1738287Smg140465 delay(drv_usectohz(100 * MSEC_TO_USEC)); 1739287Smg140465 } 1740287Smg140465 pwr_p->pwr_link_lvl = PM_LEVEL_L3; 1741118Sjchu 1742118Sjchu } 17430Sstevel@tonic-gate mutex_exit(&pwr_p->pwr_lock); 17440Sstevel@tonic-gate return (ret); 17450Sstevel@tonic-gate } 17460Sstevel@tonic-gate 1747118Sjchu /* 1748118Sjchu * Message interrupt handler intended to be shared for both 1749118Sjchu * PME and PME_TO_ACK msg handling, currently only handles 1750118Sjchu * PME_To_ACK message. 1751118Sjchu */ 1752118Sjchu uint_t 1753118Sjchu px_pmeq_intr(caddr_t arg) 1754118Sjchu { 1755118Sjchu px_t *px_p = (px_t *)arg; 1756118Sjchu 1757287Smg140465 DBG(DBG_PWR, px_p->px_dip, " PME_To_ACK received \n"); 1758118Sjchu mutex_enter(&px_p->px_l23ready_lock); 1759118Sjchu cv_broadcast(&px_p->px_l23ready_cv); 1760118Sjchu if (px_p->px_pm_flags & PX_PME_TURNOFF_PENDING) { 1761118Sjchu px_p->px_pm_flags |= PX_PMETOACK_RECVD; 1762118Sjchu } else { 1763118Sjchu /* 1764118Sjchu * This maybe the second ack received. If so then, 1765118Sjchu * we should be receiving it during wait4L1 stage. 1766118Sjchu */ 1767118Sjchu px_p->px_pmetoack_ignored++; 1768118Sjchu } 1769118Sjchu mutex_exit(&px_p->px_l23ready_lock); 1770118Sjchu return (DDI_INTR_CLAIMED); 1771118Sjchu } 1772118Sjchu 1773118Sjchu static int 1774118Sjchu px_pre_pwron_check(px_t *px_p) 1775118Sjchu { 1776118Sjchu pcie_pwr_t *pwr_p; 1777118Sjchu 1778118Sjchu /* If no PM info, return failure */ 1779118Sjchu if (!PCIE_PMINFO(px_p->px_dip) || 1780118Sjchu !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) 1781118Sjchu return (DDI_FAILURE); 1782118Sjchu 1783287Smg140465 /* 1784287Smg140465 * For the spec compliant downstream cards link down 1785287Smg140465 * is expected when the device is powered on. 1786287Smg140465 */ 1787287Smg140465 px_p->px_pm_flags |= PX_LDN_EXPECTED; 1788118Sjchu return (pwr_p->pwr_link_lvl == PM_LEVEL_L3 ? DDI_SUCCESS : DDI_FAILURE); 1789118Sjchu } 1790118Sjchu 1791118Sjchu static int 1792118Sjchu px_goto_l0(px_t *px_p) 1793118Sjchu { 1794118Sjchu pcie_pwr_t *pwr_p; 1795118Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 1796118Sjchu caddr_t csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 1797118Sjchu int ret = DDI_SUCCESS; 1798118Sjchu clock_t end, timeleft; 1799118Sjchu int mutex_held = 1; 1800118Sjchu 1801118Sjchu /* If no PM info, return failure */ 1802118Sjchu if (!PCIE_PMINFO(px_p->px_dip) || 1803118Sjchu !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) 1804118Sjchu return (DDI_FAILURE); 1805118Sjchu 1806118Sjchu mutex_enter(&pwr_p->pwr_lock); 1807118Sjchu mutex_enter(&px_p->px_lupsoft_lock); 1808118Sjchu /* Clear the LINKUP_RECVD receieved flag */ 1809118Sjchu px_p->px_pm_flags &= ~PX_LINKUP_RECVD; 1810287Smg140465 /* 1811287Smg140465 * Set flags LUP_EXPECTED to inform FMA code that LUP is 1812287Smg140465 * expected as part of link training and no ereports should 1813287Smg140465 * be posted for this event. FMA code will clear this flag 1814287Smg140465 * after one instance of this event. In case of P25, there 1815287Smg140465 * will not be a LDN event. So clear the flag set at PRE_PWRON 1816287Smg140465 * time. 1817287Smg140465 */ 1818287Smg140465 px_p->px_pm_flags |= PX_LUP_EXPECTED; 1819287Smg140465 px_p->px_pm_flags &= ~PX_LDN_EXPECTED; 1820118Sjchu if (px_link_retrain(csr_base) != DDI_SUCCESS) { 1821118Sjchu ret = DDI_FAILURE; 1822118Sjchu goto l0_done; 1823118Sjchu } 1824118Sjchu px_p->px_pm_flags |= PX_LINKUP_PENDING; 1825118Sjchu 1826118Sjchu end = ddi_get_lbolt() + drv_usectohz(px_linkup_timeout); 1827118Sjchu while (!(px_p->px_pm_flags & PX_LINKUP_RECVD)) { 1828118Sjchu timeleft = cv_timedwait(&px_p->px_lup_cv, 1829118Sjchu &px_p->px_lupsoft_lock, end); 1830118Sjchu /* 1831118Sjchu * if cv_timedwait returns -1, it is either 1832118Sjchu * 1) timed out or 1833118Sjchu * 2) there was a pre-mature wakeup but by the time 1834118Sjchu * cv_timedwait is called again end < lbolt i.e. 1835118Sjchu * end is in the past. 1836118Sjchu * 3) By the time we make first cv_timedwait call, 1837118Sjchu * end < lbolt is true. 1838118Sjchu */ 1839118Sjchu if (timeleft == -1) 1840118Sjchu break; 1841118Sjchu } 1842118Sjchu if (!(px_p->px_pm_flags & PX_LINKUP_RECVD)) { 1843118Sjchu /* 1844118Sjchu * Either timedout or interrupt didn't get a 1845118Sjchu * chance to grab the mutex and set the flag. 1846118Sjchu * release the mutex and delay for sometime. 1847118Sjchu * This will 1) give a chance for interrupt to 1848118Sjchu * set the flag 2) creates a delay between two 1849118Sjchu * consequetive requests. 1850118Sjchu */ 1851118Sjchu mutex_exit(&px_p->px_lupsoft_lock); 1852118Sjchu mutex_held = 0; 1853287Smg140465 delay(drv_usectohz(50 * MSEC_TO_USEC)); 1854118Sjchu if (!(px_p->px_pm_flags & PX_LINKUP_RECVD)) { 1855118Sjchu ret = DDI_FAILURE; 1856118Sjchu DBG(DBG_PWR, px_p->px_dip, " Timed out while waiting" 1857118Sjchu " for link up\n"); 1858118Sjchu } 1859118Sjchu } 1860287Smg140465 px_p->px_pm_flags &= 1861287Smg140465 ~(PX_LINKUP_PENDING | PX_LINKUP_RECVD | PX_LUP_EXPECTED); 1862118Sjchu 1863118Sjchu l0_done: 1864118Sjchu if (mutex_held) 1865118Sjchu mutex_exit(&px_p->px_lupsoft_lock); 1866287Smg140465 px_enable_detect_quiet(csr_base); 1867118Sjchu if (ret == DDI_SUCCESS) 1868287Smg140465 pwr_p->pwr_link_lvl = PM_LEVEL_L0; 1869118Sjchu mutex_exit(&pwr_p->pwr_lock); 1870118Sjchu return (ret); 1871118Sjchu } 1872118Sjchu 1873118Sjchu uint_t 1874118Sjchu px_lup_softintr(caddr_t arg) 1875118Sjchu { 1876118Sjchu px_t *px_p = (px_t *)arg; 1877118Sjchu 1878287Smg140465 DBG(DBG_PWR, px_p->px_dip, " Link up soft interrupt received \n"); 1879118Sjchu mutex_enter(&px_p->px_lup_lock); 1880118Sjchu if (!(px_p->px_lupsoft_pending > 0)) { 1881118Sjchu /* Spurious */ 1882118Sjchu mutex_exit(&px_p->px_lup_lock); 1883118Sjchu return (DDI_INTR_UNCLAIMED); 1884118Sjchu } 1885118Sjchu px_p->px_lupsoft_pending--; 1886118Sjchu if (px_p->px_lupsoft_pending > 0) { 1887118Sjchu /* More than one lup soft intr posted - unlikely */ 1888118Sjchu mutex_exit(&px_p->px_lup_lock); 1889118Sjchu return (DDI_INTR_UNCLAIMED); 1890118Sjchu } 1891118Sjchu mutex_exit(&px_p->px_lup_lock); 1892118Sjchu 1893118Sjchu mutex_enter(&px_p->px_lupsoft_lock); 1894118Sjchu cv_broadcast(&px_p->px_lup_cv); 1895118Sjchu if (px_p->px_pm_flags & PX_LINKUP_PENDING) { 1896118Sjchu px_p->px_pm_flags |= PX_LINKUP_RECVD; 1897118Sjchu } else { 1898118Sjchu /* Nobody waiting for this! */ 1899118Sjchu px_p->px_lup_ignored++; 1900118Sjchu } 1901118Sjchu mutex_exit(&px_p->px_lupsoft_lock); 1902118Sjchu return (DDI_INTR_CLAIMED); 1903118Sjchu } 19040Sstevel@tonic-gate 19050Sstevel@tonic-gate /* 19060Sstevel@tonic-gate * Extract the drivers binding name to identify which chip we're binding to. 19070Sstevel@tonic-gate * Whenever a new bus bridge is created, the driver alias entry should be 19080Sstevel@tonic-gate * added here to identify the device if needed. If a device isn't added, 19090Sstevel@tonic-gate * the identity defaults to PX_CHIP_UNIDENTIFIED. 19100Sstevel@tonic-gate */ 19110Sstevel@tonic-gate static uint32_t 19120Sstevel@tonic-gate px_identity_chip(px_t *px_p) 19130Sstevel@tonic-gate { 19140Sstevel@tonic-gate dev_info_t *dip = px_p->px_dip; 19150Sstevel@tonic-gate char *name = ddi_binding_name(dip); 19160Sstevel@tonic-gate uint32_t revision = 0; 19170Sstevel@tonic-gate 19180Sstevel@tonic-gate revision = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 19190Sstevel@tonic-gate "module-revision#", 0); 19200Sstevel@tonic-gate 19210Sstevel@tonic-gate /* Check for Fire driver binding name */ 1922226Set142600 if ((strcmp(name, "pci108e,80f0") == 0) || 1923226Set142600 (strcmp(name, "pciex108e,80f0") == 0)) { 19240Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "px_identity_chip: %s%d: " 19250Sstevel@tonic-gate "name %s module-revision %d\n", ddi_driver_name(dip), 19260Sstevel@tonic-gate ddi_get_instance(dip), name, revision); 19270Sstevel@tonic-gate 19280Sstevel@tonic-gate return (PX_CHIP_ID(PX_CHIP_FIRE, revision, 0x00)); 19290Sstevel@tonic-gate } 19300Sstevel@tonic-gate 19310Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "%s%d: Unknown PCI Express Host bridge %s %x\n", 19320Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), name, revision); 19330Sstevel@tonic-gate 19340Sstevel@tonic-gate return (PX_CHIP_UNIDENTIFIED); 19350Sstevel@tonic-gate } 193627Sjchu 193727Sjchu int 193827Sjchu px_err_add_intr(px_fault_t *px_fault_p) 193927Sjchu { 194027Sjchu dev_info_t *dip = px_fault_p->px_fh_dip; 194127Sjchu px_t *px_p = DIP_TO_STATE(dip); 194227Sjchu 194327Sjchu VERIFY(add_ivintr(px_fault_p->px_fh_sysino, PX_ERR_PIL, 194427Sjchu px_fault_p->px_err_func, (caddr_t)px_fault_p, NULL) == 0); 194527Sjchu 194627Sjchu px_ib_intr_enable(px_p, intr_dist_cpuid(), px_fault_p->px_intr_ino); 194727Sjchu 194827Sjchu return (DDI_SUCCESS); 194927Sjchu } 195027Sjchu 195127Sjchu void 195227Sjchu px_err_rem_intr(px_fault_t *px_fault_p) 195327Sjchu { 195427Sjchu dev_info_t *dip = px_fault_p->px_fh_dip; 195527Sjchu px_t *px_p = DIP_TO_STATE(dip); 195627Sjchu 195727Sjchu rem_ivintr(px_fault_p->px_fh_sysino, NULL); 195827Sjchu 195927Sjchu px_ib_intr_disable(px_p->px_ib_p, px_fault_p->px_intr_ino, 196027Sjchu IB_INTR_WAIT); 196127Sjchu } 196227Sjchu 196327Sjchu #ifdef FMA 196427Sjchu void 196527Sjchu px_fill_rc_status(px_fault_t *px_fault_p, pciex_rc_error_regs_t *rc_status) 196627Sjchu { 196727Sjchu /* populate the rc_status by reading the registers - TBD */ 196827Sjchu } 196927Sjchu #endif /* FMA */ 1970383Set142600 1971383Set142600 /* 1972383Set142600 * Unprotected raw reads/writes of fabric device's config space. 1973383Set142600 * Only used for temporary PCI-E Fabric Error Handling. 1974383Set142600 */ 1975383Set142600 uint32_t 1976383Set142600 px_fab_get(px_t *px_p, pcie_req_id_t bdf, uint16_t offset) { 1977383Set142600 px_ranges_t *rp = px_p->px_ranges_p; 1978383Set142600 uint64_t range_prop, base_addr; 1979383Set142600 int bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG); 1980383Set142600 uint32_t val; 1981383Set142600 1982383Set142600 /* Get Fire's Physical Base Address */ 1983383Set142600 range_prop = (((uint64_t)(rp[bank].parent_high & 0x7ff)) << 32) | 1984383Set142600 rp[bank].parent_low; 1985383Set142600 1986383Set142600 /* Get config space first. */ 1987383Set142600 base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset); 1988383Set142600 1989383Set142600 val = ldphysio(base_addr); 1990383Set142600 1991383Set142600 return (LE_32(val)); 1992383Set142600 } 1993383Set142600 1994383Set142600 void 1995383Set142600 px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset, 1996383Set142600 uint32_t val) { 1997383Set142600 px_ranges_t *rp = px_p->px_ranges_p; 1998383Set142600 uint64_t range_prop, base_addr; 1999383Set142600 int bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG); 2000383Set142600 2001383Set142600 /* Get Fire's Physical Base Address */ 2002383Set142600 range_prop = (((uint64_t)(rp[bank].parent_high & 0x7ff)) << 32) | 2003383Set142600 rp[bank].parent_low; 2004383Set142600 2005383Set142600 /* Get config space first. */ 2006383Set142600 base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset); 2007383Set142600 2008383Set142600 stphysio(base_addr, LE_32(val)); 2009383Set142600 } 2010*435Sjchu 2011*435Sjchu /* 2012*435Sjchu * cpr callback 2013*435Sjchu * 2014*435Sjchu * disable fabric error msg interrupt prior to suspending 2015*435Sjchu * all device drivers; re-enable fabric error msg interrupt 2016*435Sjchu * after all devices are resumed. 2017*435Sjchu */ 2018*435Sjchu static boolean_t 2019*435Sjchu px_cpr_callb(void *arg, int code) 2020*435Sjchu { 2021*435Sjchu px_t *px_p = (px_t *)arg; 2022*435Sjchu px_ib_t *ib_p = px_p->px_ib_p; 2023*435Sjchu px_pec_t *pec_p = px_p->px_pec_p; 2024*435Sjchu pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; 2025*435Sjchu caddr_t csr_base; 2026*435Sjchu devino_t ce_ino, nf_ino, f_ino; 2027*435Sjchu px_ib_ino_info_t *ce_ino_p, *nf_ino_p, *f_ino_p; 2028*435Sjchu uint64_t imu_log_enable, imu_intr_enable; 2029*435Sjchu uint64_t imu_log_mask, imu_intr_mask; 2030*435Sjchu 2031*435Sjchu ce_ino = px_msiqid_to_devino(px_p, pec_p->pec_corr_msg_msiq_id); 2032*435Sjchu nf_ino = px_msiqid_to_devino(px_p, pec_p->pec_non_fatal_msg_msiq_id); 2033*435Sjchu f_ino = px_msiqid_to_devino(px_p, pec_p->pec_fatal_msg_msiq_id); 2034*435Sjchu csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; 2035*435Sjchu 2036*435Sjchu imu_log_enable = CSR_XR(csr_base, IMU_ERROR_LOG_ENABLE); 2037*435Sjchu imu_intr_enable = CSR_XR(csr_base, IMU_INTERRUPT_ENABLE); 2038*435Sjchu 2039*435Sjchu imu_log_mask = BITMASK(IMU_ERROR_LOG_ENABLE_FATAL_MES_NOT_EN_LOG_EN) | 2040*435Sjchu BITMASK(IMU_ERROR_LOG_ENABLE_NONFATAL_MES_NOT_EN_LOG_EN) | 2041*435Sjchu BITMASK(IMU_ERROR_LOG_ENABLE_COR_MES_NOT_EN_LOG_EN); 2042*435Sjchu 2043*435Sjchu imu_intr_mask = 2044*435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_S_INT_EN) | 2045*435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_S_INT_EN) | 2046*435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_S_INT_EN) | 2047*435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_FATAL_MES_NOT_EN_P_INT_EN) | 2048*435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_NONFATAL_MES_NOT_EN_P_INT_EN) | 2049*435Sjchu BITMASK(IMU_INTERRUPT_ENABLE_COR_MES_NOT_EN_P_INT_EN); 2050*435Sjchu 2051*435Sjchu switch (code) { 2052*435Sjchu case CB_CODE_CPR_CHKPT: 2053*435Sjchu /* disable imu rbne on corr/nonfatal/fatal errors */ 2054*435Sjchu CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE, 2055*435Sjchu imu_log_enable & (~imu_log_mask)); 2056*435Sjchu 2057*435Sjchu CSR_XS(csr_base, IMU_INTERRUPT_ENABLE, 2058*435Sjchu imu_intr_enable & (~imu_intr_mask)); 2059*435Sjchu 2060*435Sjchu /* disable CORR intr mapping */ 2061*435Sjchu px_ib_intr_disable(ib_p, ce_ino, IB_INTR_NOWAIT); 2062*435Sjchu 2063*435Sjchu /* disable NON FATAL intr mapping */ 2064*435Sjchu px_ib_intr_disable(ib_p, nf_ino, IB_INTR_NOWAIT); 2065*435Sjchu 2066*435Sjchu /* disable FATAL intr mapping */ 2067*435Sjchu px_ib_intr_disable(ib_p, f_ino, IB_INTR_NOWAIT); 2068*435Sjchu 2069*435Sjchu break; 2070*435Sjchu 2071*435Sjchu case CB_CODE_CPR_RESUME: 2072*435Sjchu mutex_enter(&ib_p->ib_ino_lst_mutex); 2073*435Sjchu 2074*435Sjchu ce_ino_p = px_ib_locate_ino(ib_p, ce_ino); 2075*435Sjchu nf_ino_p = px_ib_locate_ino(ib_p, nf_ino); 2076*435Sjchu f_ino_p = px_ib_locate_ino(ib_p, f_ino); 2077*435Sjchu 2078*435Sjchu /* enable CORR intr mapping */ 2079*435Sjchu if (ce_ino_p) 2080*435Sjchu px_ib_intr_enable(px_p, ce_ino_p->ino_cpuid, ce_ino); 2081*435Sjchu else 2082*435Sjchu cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to " 2083*435Sjchu "reenable PCIe Correctable msg intr.\n"); 2084*435Sjchu 2085*435Sjchu /* enable NON FATAL intr mapping */ 2086*435Sjchu if (nf_ino_p) 2087*435Sjchu px_ib_intr_enable(px_p, nf_ino_p->ino_cpuid, nf_ino); 2088*435Sjchu else 2089*435Sjchu cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to " 2090*435Sjchu "reenable PCIe Non Fatal msg intr.\n"); 2091*435Sjchu 2092*435Sjchu /* enable FATAL intr mapping */ 2093*435Sjchu if (f_ino_p) 2094*435Sjchu px_ib_intr_enable(px_p, f_ino_p->ino_cpuid, f_ino); 2095*435Sjchu else 2096*435Sjchu cmn_err(CE_WARN, "px_cpr_callb: RESUME unable to " 2097*435Sjchu "reenable PCIe Fatal msg intr.\n"); 2098*435Sjchu 2099*435Sjchu mutex_exit(&ib_p->ib_ino_lst_mutex); 2100*435Sjchu 2101*435Sjchu /* enable corr/nonfatal/fatal not enable error */ 2102*435Sjchu CSR_XS(csr_base, IMU_ERROR_LOG_ENABLE, (imu_log_enable | 2103*435Sjchu (imu_log_mask & px_imu_log_mask))); 2104*435Sjchu CSR_XS(csr_base, IMU_INTERRUPT_ENABLE, (imu_intr_enable | 2105*435Sjchu (imu_intr_mask & px_imu_intr_mask))); 2106*435Sjchu 2107*435Sjchu break; 2108*435Sjchu } 2109*435Sjchu 2110*435Sjchu return (B_TRUE); 2111*435Sjchu } 2112*435Sjchu 2113*435Sjchu /* 2114*435Sjchu * add cpr callback 2115*435Sjchu */ 2116*435Sjchu void 2117*435Sjchu px_cpr_add_callb(px_t *px_p) 2118*435Sjchu { 2119*435Sjchu px_p->px_cprcb_id = callb_add(px_cpr_callb, (void *)px_p, 2120*435Sjchu CB_CL_CPR_POST_USER, "px_cpr"); 2121*435Sjchu } 2122*435Sjchu 2123*435Sjchu /* 2124*435Sjchu * remove cpr callback 2125*435Sjchu */ 2126*435Sjchu void 2127*435Sjchu px_cpr_rem_callb(px_t *px_p) 2128*435Sjchu { 2129*435Sjchu (void) callb_delete(px_p->px_cprcb_id); 2130*435Sjchu } 2131