110187SKrishna.Elango@Sun.COM /* 210187SKrishna.Elango@Sun.COM * CDDL HEADER START 310187SKrishna.Elango@Sun.COM * 410187SKrishna.Elango@Sun.COM * The contents of this file are subject to the terms of the 510187SKrishna.Elango@Sun.COM * Common Development and Distribution License (the "License"). 610187SKrishna.Elango@Sun.COM * You may not use this file except in compliance with the License. 710187SKrishna.Elango@Sun.COM * 810187SKrishna.Elango@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 910187SKrishna.Elango@Sun.COM * or http://www.opensolaris.org/os/licensing. 1010187SKrishna.Elango@Sun.COM * See the License for the specific language governing permissions 1110187SKrishna.Elango@Sun.COM * and limitations under the License. 1210187SKrishna.Elango@Sun.COM * 1310187SKrishna.Elango@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1410187SKrishna.Elango@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1510187SKrishna.Elango@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1610187SKrishna.Elango@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1710187SKrishna.Elango@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1810187SKrishna.Elango@Sun.COM * 1910187SKrishna.Elango@Sun.COM * CDDL HEADER END 2010187SKrishna.Elango@Sun.COM */ 2110187SKrishna.Elango@Sun.COM /* 2210187SKrishna.Elango@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2310187SKrishna.Elango@Sun.COM * Use is subject to license terms. 2410187SKrishna.Elango@Sun.COM */ 2510187SKrishna.Elango@Sun.COM 2610187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h> 2710187SKrishna.Elango@Sun.COM #include <sys/types.h> 2810187SKrishna.Elango@Sun.COM #include <sys/kmem.h> 2910187SKrishna.Elango@Sun.COM #include <sys/modctl.h> 3010187SKrishna.Elango@Sun.COM #include <sys/ddi.h> 3110187SKrishna.Elango@Sun.COM #include <sys/sunddi.h> 3210187SKrishna.Elango@Sun.COM #include <sys/sunndi.h> 3310187SKrishna.Elango@Sun.COM #include <sys/fm/protocol.h> 3410187SKrishna.Elango@Sun.COM #include <sys/fm/util.h> 3510187SKrishna.Elango@Sun.COM #include <sys/promif.h> 3610187SKrishna.Elango@Sun.COM #include <sys/disp.h> 3710923SEvan.Yan@Sun.COM #include <sys/stat.h> 3810923SEvan.Yan@Sun.COM #include <sys/file.h> 3910187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h> 4010923SEvan.Yan@Sun.COM #include <sys/pci_impl.h> 4110187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h> 4210923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcie_hp.h> 4310923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcicfg.h> 4411245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h> 4510187SKrishna.Elango@Sun.COM 4610923SEvan.Yan@Sun.COM /* Local functions prototypes */ 4710187SKrishna.Elango@Sun.COM static void pcie_init_pfd(dev_info_t *); 4810187SKrishna.Elango@Sun.COM static void pcie_fini_pfd(dev_info_t *); 4910187SKrishna.Elango@Sun.COM 5010187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64) 5110187SKrishna.Elango@Sun.COM static void pcie_check_io_mem_range(ddi_acc_handle_t, boolean_t *, boolean_t *); 5210187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */ 5310187SKrishna.Elango@Sun.COM 5410187SKrishna.Elango@Sun.COM #ifdef DEBUG 5510187SKrishna.Elango@Sun.COM uint_t pcie_debug_flags = 0; 5610187SKrishna.Elango@Sun.COM static void pcie_print_bus(pcie_bus_t *bus_p); 5710923SEvan.Yan@Sun.COM void pcie_dbg(char *fmt, ...); 5810187SKrishna.Elango@Sun.COM #endif /* DEBUG */ 5910187SKrishna.Elango@Sun.COM 6010187SKrishna.Elango@Sun.COM /* Variable to control default PCI-Express config settings */ 6110187SKrishna.Elango@Sun.COM ushort_t pcie_command_default = 6210187SKrishna.Elango@Sun.COM PCI_COMM_SERR_ENABLE | 6310187SKrishna.Elango@Sun.COM PCI_COMM_WAIT_CYC_ENAB | 6410187SKrishna.Elango@Sun.COM PCI_COMM_PARITY_DETECT | 6510187SKrishna.Elango@Sun.COM PCI_COMM_ME | 6610187SKrishna.Elango@Sun.COM PCI_COMM_MAE | 6710187SKrishna.Elango@Sun.COM PCI_COMM_IO; 6810187SKrishna.Elango@Sun.COM 6910187SKrishna.Elango@Sun.COM /* xxx_fw are bits that are controlled by FW and should not be modified */ 7010187SKrishna.Elango@Sun.COM ushort_t pcie_command_default_fw = 7110187SKrishna.Elango@Sun.COM PCI_COMM_SPEC_CYC | 7210187SKrishna.Elango@Sun.COM PCI_COMM_MEMWR_INVAL | 7310187SKrishna.Elango@Sun.COM PCI_COMM_PALETTE_SNOOP | 7410187SKrishna.Elango@Sun.COM PCI_COMM_WAIT_CYC_ENAB | 7510187SKrishna.Elango@Sun.COM 0xF800; /* Reserved Bits */ 7610187SKrishna.Elango@Sun.COM 7710187SKrishna.Elango@Sun.COM ushort_t pcie_bdg_command_default_fw = 7810187SKrishna.Elango@Sun.COM PCI_BCNF_BCNTRL_ISA_ENABLE | 7910187SKrishna.Elango@Sun.COM PCI_BCNF_BCNTRL_VGA_ENABLE | 8010187SKrishna.Elango@Sun.COM 0xF000; /* Reserved Bits */ 8110187SKrishna.Elango@Sun.COM 8210187SKrishna.Elango@Sun.COM /* PCI-Express Base error defaults */ 8310187SKrishna.Elango@Sun.COM ushort_t pcie_base_err_default = 8410187SKrishna.Elango@Sun.COM PCIE_DEVCTL_CE_REPORTING_EN | 8510187SKrishna.Elango@Sun.COM PCIE_DEVCTL_NFE_REPORTING_EN | 8610187SKrishna.Elango@Sun.COM PCIE_DEVCTL_FE_REPORTING_EN | 8710187SKrishna.Elango@Sun.COM PCIE_DEVCTL_UR_REPORTING_EN; 8810187SKrishna.Elango@Sun.COM 8910187SKrishna.Elango@Sun.COM /* PCI-Express Device Control Register */ 9010187SKrishna.Elango@Sun.COM uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN | 9110187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_READ_REQ_512; 9210187SKrishna.Elango@Sun.COM 9310187SKrishna.Elango@Sun.COM /* PCI-Express AER Root Control Register */ 9410187SKrishna.Elango@Sun.COM #define PCIE_ROOT_SYS_ERR (PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \ 9510187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \ 9610187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_FE_EN) 9710187SKrishna.Elango@Sun.COM 9810187SKrishna.Elango@Sun.COM ushort_t pcie_root_ctrl_default = 9910187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | 10010187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | 10110187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_FE_EN; 10210187SKrishna.Elango@Sun.COM 10310187SKrishna.Elango@Sun.COM /* PCI-Express Root Error Command Register */ 10410187SKrishna.Elango@Sun.COM ushort_t pcie_root_error_cmd_default = 10510187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_CE_REP_EN | 10610187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_NFE_REP_EN | 10710187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_FE_REP_EN; 10810187SKrishna.Elango@Sun.COM 10910187SKrishna.Elango@Sun.COM /* ECRC settings in the PCIe AER Control Register */ 11010187SKrishna.Elango@Sun.COM uint32_t pcie_ecrc_value = 11110187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_GEN_ENA | 11210187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_CHECK_ENA; 11310187SKrishna.Elango@Sun.COM 11410187SKrishna.Elango@Sun.COM /* 11510187SKrishna.Elango@Sun.COM * If a particular platform wants to disable certain errors such as UR/MA, 11610187SKrishna.Elango@Sun.COM * instead of using #defines have the platform's PCIe Root Complex driver set 11710187SKrishna.Elango@Sun.COM * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions. For 11810923SEvan.Yan@Sun.COM * x86 the closest thing to a PCIe root complex driver is NPE. For SPARC the 11910187SKrishna.Elango@Sun.COM * closest PCIe root complex driver is PX. 12010187SKrishna.Elango@Sun.COM * 12110187SKrishna.Elango@Sun.COM * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86 12210187SKrishna.Elango@Sun.COM * systems may want to disable SERR in general. For root ports, enabling SERR 12310187SKrishna.Elango@Sun.COM * causes NMIs which are not handled and results in a watchdog timeout error. 12410187SKrishna.Elango@Sun.COM */ 12510187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_mask = 0; /* AER UE Mask */ 12610187SKrishna.Elango@Sun.COM uint32_t pcie_aer_ce_mask = 0; /* AER CE Mask */ 12710187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_mask = 0; /* AER Secondary UE Mask */ 12810187SKrishna.Elango@Sun.COM uint32_t pcie_serr_disable_flag = 0; /* Disable SERR */ 12910187SKrishna.Elango@Sun.COM 13010187SKrishna.Elango@Sun.COM /* Default severities needed for eversholt. Error handling doesn't care */ 13110187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \ 13210187SKrishna.Elango@Sun.COM PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \ 13310187SKrishna.Elango@Sun.COM PCIE_AER_UCE_TRAINING; 13410187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \ 13510187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \ 13610187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_USC_MSG_DATA_ERR; 13710187SKrishna.Elango@Sun.COM 13810187SKrishna.Elango@Sun.COM int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5; 13910923SEvan.Yan@Sun.COM int pcie_disable_ari = 0; 14010187SKrishna.Elango@Sun.COM 14110187SKrishna.Elango@Sun.COM static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, 14210187SKrishna.Elango@Sun.COM int *max_supported); 14310187SKrishna.Elango@Sun.COM static int pcie_get_max_supported(dev_info_t *dip, void *arg); 14410187SKrishna.Elango@Sun.COM static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 14510187SKrishna.Elango@Sun.COM caddr_t *addrp, ddi_acc_handle_t *handlep); 14610923SEvan.Yan@Sun.COM static void pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph); 14710187SKrishna.Elango@Sun.COM 14811245SZhijun.Fu@Sun.COM dev_info_t *pcie_get_rc_dip(dev_info_t *dip); 14911245SZhijun.Fu@Sun.COM 15010187SKrishna.Elango@Sun.COM /* 15110187SKrishna.Elango@Sun.COM * modload support 15210187SKrishna.Elango@Sun.COM */ 15310187SKrishna.Elango@Sun.COM 15410187SKrishna.Elango@Sun.COM static struct modlmisc modlmisc = { 15510187SKrishna.Elango@Sun.COM &mod_miscops, /* Type of module */ 15610923SEvan.Yan@Sun.COM "PCI Express Framework Module" 15710187SKrishna.Elango@Sun.COM }; 15810187SKrishna.Elango@Sun.COM 15910187SKrishna.Elango@Sun.COM static struct modlinkage modlinkage = { 16010187SKrishna.Elango@Sun.COM MODREV_1, 16110187SKrishna.Elango@Sun.COM (void *)&modlmisc, 16210187SKrishna.Elango@Sun.COM NULL 16310187SKrishna.Elango@Sun.COM }; 16410187SKrishna.Elango@Sun.COM 16510187SKrishna.Elango@Sun.COM /* 16610187SKrishna.Elango@Sun.COM * Global Variables needed for a non-atomic version of ddi_fm_ereport_post. 16710187SKrishna.Elango@Sun.COM * Currently used to send the pci.fabric ereports whose payload depends on the 16810187SKrishna.Elango@Sun.COM * type of PCI device it is being sent for. 16910187SKrishna.Elango@Sun.COM */ 17010187SKrishna.Elango@Sun.COM char *pcie_nv_buf; 17110187SKrishna.Elango@Sun.COM nv_alloc_t *pcie_nvap; 17210187SKrishna.Elango@Sun.COM nvlist_t *pcie_nvl; 17310187SKrishna.Elango@Sun.COM 17410187SKrishna.Elango@Sun.COM int 17510187SKrishna.Elango@Sun.COM _init(void) 17610187SKrishna.Elango@Sun.COM { 17710187SKrishna.Elango@Sun.COM int rval; 17810187SKrishna.Elango@Sun.COM 17910187SKrishna.Elango@Sun.COM pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP); 18010187SKrishna.Elango@Sun.COM pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ); 18110187SKrishna.Elango@Sun.COM pcie_nvl = fm_nvlist_create(pcie_nvap); 18210187SKrishna.Elango@Sun.COM 18310187SKrishna.Elango@Sun.COM rval = mod_install(&modlinkage); 18410187SKrishna.Elango@Sun.COM return (rval); 18510187SKrishna.Elango@Sun.COM } 18610187SKrishna.Elango@Sun.COM 18710187SKrishna.Elango@Sun.COM int 18810187SKrishna.Elango@Sun.COM _fini() 18910187SKrishna.Elango@Sun.COM { 19010187SKrishna.Elango@Sun.COM int rval; 19110187SKrishna.Elango@Sun.COM 19210187SKrishna.Elango@Sun.COM fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN); 19310187SKrishna.Elango@Sun.COM fm_nva_xdestroy(pcie_nvap); 19410187SKrishna.Elango@Sun.COM kmem_free(pcie_nv_buf, ERPT_DATA_SZ); 19510187SKrishna.Elango@Sun.COM 19610187SKrishna.Elango@Sun.COM rval = mod_remove(&modlinkage); 19710187SKrishna.Elango@Sun.COM return (rval); 19810187SKrishna.Elango@Sun.COM } 19910187SKrishna.Elango@Sun.COM 20010187SKrishna.Elango@Sun.COM int 20110187SKrishna.Elango@Sun.COM _info(struct modinfo *modinfop) 20210187SKrishna.Elango@Sun.COM { 20310187SKrishna.Elango@Sun.COM return (mod_info(&modlinkage, modinfop)); 20410187SKrishna.Elango@Sun.COM } 20510187SKrishna.Elango@Sun.COM 20610923SEvan.Yan@Sun.COM /* ARGSUSED */ 20710923SEvan.Yan@Sun.COM int 20810923SEvan.Yan@Sun.COM pcie_init(dev_info_t *dip, caddr_t arg) 20910923SEvan.Yan@Sun.COM { 21010923SEvan.Yan@Sun.COM int ret = DDI_SUCCESS; 21110923SEvan.Yan@Sun.COM 21210923SEvan.Yan@Sun.COM /* 21310923SEvan.Yan@Sun.COM * Create a "devctl" minor node to support DEVCTL_DEVICE_* 21410923SEvan.Yan@Sun.COM * and DEVCTL_BUS_* ioctls to this bus. 21510923SEvan.Yan@Sun.COM */ 21610923SEvan.Yan@Sun.COM if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR, 21710923SEvan.Yan@Sun.COM PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR), 21810923SEvan.Yan@Sun.COM DDI_NT_NEXUS, 0)) != DDI_SUCCESS) { 21910923SEvan.Yan@Sun.COM PCIE_DBG("Failed to create devctl minor node for %s%d\n", 22010923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 22110923SEvan.Yan@Sun.COM 22210923SEvan.Yan@Sun.COM return (ret); 22310923SEvan.Yan@Sun.COM } 22410923SEvan.Yan@Sun.COM 22510923SEvan.Yan@Sun.COM if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) { 22610923SEvan.Yan@Sun.COM /* 227*11366SColin.Zou@Sun.COM * On some x86 platforms, we observed unexpected hotplug 228*11366SColin.Zou@Sun.COM * initialization failures in recent years. The known cause 229*11366SColin.Zou@Sun.COM * is a hardware issue: while the problem PCI bridges have 230*11366SColin.Zou@Sun.COM * the Hotplug Capable registers set, the machine actually 231*11366SColin.Zou@Sun.COM * does not implement the expected ACPI object. 232*11366SColin.Zou@Sun.COM * 233*11366SColin.Zou@Sun.COM * We don't want to stop PCI driver attach and system boot 234*11366SColin.Zou@Sun.COM * just because of this hotplug initialization failure. 235*11366SColin.Zou@Sun.COM * Continue with a debug message printed. 23610923SEvan.Yan@Sun.COM */ 237*11366SColin.Zou@Sun.COM PCIE_DBG("%s%d: Failed setting hotplug framework\n", 23810923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 23910923SEvan.Yan@Sun.COM 24010923SEvan.Yan@Sun.COM #if defined(__sparc) 24110923SEvan.Yan@Sun.COM ddi_remove_minor_node(dip, "devctl"); 24210923SEvan.Yan@Sun.COM 24310923SEvan.Yan@Sun.COM return (ret); 24410923SEvan.Yan@Sun.COM #endif /* defined(__sparc) */ 24510923SEvan.Yan@Sun.COM } 24610923SEvan.Yan@Sun.COM 24710923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 24810923SEvan.Yan@Sun.COM } 24910923SEvan.Yan@Sun.COM 25010923SEvan.Yan@Sun.COM /* ARGSUSED */ 25110923SEvan.Yan@Sun.COM int 25210923SEvan.Yan@Sun.COM pcie_uninit(dev_info_t *dip) 25310923SEvan.Yan@Sun.COM { 25410923SEvan.Yan@Sun.COM int ret = DDI_SUCCESS; 25510923SEvan.Yan@Sun.COM 25610923SEvan.Yan@Sun.COM if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED) 25710923SEvan.Yan@Sun.COM (void) pcie_ari_disable(dip); 25810923SEvan.Yan@Sun.COM 25910923SEvan.Yan@Sun.COM if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) { 26010923SEvan.Yan@Sun.COM PCIE_DBG("Failed to uninitialize hotplug for %s%d\n", 26110923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 26210923SEvan.Yan@Sun.COM 26310923SEvan.Yan@Sun.COM return (ret); 26410923SEvan.Yan@Sun.COM } 26510923SEvan.Yan@Sun.COM 26610923SEvan.Yan@Sun.COM ddi_remove_minor_node(dip, "devctl"); 26710923SEvan.Yan@Sun.COM 26810923SEvan.Yan@Sun.COM return (ret); 26910923SEvan.Yan@Sun.COM } 27010923SEvan.Yan@Sun.COM 27110923SEvan.Yan@Sun.COM /* ARGSUSED */ 27210923SEvan.Yan@Sun.COM int 27310923SEvan.Yan@Sun.COM pcie_intr(dev_info_t *dip) 27410923SEvan.Yan@Sun.COM { 27510923SEvan.Yan@Sun.COM return (pcie_hp_intr(dip)); 27610923SEvan.Yan@Sun.COM } 27710923SEvan.Yan@Sun.COM 27810923SEvan.Yan@Sun.COM /* ARGSUSED */ 27910923SEvan.Yan@Sun.COM int 28010923SEvan.Yan@Sun.COM pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp) 28110923SEvan.Yan@Sun.COM { 28210923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 28310923SEvan.Yan@Sun.COM 28410923SEvan.Yan@Sun.COM /* 28510923SEvan.Yan@Sun.COM * Make sure the open is for the right file type. 28610923SEvan.Yan@Sun.COM */ 28710923SEvan.Yan@Sun.COM if (otyp != OTYP_CHR) 28810923SEvan.Yan@Sun.COM return (EINVAL); 28910923SEvan.Yan@Sun.COM 29010923SEvan.Yan@Sun.COM /* 29110923SEvan.Yan@Sun.COM * Handle the open by tracking the device state. 29210923SEvan.Yan@Sun.COM */ 29310923SEvan.Yan@Sun.COM if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) || 29410923SEvan.Yan@Sun.COM ((flags & FEXCL) && 29510923SEvan.Yan@Sun.COM (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) { 29610923SEvan.Yan@Sun.COM return (EBUSY); 29710923SEvan.Yan@Sun.COM } 29810923SEvan.Yan@Sun.COM 29910923SEvan.Yan@Sun.COM if (flags & FEXCL) 30010923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL; 30110923SEvan.Yan@Sun.COM else 30210923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN; 30310923SEvan.Yan@Sun.COM 30410923SEvan.Yan@Sun.COM return (0); 30510923SEvan.Yan@Sun.COM } 30610923SEvan.Yan@Sun.COM 30710923SEvan.Yan@Sun.COM /* ARGSUSED */ 30810923SEvan.Yan@Sun.COM int 30910923SEvan.Yan@Sun.COM pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp) 31010923SEvan.Yan@Sun.COM { 31110923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 31210923SEvan.Yan@Sun.COM 31310923SEvan.Yan@Sun.COM if (otyp != OTYP_CHR) 31410923SEvan.Yan@Sun.COM return (EINVAL); 31510923SEvan.Yan@Sun.COM 31610923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED; 31710923SEvan.Yan@Sun.COM 31810923SEvan.Yan@Sun.COM return (0); 31910923SEvan.Yan@Sun.COM } 32010923SEvan.Yan@Sun.COM 32110923SEvan.Yan@Sun.COM /* ARGSUSED */ 32210923SEvan.Yan@Sun.COM int 32310923SEvan.Yan@Sun.COM pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode, 32410923SEvan.Yan@Sun.COM cred_t *credp, int *rvalp) 32510923SEvan.Yan@Sun.COM { 32610923SEvan.Yan@Sun.COM struct devctl_iocdata *dcp; 32710923SEvan.Yan@Sun.COM uint_t bus_state; 32810923SEvan.Yan@Sun.COM int rv = DDI_SUCCESS; 32910923SEvan.Yan@Sun.COM 33010923SEvan.Yan@Sun.COM /* 33110923SEvan.Yan@Sun.COM * We can use the generic implementation for devctl ioctl 33210923SEvan.Yan@Sun.COM */ 33310923SEvan.Yan@Sun.COM switch (cmd) { 33410923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_GETSTATE: 33510923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_ONLINE: 33610923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_OFFLINE: 33710923SEvan.Yan@Sun.COM case DEVCTL_BUS_GETSTATE: 33810923SEvan.Yan@Sun.COM return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0)); 33910923SEvan.Yan@Sun.COM default: 34010923SEvan.Yan@Sun.COM break; 34110923SEvan.Yan@Sun.COM } 34210923SEvan.Yan@Sun.COM 34310923SEvan.Yan@Sun.COM /* 34410923SEvan.Yan@Sun.COM * read devctl ioctl data 34510923SEvan.Yan@Sun.COM */ 34610923SEvan.Yan@Sun.COM if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 34710923SEvan.Yan@Sun.COM return (EFAULT); 34810923SEvan.Yan@Sun.COM 34910923SEvan.Yan@Sun.COM switch (cmd) { 35010923SEvan.Yan@Sun.COM case DEVCTL_BUS_QUIESCE: 35110923SEvan.Yan@Sun.COM if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) 35210923SEvan.Yan@Sun.COM if (bus_state == BUS_QUIESCED) 35310923SEvan.Yan@Sun.COM break; 35410923SEvan.Yan@Sun.COM (void) ndi_set_bus_state(dip, BUS_QUIESCED); 35510923SEvan.Yan@Sun.COM break; 35610923SEvan.Yan@Sun.COM case DEVCTL_BUS_UNQUIESCE: 35710923SEvan.Yan@Sun.COM if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) 35810923SEvan.Yan@Sun.COM if (bus_state == BUS_ACTIVE) 35910923SEvan.Yan@Sun.COM break; 36010923SEvan.Yan@Sun.COM (void) ndi_set_bus_state(dip, BUS_ACTIVE); 36110923SEvan.Yan@Sun.COM break; 36210923SEvan.Yan@Sun.COM case DEVCTL_BUS_RESET: 36310923SEvan.Yan@Sun.COM case DEVCTL_BUS_RESETALL: 36410923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_RESET: 36510923SEvan.Yan@Sun.COM rv = ENOTSUP; 36610923SEvan.Yan@Sun.COM break; 36710923SEvan.Yan@Sun.COM default: 36810923SEvan.Yan@Sun.COM rv = ENOTTY; 36910923SEvan.Yan@Sun.COM } 37010923SEvan.Yan@Sun.COM 37110923SEvan.Yan@Sun.COM ndi_dc_freehdl(dcp); 37210923SEvan.Yan@Sun.COM return (rv); 37310923SEvan.Yan@Sun.COM } 37410923SEvan.Yan@Sun.COM 37510923SEvan.Yan@Sun.COM /* ARGSUSED */ 37610923SEvan.Yan@Sun.COM int 37710923SEvan.Yan@Sun.COM pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 37810923SEvan.Yan@Sun.COM int flags, char *name, caddr_t valuep, int *lengthp) 37910923SEvan.Yan@Sun.COM { 38010923SEvan.Yan@Sun.COM if (dev == DDI_DEV_T_ANY) 38110923SEvan.Yan@Sun.COM goto skip; 38210923SEvan.Yan@Sun.COM 38310923SEvan.Yan@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip) && 38410923SEvan.Yan@Sun.COM strcmp(name, "pci-occupant") == 0) { 38510923SEvan.Yan@Sun.COM int pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev)); 38610923SEvan.Yan@Sun.COM 38710923SEvan.Yan@Sun.COM pcie_hp_create_occupant_props(dip, dev, pci_dev); 38810923SEvan.Yan@Sun.COM } 38910923SEvan.Yan@Sun.COM 39010923SEvan.Yan@Sun.COM skip: 39110923SEvan.Yan@Sun.COM return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); 39210923SEvan.Yan@Sun.COM } 39310923SEvan.Yan@Sun.COM 39411245SZhijun.Fu@Sun.COM int 39511245SZhijun.Fu@Sun.COM pcie_init_cfghdl(dev_info_t *cdip) 39611245SZhijun.Fu@Sun.COM { 39711245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p; 39811245SZhijun.Fu@Sun.COM ddi_acc_handle_t eh = NULL; 39911245SZhijun.Fu@Sun.COM 40011245SZhijun.Fu@Sun.COM bus_p = PCIE_DIP2BUS(cdip); 40111245SZhijun.Fu@Sun.COM if (bus_p == NULL) 40211245SZhijun.Fu@Sun.COM return (DDI_FAILURE); 40311245SZhijun.Fu@Sun.COM 40411245SZhijun.Fu@Sun.COM /* Create an config access special to error handling */ 40511245SZhijun.Fu@Sun.COM if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) { 40611245SZhijun.Fu@Sun.COM cmn_err(CE_WARN, "Cannot setup config access" 40711245SZhijun.Fu@Sun.COM " for BDF 0x%x\n", bus_p->bus_bdf); 40811245SZhijun.Fu@Sun.COM return (DDI_FAILURE); 40911245SZhijun.Fu@Sun.COM } 41011245SZhijun.Fu@Sun.COM 41111245SZhijun.Fu@Sun.COM bus_p->bus_cfg_hdl = eh; 41211245SZhijun.Fu@Sun.COM return (DDI_SUCCESS); 41311245SZhijun.Fu@Sun.COM } 41411245SZhijun.Fu@Sun.COM 41511245SZhijun.Fu@Sun.COM void 41611245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(dev_info_t *cdip) 41711245SZhijun.Fu@Sun.COM { 41811245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip); 41911245SZhijun.Fu@Sun.COM 42011245SZhijun.Fu@Sun.COM pci_config_teardown(&bus_p->bus_cfg_hdl); 42111245SZhijun.Fu@Sun.COM } 42211245SZhijun.Fu@Sun.COM 42310187SKrishna.Elango@Sun.COM /* 42410187SKrishna.Elango@Sun.COM * PCI-Express child device initialization. 42510187SKrishna.Elango@Sun.COM * This function enables generic pci-express interrupts and error 42610187SKrishna.Elango@Sun.COM * handling. 42710187SKrishna.Elango@Sun.COM * 42810187SKrishna.Elango@Sun.COM * @param pdip root dip (root nexus's dip) 42910187SKrishna.Elango@Sun.COM * @param cdip child's dip (device's dip) 43010187SKrishna.Elango@Sun.COM * @return DDI_SUCCESS or DDI_FAILURE 43110187SKrishna.Elango@Sun.COM */ 43210187SKrishna.Elango@Sun.COM /* ARGSUSED */ 43310187SKrishna.Elango@Sun.COM int 43410187SKrishna.Elango@Sun.COM pcie_initchild(dev_info_t *cdip) 43510187SKrishna.Elango@Sun.COM { 43610187SKrishna.Elango@Sun.COM uint16_t tmp16, reg16; 43710187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 43810187SKrishna.Elango@Sun.COM 43910187SKrishna.Elango@Sun.COM bus_p = PCIE_DIP2BUS(cdip); 44010187SKrishna.Elango@Sun.COM if (bus_p == NULL) { 44110187SKrishna.Elango@Sun.COM PCIE_DBG("%s: BUS not found.\n", 44210187SKrishna.Elango@Sun.COM ddi_driver_name(cdip)); 44310187SKrishna.Elango@Sun.COM 44410187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 44510187SKrishna.Elango@Sun.COM } 44610187SKrishna.Elango@Sun.COM 44711245SZhijun.Fu@Sun.COM if (pcie_init_cfghdl(cdip) != DDI_SUCCESS) 44811245SZhijun.Fu@Sun.COM return (DDI_FAILURE); 44911245SZhijun.Fu@Sun.COM 45010187SKrishna.Elango@Sun.COM /* Clear the device's status register */ 45110187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT); 45210187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16); 45310187SKrishna.Elango@Sun.COM 45410187SKrishna.Elango@Sun.COM /* Setup the device's command register */ 45510187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM); 45610187SKrishna.Elango@Sun.COM tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default; 45710187SKrishna.Elango@Sun.COM 45810187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64) 45910187SKrishna.Elango@Sun.COM boolean_t empty_io_range = B_FALSE; 46010187SKrishna.Elango@Sun.COM boolean_t empty_mem_range = B_FALSE; 46110187SKrishna.Elango@Sun.COM /* 46210187SKrishna.Elango@Sun.COM * Check for empty IO and Mem ranges on bridges. If so disable IO/Mem 46310187SKrishna.Elango@Sun.COM * access as it can cause a hang if enabled. 46410187SKrishna.Elango@Sun.COM */ 46510187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(bus_p->bus_cfg_hdl, &empty_io_range, 46610187SKrishna.Elango@Sun.COM &empty_mem_range); 46710187SKrishna.Elango@Sun.COM if ((empty_io_range == B_TRUE) && 46810187SKrishna.Elango@Sun.COM (pcie_command_default & PCI_COMM_IO)) { 46910187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_IO; 47010187SKrishna.Elango@Sun.COM PCIE_DBG("No I/O range found for %s, bdf 0x%x\n", 47110187SKrishna.Elango@Sun.COM ddi_driver_name(cdip), bus_p->bus_bdf); 47210187SKrishna.Elango@Sun.COM } 47310187SKrishna.Elango@Sun.COM if ((empty_mem_range == B_TRUE) && 47410187SKrishna.Elango@Sun.COM (pcie_command_default & PCI_COMM_MAE)) { 47510187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_MAE; 47610187SKrishna.Elango@Sun.COM PCIE_DBG("No Mem range found for %s, bdf 0x%x\n", 47710187SKrishna.Elango@Sun.COM ddi_driver_name(cdip), bus_p->bus_bdf); 47810187SKrishna.Elango@Sun.COM } 47910187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */ 48010187SKrishna.Elango@Sun.COM 48110187SKrishna.Elango@Sun.COM if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p)) 48210187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_SERR_ENABLE; 48310187SKrishna.Elango@Sun.COM 48410187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16); 48510187SKrishna.Elango@Sun.COM PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16); 48610187SKrishna.Elango@Sun.COM 48710187SKrishna.Elango@Sun.COM /* 48810187SKrishna.Elango@Sun.COM * If the device has a bus control register then program it 48910187SKrishna.Elango@Sun.COM * based on the settings in the command register. 49010187SKrishna.Elango@Sun.COM */ 49110187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 49210187SKrishna.Elango@Sun.COM /* Clear the device's secondary status register */ 49310187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS); 49410187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16); 49510187SKrishna.Elango@Sun.COM 49610187SKrishna.Elango@Sun.COM /* Setup the device's secondary command register */ 49710187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL); 49810187SKrishna.Elango@Sun.COM tmp16 = (reg16 & pcie_bdg_command_default_fw); 49910187SKrishna.Elango@Sun.COM 50010187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE; 50110187SKrishna.Elango@Sun.COM /* 50210187SKrishna.Elango@Sun.COM * Workaround for this Nvidia bridge. Don't enable the SERR 50310187SKrishna.Elango@Sun.COM * enable bit in the bridge control register as it could lead to 50410187SKrishna.Elango@Sun.COM * bogus NMIs. 50510187SKrishna.Elango@Sun.COM */ 50610187SKrishna.Elango@Sun.COM if (bus_p->bus_dev_ven_id == 0x037010DE) 50710187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE; 50810187SKrishna.Elango@Sun.COM 50910187SKrishna.Elango@Sun.COM if (pcie_command_default & PCI_COMM_PARITY_DETECT) 51010187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE; 51110187SKrishna.Elango@Sun.COM 51210187SKrishna.Elango@Sun.COM /* 51310187SKrishna.Elango@Sun.COM * Enable Master Abort Mode only if URs have not been masked. 51410187SKrishna.Elango@Sun.COM * For PCI and PCIe-PCI bridges, enabling this bit causes a 51510187SKrishna.Elango@Sun.COM * Master Aborts/UR to be forwarded as a UR/TA or SERR. If this 51610187SKrishna.Elango@Sun.COM * bit is masked, posted requests are dropped and non-posted 51710187SKrishna.Elango@Sun.COM * requests are returned with -1. 51810187SKrishna.Elango@Sun.COM */ 51910187SKrishna.Elango@Sun.COM if (pcie_aer_uce_mask & PCIE_AER_UCE_UR) 52010187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE; 52110187SKrishna.Elango@Sun.COM else 52210187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE; 52310187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16); 52410187SKrishna.Elango@Sun.COM PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL, 52510187SKrishna.Elango@Sun.COM reg16); 52610187SKrishna.Elango@Sun.COM } 52710187SKrishna.Elango@Sun.COM 52810187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 52910187SKrishna.Elango@Sun.COM /* Setup PCIe device control register */ 53010187SKrishna.Elango@Sun.COM reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 53110187SKrishna.Elango@Sun.COM tmp16 = pcie_devctl_default; 53210187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16); 53310187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16); 53410187SKrishna.Elango@Sun.COM 53510187SKrishna.Elango@Sun.COM /* Enable PCIe errors */ 53610187SKrishna.Elango@Sun.COM pcie_enable_errors(cdip); 53710187SKrishna.Elango@Sun.COM } 53810187SKrishna.Elango@Sun.COM 53910923SEvan.Yan@Sun.COM bus_p->bus_ari = B_FALSE; 54010923SEvan.Yan@Sun.COM if ((pcie_ari_is_enabled(ddi_get_parent(cdip)) 54110923SEvan.Yan@Sun.COM == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip) 54210923SEvan.Yan@Sun.COM == PCIE_ARI_DEVICE)) { 54310923SEvan.Yan@Sun.COM bus_p->bus_ari = B_TRUE; 54410923SEvan.Yan@Sun.COM } 54510923SEvan.Yan@Sun.COM 54611245SZhijun.Fu@Sun.COM if (pcie_initchild_mps(cdip) == DDI_FAILURE) { 54711245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(cdip); 54810187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 54911245SZhijun.Fu@Sun.COM } 55010187SKrishna.Elango@Sun.COM 55110187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 55210187SKrishna.Elango@Sun.COM } 55310187SKrishna.Elango@Sun.COM 55410187SKrishna.Elango@Sun.COM #define PCIE_ZALLOC(data) kmem_zalloc(sizeof (data), KM_SLEEP) 55510187SKrishna.Elango@Sun.COM static void 55610187SKrishna.Elango@Sun.COM pcie_init_pfd(dev_info_t *dip) 55710187SKrishna.Elango@Sun.COM { 55810187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_ZALLOC(pf_data_t); 55910187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 56010187SKrishna.Elango@Sun.COM 56110187SKrishna.Elango@Sun.COM PCIE_DIP2PFD(dip) = pfd_p; 56210187SKrishna.Elango@Sun.COM 56310187SKrishna.Elango@Sun.COM pfd_p->pe_bus_p = bus_p; 56410187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = 0; 56510187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE; 56610187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE; 56710187SKrishna.Elango@Sun.COM 56810187SKrishna.Elango@Sun.COM /* Allocate the root fault struct for both RC and RP */ 56910187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) { 57010187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t); 57110187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF; 57210187SKrishna.Elango@Sun.COM } 57310187SKrishna.Elango@Sun.COM 57410187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t); 57510187SKrishna.Elango@Sun.COM 57610187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) 57710187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t); 57810187SKrishna.Elango@Sun.COM 57910187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 58010187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t); 58110187SKrishna.Elango@Sun.COM 58210187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 58310187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p) = 58410187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_rp_err_regs_t); 58510187SKrishna.Elango@Sun.COM 58610187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t); 58710187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF; 58810187SKrishna.Elango@Sun.COM 58910187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) { 59010187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p) = 59110187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t); 59210187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = 59310187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 59410187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = 59510187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 59610187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIE_BDG(bus_p)) { 59710187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p) = 59810187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t); 59910187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = 60010187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 60110187SKrishna.Elango@Sun.COM } 60210187SKrishna.Elango@Sun.COM 60310187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) { 60410187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p) = 60510187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_bdg_err_regs_t); 60610187SKrishna.Elango@Sun.COM 60710187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 60810187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0) = 60910187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 61010187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 1) = 61110187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 61210187SKrishna.Elango@Sun.COM } 61310187SKrishna.Elango@Sun.COM } 61410187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIX(bus_p)) { 61510187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 61610187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p) = 61710187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_bdg_err_regs_t); 61810187SKrishna.Elango@Sun.COM 61910187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 62010187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0) = 62110187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 62210187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 1) = 62310187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 62410187SKrishna.Elango@Sun.COM } 62510187SKrishna.Elango@Sun.COM } else { 62610187SKrishna.Elango@Sun.COM PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t); 62710187SKrishna.Elango@Sun.COM 62810187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) 62910187SKrishna.Elango@Sun.COM PCIX_ECC_REG(pfd_p) = 63010187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 63110187SKrishna.Elango@Sun.COM } 63210187SKrishna.Elango@Sun.COM } 63310187SKrishna.Elango@Sun.COM } 63410187SKrishna.Elango@Sun.COM 63510187SKrishna.Elango@Sun.COM static void 63610187SKrishna.Elango@Sun.COM pcie_fini_pfd(dev_info_t *dip) 63710187SKrishna.Elango@Sun.COM { 63810187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip); 63910187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 64010187SKrishna.Elango@Sun.COM 64110187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 64210187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) { 64310187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 64410187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0), 64510187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 64610187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1), 64710187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 64810187SKrishna.Elango@Sun.COM } 64910187SKrishna.Elango@Sun.COM 65010187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ERR_REG(pfd_p), 65110187SKrishna.Elango@Sun.COM sizeof (pf_pcix_bdg_err_regs_t)); 65210187SKrishna.Elango@Sun.COM } 65310187SKrishna.Elango@Sun.COM 65410187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 65510187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_RP_REG(pfd_p), 65610187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_rp_err_regs_t)); 65710187SKrishna.Elango@Sun.COM else if (PCIE_IS_PCIE_BDG(bus_p)) 65810187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_BDG_REG(pfd_p), 65910187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_bdg_err_regs_t)); 66010187SKrishna.Elango@Sun.COM 66110187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_REG(pfd_p), 66210187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_err_regs_t)); 66310187SKrishna.Elango@Sun.COM 66410187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 66510187SKrishna.Elango@Sun.COM kmem_free(PCIE_RP_REG(pfd_p), 66610187SKrishna.Elango@Sun.COM sizeof (pf_pcie_rp_err_regs_t)); 66710187SKrishna.Elango@Sun.COM 66810187SKrishna.Elango@Sun.COM kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t)); 66910187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIX(bus_p)) { 67010187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 67110187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 67210187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0), 67310187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 67410187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1), 67510187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 67610187SKrishna.Elango@Sun.COM } 67710187SKrishna.Elango@Sun.COM 67810187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ERR_REG(pfd_p), 67910187SKrishna.Elango@Sun.COM sizeof (pf_pcix_bdg_err_regs_t)); 68010187SKrishna.Elango@Sun.COM } else { 68110187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) 68210187SKrishna.Elango@Sun.COM kmem_free(PCIX_ECC_REG(pfd_p), 68310187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 68410187SKrishna.Elango@Sun.COM 68510187SKrishna.Elango@Sun.COM kmem_free(PCIX_ERR_REG(pfd_p), 68610187SKrishna.Elango@Sun.COM sizeof (pf_pcix_err_regs_t)); 68710187SKrishna.Elango@Sun.COM } 68810187SKrishna.Elango@Sun.COM } 68910187SKrishna.Elango@Sun.COM 69010187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) 69110187SKrishna.Elango@Sun.COM kmem_free(PCI_BDG_ERR_REG(pfd_p), 69210187SKrishna.Elango@Sun.COM sizeof (pf_pci_bdg_err_regs_t)); 69310187SKrishna.Elango@Sun.COM 69410187SKrishna.Elango@Sun.COM kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t)); 69510187SKrishna.Elango@Sun.COM 69610187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) 69710187SKrishna.Elango@Sun.COM kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t)); 69810187SKrishna.Elango@Sun.COM 69910187SKrishna.Elango@Sun.COM kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t)); 70010187SKrishna.Elango@Sun.COM 70110187SKrishna.Elango@Sun.COM PCIE_DIP2PFD(dip) = NULL; 70210187SKrishna.Elango@Sun.COM } 70310187SKrishna.Elango@Sun.COM 70410187SKrishna.Elango@Sun.COM 70510187SKrishna.Elango@Sun.COM /* 70610187SKrishna.Elango@Sun.COM * Special functions to allocate pf_data_t's for PCIe root complexes. 70710187SKrishna.Elango@Sun.COM * Note: Root Complex not Root Port 70810187SKrishna.Elango@Sun.COM */ 70910187SKrishna.Elango@Sun.COM void 71010187SKrishna.Elango@Sun.COM pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p) 71110187SKrishna.Elango@Sun.COM { 71210187SKrishna.Elango@Sun.COM pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip); 71310187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = 0; 71410187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE; 71510187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE; 71610187SKrishna.Elango@Sun.COM 71710187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t); 71810187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF; 71910187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t); 72010187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t); 72110187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t); 72210187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t); 72310187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t); 72410187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t); 72510187SKrishna.Elango@Sun.COM 72610187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity; 72710187SKrishna.Elango@Sun.COM } 72810187SKrishna.Elango@Sun.COM 72910187SKrishna.Elango@Sun.COM void 73010187SKrishna.Elango@Sun.COM pcie_rc_fini_pfd(pf_data_t *pfd_p) 73110187SKrishna.Elango@Sun.COM { 73210187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t)); 73310187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t)); 73410187SKrishna.Elango@Sun.COM kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t)); 73510187SKrishna.Elango@Sun.COM kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t)); 73610187SKrishna.Elango@Sun.COM kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t)); 73710187SKrishna.Elango@Sun.COM kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t)); 73810187SKrishna.Elango@Sun.COM kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t)); 73910187SKrishna.Elango@Sun.COM } 74010187SKrishna.Elango@Sun.COM 74111245SZhijun.Fu@Sun.COM /* 74211245SZhijun.Fu@Sun.COM * init pcie_bus_t for root complex 74311245SZhijun.Fu@Sun.COM * 74411245SZhijun.Fu@Sun.COM * Only a few of the fields in bus_t is valid for root complex. 74511245SZhijun.Fu@Sun.COM * The fields that are bracketed are initialized in this routine: 74611245SZhijun.Fu@Sun.COM * 74711245SZhijun.Fu@Sun.COM * dev_info_t * <bus_dip> 74811245SZhijun.Fu@Sun.COM * dev_info_t * bus_rp_dip 74911245SZhijun.Fu@Sun.COM * ddi_acc_handle_t bus_cfg_hdl 75011245SZhijun.Fu@Sun.COM * uint_t <bus_fm_flags> 75111245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_bdf 75211245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_rp_bdf 75311245SZhijun.Fu@Sun.COM * uint32_t bus_dev_ven_id 75411245SZhijun.Fu@Sun.COM * uint8_t bus_rev_id 75511245SZhijun.Fu@Sun.COM * uint8_t <bus_hdr_type> 75611245SZhijun.Fu@Sun.COM * uint16_t <bus_dev_type> 75711245SZhijun.Fu@Sun.COM * uint8_t bus_bdg_secbus 75811245SZhijun.Fu@Sun.COM * uint16_t bus_pcie_off 75911245SZhijun.Fu@Sun.COM * uint16_t <bus_aer_off> 76011245SZhijun.Fu@Sun.COM * uint16_t bus_pcix_off 76111245SZhijun.Fu@Sun.COM * uint16_t bus_ecc_ver 76211245SZhijun.Fu@Sun.COM * pci_bus_range_t bus_bus_range 76311245SZhijun.Fu@Sun.COM * ppb_ranges_t * bus_addr_ranges 76411245SZhijun.Fu@Sun.COM * int bus_addr_entries 76511245SZhijun.Fu@Sun.COM * pci_regspec_t * bus_assigned_addr 76611245SZhijun.Fu@Sun.COM * int bus_assigned_entries 76711245SZhijun.Fu@Sun.COM * pf_data_t * bus_pfd 76811245SZhijun.Fu@Sun.COM * int bus_mps 76911245SZhijun.Fu@Sun.COM * uint64_t bus_cfgacc_base 77011245SZhijun.Fu@Sun.COM * void * bus_plat_private 77111245SZhijun.Fu@Sun.COM */ 77210187SKrishna.Elango@Sun.COM void 77310187SKrishna.Elango@Sun.COM pcie_rc_init_bus(dev_info_t *dip) 77410187SKrishna.Elango@Sun.COM { 77510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 77610187SKrishna.Elango@Sun.COM 77710187SKrishna.Elango@Sun.COM bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP); 77810187SKrishna.Elango@Sun.COM bus_p->bus_dip = dip; 77910187SKrishna.Elango@Sun.COM bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO; 78010187SKrishna.Elango@Sun.COM bus_p->bus_hdr_type = PCI_HEADER_ONE; 78110187SKrishna.Elango@Sun.COM 78210187SKrishna.Elango@Sun.COM /* Fake that there are AER logs */ 78310187SKrishna.Elango@Sun.COM bus_p->bus_aer_off = (uint16_t)-1; 78410187SKrishna.Elango@Sun.COM 78510187SKrishna.Elango@Sun.COM /* Needed only for handle lookup */ 78610187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags |= PF_FM_READY; 78710187SKrishna.Elango@Sun.COM 78810187SKrishna.Elango@Sun.COM ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p); 78910187SKrishna.Elango@Sun.COM } 79010187SKrishna.Elango@Sun.COM 79110187SKrishna.Elango@Sun.COM void 79210187SKrishna.Elango@Sun.COM pcie_rc_fini_bus(dev_info_t *dip) 79310187SKrishna.Elango@Sun.COM { 79411245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2DOWNBUS(dip); 79510187SKrishna.Elango@Sun.COM ndi_set_bus_private(dip, B_FALSE, NULL, NULL); 79610187SKrishna.Elango@Sun.COM kmem_free(bus_p, sizeof (pcie_bus_t)); 79710187SKrishna.Elango@Sun.COM } 79810187SKrishna.Elango@Sun.COM 79910187SKrishna.Elango@Sun.COM /* 80011245SZhijun.Fu@Sun.COM * partially init pcie_bus_t for device (dip,bdf) for accessing pci 80111245SZhijun.Fu@Sun.COM * config space 80211245SZhijun.Fu@Sun.COM * 80311245SZhijun.Fu@Sun.COM * This routine is invoked during boot, either after creating a devinfo node 80411245SZhijun.Fu@Sun.COM * (x86 case) or during px driver attach (sparc case); it is also invoked 80511245SZhijun.Fu@Sun.COM * in hotplug context after a devinfo node is created. 80611245SZhijun.Fu@Sun.COM * 80711245SZhijun.Fu@Sun.COM * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL 80811245SZhijun.Fu@Sun.COM * is set: 80910187SKrishna.Elango@Sun.COM * 81011245SZhijun.Fu@Sun.COM * dev_info_t * <bus_dip> 81111245SZhijun.Fu@Sun.COM * dev_info_t * <bus_rp_dip> 81211245SZhijun.Fu@Sun.COM * ddi_acc_handle_t bus_cfg_hdl 81311245SZhijun.Fu@Sun.COM * uint_t bus_fm_flags 81411245SZhijun.Fu@Sun.COM * pcie_req_id_t <bus_bdf> 81511245SZhijun.Fu@Sun.COM * pcie_req_id_t <bus_rp_bdf> 81611245SZhijun.Fu@Sun.COM * uint32_t <bus_dev_ven_id> 81711245SZhijun.Fu@Sun.COM * uint8_t <bus_rev_id> 81811245SZhijun.Fu@Sun.COM * uint8_t <bus_hdr_type> 81911245SZhijun.Fu@Sun.COM * uint16_t <bus_dev_type> 82011245SZhijun.Fu@Sun.COM * uint8_t <bus_bdg_secbus 82111245SZhijun.Fu@Sun.COM * uint16_t <bus_pcie_off> 82211245SZhijun.Fu@Sun.COM * uint16_t <bus_aer_off> 82311245SZhijun.Fu@Sun.COM * uint16_t <bus_pcix_off> 82411245SZhijun.Fu@Sun.COM * uint16_t <bus_ecc_ver> 82511245SZhijun.Fu@Sun.COM * pci_bus_range_t bus_bus_range 82611245SZhijun.Fu@Sun.COM * ppb_ranges_t * bus_addr_ranges 82711245SZhijun.Fu@Sun.COM * int bus_addr_entries 82811245SZhijun.Fu@Sun.COM * pci_regspec_t * bus_assigned_addr 82911245SZhijun.Fu@Sun.COM * int bus_assigned_entries 83011245SZhijun.Fu@Sun.COM * pf_data_t * bus_pfd 83111245SZhijun.Fu@Sun.COM * int bus_mps 83211245SZhijun.Fu@Sun.COM * uint64_t bus_cfgacc_base 83311245SZhijun.Fu@Sun.COM * void * bus_plat_private 83411245SZhijun.Fu@Sun.COM * 83511245SZhijun.Fu@Sun.COM * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL 83611245SZhijun.Fu@Sun.COM * is set: 83711245SZhijun.Fu@Sun.COM * 83811245SZhijun.Fu@Sun.COM * dev_info_t * bus_dip 83911245SZhijun.Fu@Sun.COM * dev_info_t * bus_rp_dip 84011245SZhijun.Fu@Sun.COM * ddi_acc_handle_t bus_cfg_hdl 84111245SZhijun.Fu@Sun.COM * uint_t bus_fm_flags 84211245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_bdf 84311245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_rp_bdf 84411245SZhijun.Fu@Sun.COM * uint32_t bus_dev_ven_id 84511245SZhijun.Fu@Sun.COM * uint8_t bus_rev_id 84611245SZhijun.Fu@Sun.COM * uint8_t bus_hdr_type 84711245SZhijun.Fu@Sun.COM * uint16_t bus_dev_type 84811245SZhijun.Fu@Sun.COM * uint8_t <bus_bdg_secbus> 84911245SZhijun.Fu@Sun.COM * uint16_t bus_pcie_off 85011245SZhijun.Fu@Sun.COM * uint16_t bus_aer_off 85111245SZhijun.Fu@Sun.COM * uint16_t bus_pcix_off 85211245SZhijun.Fu@Sun.COM * uint16_t bus_ecc_ver 85311245SZhijun.Fu@Sun.COM * pci_bus_range_t <bus_bus_range> 85411245SZhijun.Fu@Sun.COM * ppb_ranges_t * <bus_addr_ranges> 85511245SZhijun.Fu@Sun.COM * int <bus_addr_entries> 85611245SZhijun.Fu@Sun.COM * pci_regspec_t * <bus_assigned_addr> 85711245SZhijun.Fu@Sun.COM * int <bus_assigned_entries> 85811245SZhijun.Fu@Sun.COM * pf_data_t * <bus_pfd> 85911245SZhijun.Fu@Sun.COM * int bus_mps 86011245SZhijun.Fu@Sun.COM * uint64_t bus_cfgacc_base 86111245SZhijun.Fu@Sun.COM * void * <bus_plat_private> 86210187SKrishna.Elango@Sun.COM */ 86311245SZhijun.Fu@Sun.COM 86410187SKrishna.Elango@Sun.COM pcie_bus_t * 86511245SZhijun.Fu@Sun.COM pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf, uint8_t flags) 86610187SKrishna.Elango@Sun.COM { 86711245SZhijun.Fu@Sun.COM uint16_t status, base, baseptr, num_cap; 86811245SZhijun.Fu@Sun.COM uint32_t capid; 86911245SZhijun.Fu@Sun.COM int range_size; 87011245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p; 87111245SZhijun.Fu@Sun.COM dev_info_t *rcdip; 87211245SZhijun.Fu@Sun.COM dev_info_t *pdip; 87311245SZhijun.Fu@Sun.COM const char *errstr = NULL; 87410187SKrishna.Elango@Sun.COM 87511245SZhijun.Fu@Sun.COM if (!(flags & PCIE_BUS_INITIAL)) 87611245SZhijun.Fu@Sun.COM goto initial_done; 87710187SKrishna.Elango@Sun.COM 87810187SKrishna.Elango@Sun.COM bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP); 87910187SKrishna.Elango@Sun.COM 88011245SZhijun.Fu@Sun.COM bus_p->bus_dip = dip; 88111245SZhijun.Fu@Sun.COM bus_p->bus_bdf = bdf; 88210187SKrishna.Elango@Sun.COM 88311245SZhijun.Fu@Sun.COM rcdip = pcie_get_rc_dip(dip); 88411245SZhijun.Fu@Sun.COM ASSERT(rcdip != NULL); 88510187SKrishna.Elango@Sun.COM 88611245SZhijun.Fu@Sun.COM /* Save the Vendor ID, Device ID and revision ID */ 88711245SZhijun.Fu@Sun.COM bus_p->bus_dev_ven_id = pci_cfgacc_get32(rcdip, bdf, PCI_CONF_VENID); 88811245SZhijun.Fu@Sun.COM bus_p->bus_rev_id = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID); 88910187SKrishna.Elango@Sun.COM /* Save the Header Type */ 89011245SZhijun.Fu@Sun.COM bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER); 89110187SKrishna.Elango@Sun.COM bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M; 89210187SKrishna.Elango@Sun.COM 89311245SZhijun.Fu@Sun.COM /* 89411245SZhijun.Fu@Sun.COM * Figure out the device type and all the relavant capability offsets 89511245SZhijun.Fu@Sun.COM */ 89611245SZhijun.Fu@Sun.COM /* set default value */ 89711245SZhijun.Fu@Sun.COM bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO; 89810187SKrishna.Elango@Sun.COM 89911245SZhijun.Fu@Sun.COM status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT); 90011245SZhijun.Fu@Sun.COM if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP)) 90111245SZhijun.Fu@Sun.COM goto caps_done; /* capability not supported */ 90211245SZhijun.Fu@Sun.COM 90311245SZhijun.Fu@Sun.COM /* Relevant conventional capabilities first */ 90411245SZhijun.Fu@Sun.COM 90511245SZhijun.Fu@Sun.COM /* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */ 90611245SZhijun.Fu@Sun.COM num_cap = 2; 90710923SEvan.Yan@Sun.COM 90811245SZhijun.Fu@Sun.COM switch (bus_p->bus_hdr_type) { 90911245SZhijun.Fu@Sun.COM case PCI_HEADER_ZERO: 91011245SZhijun.Fu@Sun.COM baseptr = PCI_CONF_CAP_PTR; 91111245SZhijun.Fu@Sun.COM break; 91211245SZhijun.Fu@Sun.COM case PCI_HEADER_PPB: 91311245SZhijun.Fu@Sun.COM baseptr = PCI_BCNF_CAP_PTR; 91411245SZhijun.Fu@Sun.COM break; 91511245SZhijun.Fu@Sun.COM case PCI_HEADER_CARDBUS: 91611245SZhijun.Fu@Sun.COM baseptr = PCI_CBUS_CAP_PTR; 91711245SZhijun.Fu@Sun.COM break; 91811245SZhijun.Fu@Sun.COM default: 91911245SZhijun.Fu@Sun.COM cmn_err(CE_WARN, "%s: unexpected pci header type:%x", 92011245SZhijun.Fu@Sun.COM __func__, bus_p->bus_hdr_type); 92111245SZhijun.Fu@Sun.COM goto caps_done; 92210187SKrishna.Elango@Sun.COM } 92310187SKrishna.Elango@Sun.COM 92411245SZhijun.Fu@Sun.COM base = baseptr; 92511245SZhijun.Fu@Sun.COM for (base = pci_cfgacc_get8(rcdip, bdf, base); base && num_cap; 92611245SZhijun.Fu@Sun.COM base = pci_cfgacc_get8(rcdip, bdf, base + PCI_CAP_NEXT_PTR)) { 92711245SZhijun.Fu@Sun.COM capid = pci_cfgacc_get8(rcdip, bdf, base); 92811245SZhijun.Fu@Sun.COM switch (capid) { 92911245SZhijun.Fu@Sun.COM case PCI_CAP_ID_PCI_E: 93011245SZhijun.Fu@Sun.COM bus_p->bus_pcie_off = base; 93111245SZhijun.Fu@Sun.COM bus_p->bus_dev_type = pci_cfgacc_get16(rcdip, bdf, 93211245SZhijun.Fu@Sun.COM base + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 93311245SZhijun.Fu@Sun.COM 93411245SZhijun.Fu@Sun.COM /* Check and save PCIe hotplug capability information */ 93511245SZhijun.Fu@Sun.COM if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) && 93611245SZhijun.Fu@Sun.COM (pci_cfgacc_get16(rcdip, bdf, base + PCIE_PCIECAP) 93711245SZhijun.Fu@Sun.COM & PCIE_PCIECAP_SLOT_IMPL) && 93811245SZhijun.Fu@Sun.COM (pci_cfgacc_get32(rcdip, bdf, base + PCIE_SLOTCAP) 93911245SZhijun.Fu@Sun.COM & PCIE_SLOTCAP_HP_CAPABLE)) 94011245SZhijun.Fu@Sun.COM bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE; 94110923SEvan.Yan@Sun.COM 94211245SZhijun.Fu@Sun.COM num_cap--; 94311245SZhijun.Fu@Sun.COM break; 94411245SZhijun.Fu@Sun.COM case PCI_CAP_ID_PCIX: 94511245SZhijun.Fu@Sun.COM bus_p->bus_pcix_off = base; 94611245SZhijun.Fu@Sun.COM if (PCIE_IS_BDG(bus_p)) 94711245SZhijun.Fu@Sun.COM bus_p->bus_ecc_ver = 94811245SZhijun.Fu@Sun.COM pci_cfgacc_get16(rcdip, bdf, base + 94911245SZhijun.Fu@Sun.COM PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 95011245SZhijun.Fu@Sun.COM else 95111245SZhijun.Fu@Sun.COM bus_p->bus_ecc_ver = 95211245SZhijun.Fu@Sun.COM pci_cfgacc_get16(rcdip, bdf, base + 95311245SZhijun.Fu@Sun.COM PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK; 95411245SZhijun.Fu@Sun.COM num_cap--; 95511245SZhijun.Fu@Sun.COM break; 95611245SZhijun.Fu@Sun.COM default: 95711245SZhijun.Fu@Sun.COM break; 95810187SKrishna.Elango@Sun.COM } 95910187SKrishna.Elango@Sun.COM } 96010187SKrishna.Elango@Sun.COM 96111245SZhijun.Fu@Sun.COM /* Check and save PCI hotplug (SHPC) capability information */ 96211245SZhijun.Fu@Sun.COM if (PCIE_IS_BDG(bus_p)) { 96311245SZhijun.Fu@Sun.COM base = baseptr; 96411245SZhijun.Fu@Sun.COM for (base = pci_cfgacc_get8(rcdip, bdf, base); 96511245SZhijun.Fu@Sun.COM base; base = pci_cfgacc_get8(rcdip, bdf, 96611245SZhijun.Fu@Sun.COM base + PCI_CAP_NEXT_PTR)) { 96711245SZhijun.Fu@Sun.COM capid = pci_cfgacc_get8(rcdip, bdf, base); 96811245SZhijun.Fu@Sun.COM if (capid == PCI_CAP_ID_PCI_HOTPLUG) { 96911245SZhijun.Fu@Sun.COM bus_p->bus_pci_hp_off = base; 97011245SZhijun.Fu@Sun.COM bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE; 97111245SZhijun.Fu@Sun.COM break; 97211245SZhijun.Fu@Sun.COM } 97311245SZhijun.Fu@Sun.COM } 97411245SZhijun.Fu@Sun.COM } 97511245SZhijun.Fu@Sun.COM 97611245SZhijun.Fu@Sun.COM /* Then, relevant extended capabilities */ 97710187SKrishna.Elango@Sun.COM 97811245SZhijun.Fu@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 97911245SZhijun.Fu@Sun.COM goto caps_done; 98011245SZhijun.Fu@Sun.COM 98111245SZhijun.Fu@Sun.COM /* Extended caps: PCIE_EXT_CAP_ID_AER */ 98211245SZhijun.Fu@Sun.COM for (base = PCIE_EXT_CAP; base; base = (capid >> 98311245SZhijun.Fu@Sun.COM PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) { 98411245SZhijun.Fu@Sun.COM capid = pci_cfgacc_get32(rcdip, bdf, base); 98511245SZhijun.Fu@Sun.COM if (capid == PCI_CAP_EINVAL32) 98611245SZhijun.Fu@Sun.COM break; 98711245SZhijun.Fu@Sun.COM if (((capid >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK) 98811245SZhijun.Fu@Sun.COM == PCIE_EXT_CAP_ID_AER) { 98911245SZhijun.Fu@Sun.COM bus_p->bus_aer_off = base; 99011245SZhijun.Fu@Sun.COM break; 99111245SZhijun.Fu@Sun.COM } 99211245SZhijun.Fu@Sun.COM } 99311245SZhijun.Fu@Sun.COM 99411245SZhijun.Fu@Sun.COM caps_done: 99510187SKrishna.Elango@Sun.COM /* save RP dip and RP bdf */ 99610187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) { 99711245SZhijun.Fu@Sun.COM bus_p->bus_rp_dip = dip; 99810187SKrishna.Elango@Sun.COM bus_p->bus_rp_bdf = bus_p->bus_bdf; 99910187SKrishna.Elango@Sun.COM } else { 100011245SZhijun.Fu@Sun.COM for (pdip = ddi_get_parent(dip); pdip; 100110187SKrishna.Elango@Sun.COM pdip = ddi_get_parent(pdip)) { 100210187SKrishna.Elango@Sun.COM pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip); 100310187SKrishna.Elango@Sun.COM 100410187SKrishna.Elango@Sun.COM /* 100511245SZhijun.Fu@Sun.COM * If RP dip and RP bdf in parent's bus_t have 100611245SZhijun.Fu@Sun.COM * been initialized, simply use these instead of 100711245SZhijun.Fu@Sun.COM * continuing up to the RC. 100811245SZhijun.Fu@Sun.COM */ 100911245SZhijun.Fu@Sun.COM if (parent_bus_p->bus_rp_dip != NULL) { 101011245SZhijun.Fu@Sun.COM bus_p->bus_rp_dip = parent_bus_p->bus_rp_dip; 101111245SZhijun.Fu@Sun.COM bus_p->bus_rp_bdf = parent_bus_p->bus_rp_bdf; 101211245SZhijun.Fu@Sun.COM break; 101311245SZhijun.Fu@Sun.COM } 101411245SZhijun.Fu@Sun.COM 101511245SZhijun.Fu@Sun.COM /* 101610187SKrishna.Elango@Sun.COM * When debugging be aware that some NVIDIA x86 101710187SKrishna.Elango@Sun.COM * architectures have 2 nodes for each RP, One at Bus 101810187SKrishna.Elango@Sun.COM * 0x0 and one at Bus 0x80. The requester is from Bus 101910187SKrishna.Elango@Sun.COM * 0x80 102010187SKrishna.Elango@Sun.COM */ 102110187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(parent_bus_p)) { 102210187SKrishna.Elango@Sun.COM bus_p->bus_rp_dip = pdip; 102310187SKrishna.Elango@Sun.COM bus_p->bus_rp_bdf = parent_bus_p->bus_bdf; 102410187SKrishna.Elango@Sun.COM break; 102510187SKrishna.Elango@Sun.COM } 102610187SKrishna.Elango@Sun.COM } 102710187SKrishna.Elango@Sun.COM } 102810187SKrishna.Elango@Sun.COM 102911245SZhijun.Fu@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED; 103011245SZhijun.Fu@Sun.COM bus_p->bus_fm_flags = 0; 103111245SZhijun.Fu@Sun.COM bus_p->bus_mps = 0; 103210187SKrishna.Elango@Sun.COM 103311245SZhijun.Fu@Sun.COM ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p); 103411245SZhijun.Fu@Sun.COM 103511245SZhijun.Fu@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip)) 103611245SZhijun.Fu@Sun.COM (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip, 103710923SEvan.Yan@Sun.COM "hotplug-capable"); 103810923SEvan.Yan@Sun.COM 103911245SZhijun.Fu@Sun.COM initial_done: 104011245SZhijun.Fu@Sun.COM if (!(flags & PCIE_BUS_FINAL)) 104111245SZhijun.Fu@Sun.COM goto final_done; 104211245SZhijun.Fu@Sun.COM 104311245SZhijun.Fu@Sun.COM /* already initialized? */ 104411245SZhijun.Fu@Sun.COM bus_p = PCIE_DIP2BUS(dip); 104511245SZhijun.Fu@Sun.COM 104611245SZhijun.Fu@Sun.COM /* Save the Range information if device is a switch/bridge */ 104711245SZhijun.Fu@Sun.COM if (PCIE_IS_BDG(bus_p)) { 104811245SZhijun.Fu@Sun.COM /* get "bus_range" property */ 104911245SZhijun.Fu@Sun.COM range_size = sizeof (pci_bus_range_t); 105011245SZhijun.Fu@Sun.COM if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 105111245SZhijun.Fu@Sun.COM "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size) 105211245SZhijun.Fu@Sun.COM != DDI_PROP_SUCCESS) { 105311245SZhijun.Fu@Sun.COM errstr = "Cannot find \"bus-range\" property"; 105411245SZhijun.Fu@Sun.COM cmn_err(CE_WARN, 105511245SZhijun.Fu@Sun.COM "PCIE init err info failed BDF 0x%x:%s\n", 105611245SZhijun.Fu@Sun.COM bus_p->bus_bdf, errstr); 105711245SZhijun.Fu@Sun.COM } 105811245SZhijun.Fu@Sun.COM 105911245SZhijun.Fu@Sun.COM /* get secondary bus number */ 106011245SZhijun.Fu@Sun.COM rcdip = pcie_get_rc_dip(dip); 106111245SZhijun.Fu@Sun.COM ASSERT(rcdip != NULL); 106210187SKrishna.Elango@Sun.COM 106311245SZhijun.Fu@Sun.COM bus_p->bus_bdg_secbus = pci_cfgacc_get8(rcdip, 106411245SZhijun.Fu@Sun.COM bus_p->bus_bdf, PCI_BCNF_SECBUS); 106511245SZhijun.Fu@Sun.COM 106611245SZhijun.Fu@Sun.COM /* Get "ranges" property */ 106711245SZhijun.Fu@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 106811245SZhijun.Fu@Sun.COM "ranges", (caddr_t)&bus_p->bus_addr_ranges, 106911245SZhijun.Fu@Sun.COM &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS) 107011245SZhijun.Fu@Sun.COM bus_p->bus_addr_entries = 0; 107111245SZhijun.Fu@Sun.COM bus_p->bus_addr_entries /= sizeof (ppb_ranges_t); 107211245SZhijun.Fu@Sun.COM } 107310187SKrishna.Elango@Sun.COM 107411245SZhijun.Fu@Sun.COM /* save "assigned-addresses" property array, ignore failues */ 107511245SZhijun.Fu@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 107611245SZhijun.Fu@Sun.COM "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr, 107711245SZhijun.Fu@Sun.COM &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS) 107811245SZhijun.Fu@Sun.COM bus_p->bus_assigned_entries /= sizeof (pci_regspec_t); 107911245SZhijun.Fu@Sun.COM else 108011245SZhijun.Fu@Sun.COM bus_p->bus_assigned_entries = 0; 108111245SZhijun.Fu@Sun.COM 108211245SZhijun.Fu@Sun.COM pcie_init_pfd(dip); 108311245SZhijun.Fu@Sun.COM 108411245SZhijun.Fu@Sun.COM pcie_init_plat(dip); 108511245SZhijun.Fu@Sun.COM 108611245SZhijun.Fu@Sun.COM final_done: 108710187SKrishna.Elango@Sun.COM 108810187SKrishna.Elango@Sun.COM PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n", 108911245SZhijun.Fu@Sun.COM ddi_driver_name(dip), (void *)dip, bus_p->bus_bdf, 109010187SKrishna.Elango@Sun.COM bus_p->bus_bdg_secbus); 109110187SKrishna.Elango@Sun.COM #ifdef DEBUG 109210187SKrishna.Elango@Sun.COM pcie_print_bus(bus_p); 109310187SKrishna.Elango@Sun.COM #endif 109410187SKrishna.Elango@Sun.COM 109510187SKrishna.Elango@Sun.COM return (bus_p); 109611245SZhijun.Fu@Sun.COM } 109711245SZhijun.Fu@Sun.COM 109811245SZhijun.Fu@Sun.COM /* 109911245SZhijun.Fu@Sun.COM * Invoked before destroying devinfo node, mostly during hotplug 110011245SZhijun.Fu@Sun.COM * operation to free pcie_bus_t data structure 110111245SZhijun.Fu@Sun.COM */ 110211245SZhijun.Fu@Sun.COM /* ARGSUSED */ 110311245SZhijun.Fu@Sun.COM void 110411245SZhijun.Fu@Sun.COM pcie_fini_bus(dev_info_t *dip, uint8_t flags) 110511245SZhijun.Fu@Sun.COM { 110611245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 110711245SZhijun.Fu@Sun.COM ASSERT(bus_p); 110811245SZhijun.Fu@Sun.COM 110911245SZhijun.Fu@Sun.COM if (flags & PCIE_BUS_INITIAL) { 111011245SZhijun.Fu@Sun.COM pcie_fini_plat(dip); 111111245SZhijun.Fu@Sun.COM pcie_fini_pfd(dip); 111211245SZhijun.Fu@Sun.COM 111311245SZhijun.Fu@Sun.COM kmem_free(bus_p->bus_assigned_addr, 111411245SZhijun.Fu@Sun.COM (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries)); 111511245SZhijun.Fu@Sun.COM kmem_free(bus_p->bus_addr_ranges, 111611245SZhijun.Fu@Sun.COM (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries)); 111711245SZhijun.Fu@Sun.COM /* zero out the fields that have been destroyed */ 111811245SZhijun.Fu@Sun.COM bus_p->bus_assigned_addr = NULL; 111911245SZhijun.Fu@Sun.COM bus_p->bus_addr_ranges = NULL; 112011245SZhijun.Fu@Sun.COM bus_p->bus_assigned_entries = 0; 112111245SZhijun.Fu@Sun.COM bus_p->bus_addr_entries = 0; 112211245SZhijun.Fu@Sun.COM } 112311245SZhijun.Fu@Sun.COM 112411245SZhijun.Fu@Sun.COM if (flags & PCIE_BUS_FINAL) { 112511245SZhijun.Fu@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip)) { 112611245SZhijun.Fu@Sun.COM (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, 112711245SZhijun.Fu@Sun.COM "hotplug-capable"); 112811245SZhijun.Fu@Sun.COM } 112911245SZhijun.Fu@Sun.COM 113011245SZhijun.Fu@Sun.COM ndi_set_bus_private(dip, B_TRUE, NULL, NULL); 113111245SZhijun.Fu@Sun.COM kmem_free(bus_p, sizeof (pcie_bus_t)); 113211245SZhijun.Fu@Sun.COM } 113310187SKrishna.Elango@Sun.COM } 113410187SKrishna.Elango@Sun.COM 113510187SKrishna.Elango@Sun.COM int 113610187SKrishna.Elango@Sun.COM pcie_postattach_child(dev_info_t *cdip) 113710187SKrishna.Elango@Sun.COM { 113810187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip); 113910187SKrishna.Elango@Sun.COM 114010187SKrishna.Elango@Sun.COM if (!bus_p) 114110187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 114210187SKrishna.Elango@Sun.COM 114310187SKrishna.Elango@Sun.COM return (pcie_enable_ce(cdip)); 114410187SKrishna.Elango@Sun.COM } 114510187SKrishna.Elango@Sun.COM 114610187SKrishna.Elango@Sun.COM /* 114710187SKrishna.Elango@Sun.COM * PCI-Express child device de-initialization. 114810187SKrishna.Elango@Sun.COM * This function disables generic pci-express interrupts and error 114910187SKrishna.Elango@Sun.COM * handling. 115010187SKrishna.Elango@Sun.COM */ 115110187SKrishna.Elango@Sun.COM void 115210187SKrishna.Elango@Sun.COM pcie_uninitchild(dev_info_t *cdip) 115310187SKrishna.Elango@Sun.COM { 115410187SKrishna.Elango@Sun.COM pcie_disable_errors(cdip); 115511245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(cdip); 115611245SZhijun.Fu@Sun.COM } 115711245SZhijun.Fu@Sun.COM 115811245SZhijun.Fu@Sun.COM /* 115911245SZhijun.Fu@Sun.COM * find the root complex dip 116011245SZhijun.Fu@Sun.COM */ 116111245SZhijun.Fu@Sun.COM dev_info_t * 116211245SZhijun.Fu@Sun.COM pcie_get_rc_dip(dev_info_t *dip) 116311245SZhijun.Fu@Sun.COM { 116411245SZhijun.Fu@Sun.COM dev_info_t *rcdip; 116511245SZhijun.Fu@Sun.COM pcie_bus_t *rc_bus_p; 116611245SZhijun.Fu@Sun.COM 116711245SZhijun.Fu@Sun.COM for (rcdip = ddi_get_parent(dip); rcdip; 116811245SZhijun.Fu@Sun.COM rcdip = ddi_get_parent(rcdip)) { 116911245SZhijun.Fu@Sun.COM rc_bus_p = PCIE_DIP2BUS(rcdip); 117011245SZhijun.Fu@Sun.COM if (rc_bus_p && PCIE_IS_RC(rc_bus_p)) 117111245SZhijun.Fu@Sun.COM break; 117211245SZhijun.Fu@Sun.COM } 117311245SZhijun.Fu@Sun.COM 117411245SZhijun.Fu@Sun.COM return (rcdip); 117511245SZhijun.Fu@Sun.COM } 117611245SZhijun.Fu@Sun.COM 117711245SZhijun.Fu@Sun.COM static boolean_t 117811245SZhijun.Fu@Sun.COM pcie_is_pci_device(dev_info_t *dip) 117911245SZhijun.Fu@Sun.COM { 118011245SZhijun.Fu@Sun.COM dev_info_t *pdip; 118111245SZhijun.Fu@Sun.COM char *device_type; 118211245SZhijun.Fu@Sun.COM 118311245SZhijun.Fu@Sun.COM pdip = ddi_get_parent(dip); 118411245SZhijun.Fu@Sun.COM ASSERT(pdip); 118511245SZhijun.Fu@Sun.COM 118611245SZhijun.Fu@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 118711245SZhijun.Fu@Sun.COM "device_type", &device_type) != DDI_PROP_SUCCESS) 118811245SZhijun.Fu@Sun.COM return (B_FALSE); 118911245SZhijun.Fu@Sun.COM 119011245SZhijun.Fu@Sun.COM if (strcmp(device_type, "pciex") != 0 && 119111245SZhijun.Fu@Sun.COM strcmp(device_type, "pci") != 0) { 119211245SZhijun.Fu@Sun.COM ddi_prop_free(device_type); 119311245SZhijun.Fu@Sun.COM return (B_FALSE); 119411245SZhijun.Fu@Sun.COM } 119511245SZhijun.Fu@Sun.COM 119611245SZhijun.Fu@Sun.COM ddi_prop_free(device_type); 119711245SZhijun.Fu@Sun.COM return (B_TRUE); 119811245SZhijun.Fu@Sun.COM } 119911245SZhijun.Fu@Sun.COM 120011245SZhijun.Fu@Sun.COM typedef struct { 120111245SZhijun.Fu@Sun.COM boolean_t init; 120211245SZhijun.Fu@Sun.COM uint8_t flags; 120311245SZhijun.Fu@Sun.COM } pcie_bus_arg_t; 120411245SZhijun.Fu@Sun.COM 120511245SZhijun.Fu@Sun.COM /*ARGSUSED*/ 120611245SZhijun.Fu@Sun.COM static int 120711245SZhijun.Fu@Sun.COM pcie_fab_do_init_fini(dev_info_t *dip, void *arg) 120811245SZhijun.Fu@Sun.COM { 120911245SZhijun.Fu@Sun.COM pcie_req_id_t bdf; 121011245SZhijun.Fu@Sun.COM pcie_bus_arg_t *bus_arg = (pcie_bus_arg_t *)arg; 121111245SZhijun.Fu@Sun.COM 121211245SZhijun.Fu@Sun.COM if (!pcie_is_pci_device(dip)) 121311245SZhijun.Fu@Sun.COM goto out; 121411245SZhijun.Fu@Sun.COM 121511245SZhijun.Fu@Sun.COM if (bus_arg->init) { 121611245SZhijun.Fu@Sun.COM if (pcie_get_bdf_from_dip(dip, &bdf) != DDI_SUCCESS) 121711245SZhijun.Fu@Sun.COM goto out; 121811245SZhijun.Fu@Sun.COM 121911245SZhijun.Fu@Sun.COM (void) pcie_init_bus(dip, bdf, bus_arg->flags); 122011245SZhijun.Fu@Sun.COM } else { 122111245SZhijun.Fu@Sun.COM (void) pcie_fini_bus(dip, bus_arg->flags); 122211245SZhijun.Fu@Sun.COM } 122311245SZhijun.Fu@Sun.COM 122411245SZhijun.Fu@Sun.COM return (DDI_WALK_CONTINUE); 122511245SZhijun.Fu@Sun.COM 122611245SZhijun.Fu@Sun.COM out: 122711245SZhijun.Fu@Sun.COM return (DDI_WALK_PRUNECHILD); 122810187SKrishna.Elango@Sun.COM } 122910187SKrishna.Elango@Sun.COM 123010187SKrishna.Elango@Sun.COM void 123111245SZhijun.Fu@Sun.COM pcie_fab_init_bus(dev_info_t *rcdip, uint8_t flags) 123210187SKrishna.Elango@Sun.COM { 123311245SZhijun.Fu@Sun.COM int circular_count; 123411245SZhijun.Fu@Sun.COM dev_info_t *dip = ddi_get_child(rcdip); 123511245SZhijun.Fu@Sun.COM pcie_bus_arg_t arg; 123610187SKrishna.Elango@Sun.COM 123711245SZhijun.Fu@Sun.COM arg.init = B_TRUE; 123811245SZhijun.Fu@Sun.COM arg.flags = flags; 123910187SKrishna.Elango@Sun.COM 124011245SZhijun.Fu@Sun.COM ndi_devi_enter(rcdip, &circular_count); 124111245SZhijun.Fu@Sun.COM ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg); 124211245SZhijun.Fu@Sun.COM ndi_devi_exit(rcdip, circular_count); 124311245SZhijun.Fu@Sun.COM } 124410923SEvan.Yan@Sun.COM 124511245SZhijun.Fu@Sun.COM void 124611245SZhijun.Fu@Sun.COM pcie_fab_fini_bus(dev_info_t *rcdip, uint8_t flags) 124711245SZhijun.Fu@Sun.COM { 124811245SZhijun.Fu@Sun.COM int circular_count; 124911245SZhijun.Fu@Sun.COM dev_info_t *dip = ddi_get_child(rcdip); 125011245SZhijun.Fu@Sun.COM pcie_bus_arg_t arg; 125110923SEvan.Yan@Sun.COM 125211245SZhijun.Fu@Sun.COM arg.init = B_FALSE; 125311245SZhijun.Fu@Sun.COM arg.flags = flags; 125410187SKrishna.Elango@Sun.COM 125511245SZhijun.Fu@Sun.COM ndi_devi_enter(rcdip, &circular_count); 125611245SZhijun.Fu@Sun.COM ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg); 125711245SZhijun.Fu@Sun.COM ndi_devi_exit(rcdip, circular_count); 125810187SKrishna.Elango@Sun.COM } 125910187SKrishna.Elango@Sun.COM 126010187SKrishna.Elango@Sun.COM void 126110187SKrishna.Elango@Sun.COM pcie_enable_errors(dev_info_t *dip) 126210187SKrishna.Elango@Sun.COM { 126310187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 126410187SKrishna.Elango@Sun.COM uint16_t reg16, tmp16; 126510187SKrishna.Elango@Sun.COM uint32_t reg32, tmp32; 126610187SKrishna.Elango@Sun.COM 126710187SKrishna.Elango@Sun.COM ASSERT(bus_p); 126810187SKrishna.Elango@Sun.COM 126910187SKrishna.Elango@Sun.COM /* 127010187SKrishna.Elango@Sun.COM * Clear any pending errors 127110187SKrishna.Elango@Sun.COM */ 127210187SKrishna.Elango@Sun.COM pcie_clear_errors(dip); 127310187SKrishna.Elango@Sun.COM 127410187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 127510187SKrishna.Elango@Sun.COM return; 127610187SKrishna.Elango@Sun.COM 127710187SKrishna.Elango@Sun.COM /* 127810187SKrishna.Elango@Sun.COM * Enable Baseline Error Handling but leave CE reporting off (poweron 127910187SKrishna.Elango@Sun.COM * default). 128010187SKrishna.Elango@Sun.COM */ 128110187SKrishna.Elango@Sun.COM if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) != 128210187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 128310187SKrishna.Elango@Sun.COM tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK | 128410187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 128510187SKrishna.Elango@Sun.COM (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 128610187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 128710187SKrishna.Elango@Sun.COM (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN)); 128810187SKrishna.Elango@Sun.COM 128910187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16); 129010187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16); 129110187SKrishna.Elango@Sun.COM } 129210187SKrishna.Elango@Sun.COM 129310187SKrishna.Elango@Sun.COM /* Enable Root Port Baseline Error Receiving */ 129410187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p) && 129510187SKrishna.Elango@Sun.COM (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) != 129610187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 129710187SKrishna.Elango@Sun.COM 129810187SKrishna.Elango@Sun.COM tmp16 = pcie_serr_disable_flag ? 129910187SKrishna.Elango@Sun.COM (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) : 130010187SKrishna.Elango@Sun.COM pcie_root_ctrl_default; 130110187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16); 130210187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL, 130310187SKrishna.Elango@Sun.COM reg16); 130410187SKrishna.Elango@Sun.COM } 130510187SKrishna.Elango@Sun.COM 130610187SKrishna.Elango@Sun.COM /* 130710187SKrishna.Elango@Sun.COM * Enable PCI-Express Advanced Error Handling if Exists 130810187SKrishna.Elango@Sun.COM */ 130910187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 131010187SKrishna.Elango@Sun.COM return; 131110187SKrishna.Elango@Sun.COM 131210187SKrishna.Elango@Sun.COM /* Set Uncorrectable Severity */ 131310187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) != 131410187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 131510187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_uce_severity; 131610187SKrishna.Elango@Sun.COM 131710187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32); 131810187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV, 131910187SKrishna.Elango@Sun.COM reg32); 132010187SKrishna.Elango@Sun.COM } 132110187SKrishna.Elango@Sun.COM 132210187SKrishna.Elango@Sun.COM /* Enable Uncorrectable errors */ 132310187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) != 132410187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 132510187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_uce_mask; 132610187SKrishna.Elango@Sun.COM 132710187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32); 132810187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK, 132910187SKrishna.Elango@Sun.COM reg32); 133010187SKrishna.Elango@Sun.COM } 133110187SKrishna.Elango@Sun.COM 133210187SKrishna.Elango@Sun.COM /* Enable ECRC generation and checking */ 133310187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) != 133410187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 133510187SKrishna.Elango@Sun.COM tmp32 = reg32 | pcie_ecrc_value; 133610187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32); 133710187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32); 133810187SKrishna.Elango@Sun.COM } 133910187SKrishna.Elango@Sun.COM 134010187SKrishna.Elango@Sun.COM /* Enable Secondary Uncorrectable errors if this is a bridge */ 134110187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) 134210187SKrishna.Elango@Sun.COM goto root; 134310187SKrishna.Elango@Sun.COM 134410187SKrishna.Elango@Sun.COM /* Set Uncorrectable Severity */ 134510187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) != 134610187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 134710187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_suce_severity; 134810187SKrishna.Elango@Sun.COM 134910187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32); 135010187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV, 135110187SKrishna.Elango@Sun.COM reg32); 135210187SKrishna.Elango@Sun.COM } 135310187SKrishna.Elango@Sun.COM 135410187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) != 135510187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 135610187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask); 135710187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32, 135810187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MASK, reg32); 135910187SKrishna.Elango@Sun.COM } 136010187SKrishna.Elango@Sun.COM 136110187SKrishna.Elango@Sun.COM root: 136210187SKrishna.Elango@Sun.COM /* 136310187SKrishna.Elango@Sun.COM * Enable Root Control this is a Root device 136410187SKrishna.Elango@Sun.COM */ 136510187SKrishna.Elango@Sun.COM if (!PCIE_IS_ROOT(bus_p)) 136610187SKrishna.Elango@Sun.COM return; 136710187SKrishna.Elango@Sun.COM 136810187SKrishna.Elango@Sun.COM if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) != 136910187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 137010187SKrishna.Elango@Sun.COM PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD, 137110187SKrishna.Elango@Sun.COM pcie_root_error_cmd_default); 137210187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16, 137310187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD, reg16); 137410187SKrishna.Elango@Sun.COM } 137510187SKrishna.Elango@Sun.COM } 137610187SKrishna.Elango@Sun.COM 137710187SKrishna.Elango@Sun.COM /* 137810187SKrishna.Elango@Sun.COM * This function is used for enabling CE reporting and setting the AER CE mask. 137910187SKrishna.Elango@Sun.COM * When called from outside the pcie module it should always be preceded by 138010187SKrishna.Elango@Sun.COM * a call to pcie_enable_errors. 138110187SKrishna.Elango@Sun.COM */ 138210187SKrishna.Elango@Sun.COM int 138310187SKrishna.Elango@Sun.COM pcie_enable_ce(dev_info_t *dip) 138410187SKrishna.Elango@Sun.COM { 138510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 138610187SKrishna.Elango@Sun.COM uint16_t device_sts, device_ctl; 138710187SKrishna.Elango@Sun.COM uint32_t tmp_pcie_aer_ce_mask; 138810187SKrishna.Elango@Sun.COM 138910187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 139010187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 139110187SKrishna.Elango@Sun.COM 139210187SKrishna.Elango@Sun.COM /* 139310187SKrishna.Elango@Sun.COM * The "pcie_ce_mask" property is used to control both the CE reporting 139410187SKrishna.Elango@Sun.COM * enable field in the device control register and the AER CE mask. We 139510187SKrishna.Elango@Sun.COM * leave CE reporting disabled if pcie_ce_mask is set to -1. 139610187SKrishna.Elango@Sun.COM */ 139710187SKrishna.Elango@Sun.COM 139810187SKrishna.Elango@Sun.COM tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 139910187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask); 140010187SKrishna.Elango@Sun.COM 140110187SKrishna.Elango@Sun.COM if (tmp_pcie_aer_ce_mask == (uint32_t)-1) { 140210187SKrishna.Elango@Sun.COM /* 140310187SKrishna.Elango@Sun.COM * Nothing to do since CE reporting has already been disabled. 140410187SKrishna.Elango@Sun.COM */ 140510187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 140610187SKrishna.Elango@Sun.COM } 140710187SKrishna.Elango@Sun.COM 140810187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(bus_p)) { 140910187SKrishna.Elango@Sun.COM /* Enable AER CE */ 141010187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask); 141110187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK, 141210187SKrishna.Elango@Sun.COM 0); 141310187SKrishna.Elango@Sun.COM 141410187SKrishna.Elango@Sun.COM /* Clear any pending AER CE errors */ 141510187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1); 141610187SKrishna.Elango@Sun.COM } 141710187SKrishna.Elango@Sun.COM 141810187SKrishna.Elango@Sun.COM /* clear any pending CE errors */ 141910187SKrishna.Elango@Sun.COM if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) != 142010187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) 142110187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS, 142210187SKrishna.Elango@Sun.COM device_sts & (~PCIE_DEVSTS_CE_DETECTED)); 142310187SKrishna.Elango@Sun.COM 142410187SKrishna.Elango@Sun.COM /* Enable CE reporting */ 142510187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 142610187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, 142710187SKrishna.Elango@Sun.COM (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default); 142810187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl); 142910187SKrishna.Elango@Sun.COM 143010187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 143110187SKrishna.Elango@Sun.COM } 143210187SKrishna.Elango@Sun.COM 143310187SKrishna.Elango@Sun.COM /* ARGSUSED */ 143410187SKrishna.Elango@Sun.COM void 143510187SKrishna.Elango@Sun.COM pcie_disable_errors(dev_info_t *dip) 143610187SKrishna.Elango@Sun.COM { 143710187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 143810187SKrishna.Elango@Sun.COM uint16_t device_ctl; 143910187SKrishna.Elango@Sun.COM uint32_t aer_reg; 144010187SKrishna.Elango@Sun.COM 144110187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 144210187SKrishna.Elango@Sun.COM return; 144310187SKrishna.Elango@Sun.COM 144410187SKrishna.Elango@Sun.COM /* 144510187SKrishna.Elango@Sun.COM * Disable PCI-Express Baseline Error Handling 144610187SKrishna.Elango@Sun.COM */ 144710187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 144810187SKrishna.Elango@Sun.COM device_ctl &= ~PCIE_DEVCTL_ERR_MASK; 144910187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl); 145010187SKrishna.Elango@Sun.COM 145110187SKrishna.Elango@Sun.COM /* 145210187SKrishna.Elango@Sun.COM * Disable PCI-Express Advanced Error Handling if Exists 145310187SKrishna.Elango@Sun.COM */ 145410187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 145510187SKrishna.Elango@Sun.COM goto root; 145610187SKrishna.Elango@Sun.COM 145710187SKrishna.Elango@Sun.COM /* Disable Uncorrectable errors */ 145810187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS); 145910187SKrishna.Elango@Sun.COM 146010187SKrishna.Elango@Sun.COM /* Disable Correctable errors */ 146110187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS); 146210187SKrishna.Elango@Sun.COM 146310187SKrishna.Elango@Sun.COM /* Disable ECRC generation and checking */ 146410187SKrishna.Elango@Sun.COM if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) != 146510187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 146610187SKrishna.Elango@Sun.COM aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA | 146710187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_CHECK_ENA); 146810187SKrishna.Elango@Sun.COM 146910187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg); 147010187SKrishna.Elango@Sun.COM } 147110187SKrishna.Elango@Sun.COM /* 147210187SKrishna.Elango@Sun.COM * Disable Secondary Uncorrectable errors if this is a bridge 147310187SKrishna.Elango@Sun.COM */ 147410187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) 147510187SKrishna.Elango@Sun.COM goto root; 147610187SKrishna.Elango@Sun.COM 147710187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS); 147810187SKrishna.Elango@Sun.COM 147910187SKrishna.Elango@Sun.COM root: 148010187SKrishna.Elango@Sun.COM /* 148110187SKrishna.Elango@Sun.COM * disable Root Control this is a Root device 148210187SKrishna.Elango@Sun.COM */ 148310187SKrishna.Elango@Sun.COM if (!PCIE_IS_ROOT(bus_p)) 148410187SKrishna.Elango@Sun.COM return; 148510187SKrishna.Elango@Sun.COM 148610187SKrishna.Elango@Sun.COM if (!pcie_serr_disable_flag) { 148710187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL); 148810187SKrishna.Elango@Sun.COM device_ctl &= ~PCIE_ROOT_SYS_ERR; 148910187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl); 149010187SKrishna.Elango@Sun.COM } 149110187SKrishna.Elango@Sun.COM 149210187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 149310187SKrishna.Elango@Sun.COM return; 149410187SKrishna.Elango@Sun.COM 149510187SKrishna.Elango@Sun.COM if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) != 149610187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 149710187SKrishna.Elango@Sun.COM device_ctl &= ~pcie_root_error_cmd_default; 149810187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl); 149910187SKrishna.Elango@Sun.COM } 150010187SKrishna.Elango@Sun.COM } 150110187SKrishna.Elango@Sun.COM 150210187SKrishna.Elango@Sun.COM /* 150310187SKrishna.Elango@Sun.COM * Extract bdf from "reg" property. 150410187SKrishna.Elango@Sun.COM */ 150510187SKrishna.Elango@Sun.COM int 150610187SKrishna.Elango@Sun.COM pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf) 150710187SKrishna.Elango@Sun.COM { 150810187SKrishna.Elango@Sun.COM pci_regspec_t *regspec; 150910187SKrishna.Elango@Sun.COM int reglen; 151010187SKrishna.Elango@Sun.COM 151110187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 151210187SKrishna.Elango@Sun.COM "reg", (int **)®spec, (uint_t *)®len) != DDI_SUCCESS) 151310187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 151410187SKrishna.Elango@Sun.COM 151510187SKrishna.Elango@Sun.COM if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) { 151610187SKrishna.Elango@Sun.COM ddi_prop_free(regspec); 151710187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 151810187SKrishna.Elango@Sun.COM } 151910187SKrishna.Elango@Sun.COM 152010187SKrishna.Elango@Sun.COM /* Get phys_hi from first element. All have same bdf. */ 152110187SKrishna.Elango@Sun.COM *bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8; 152210187SKrishna.Elango@Sun.COM 152310187SKrishna.Elango@Sun.COM ddi_prop_free(regspec); 152410187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 152510187SKrishna.Elango@Sun.COM } 152610187SKrishna.Elango@Sun.COM 152710187SKrishna.Elango@Sun.COM dev_info_t * 152810187SKrishna.Elango@Sun.COM pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 152910187SKrishna.Elango@Sun.COM { 153010187SKrishna.Elango@Sun.COM dev_info_t *cdip = rdip; 153110187SKrishna.Elango@Sun.COM 153210187SKrishna.Elango@Sun.COM for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 153310187SKrishna.Elango@Sun.COM ; 153410187SKrishna.Elango@Sun.COM 153510187SKrishna.Elango@Sun.COM return (cdip); 153610187SKrishna.Elango@Sun.COM } 153710187SKrishna.Elango@Sun.COM 153810187SKrishna.Elango@Sun.COM uint32_t 153910187SKrishna.Elango@Sun.COM pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip) 154010187SKrishna.Elango@Sun.COM { 154110187SKrishna.Elango@Sun.COM dev_info_t *cdip; 154210187SKrishna.Elango@Sun.COM 154310187SKrishna.Elango@Sun.COM /* 154410187SKrishna.Elango@Sun.COM * As part of the probing, the PCI fcode interpreter may setup a DMA 154510187SKrishna.Elango@Sun.COM * request if a given card has a fcode on it using dip and rdip of the 154610923SEvan.Yan@Sun.COM * hotplug connector i.e, dip and rdip of px/pcieb driver. In this 154710187SKrishna.Elango@Sun.COM * case, return a invalid value for the bdf since we cannot get to the 154810187SKrishna.Elango@Sun.COM * bdf value of the actual device which will be initiating this DMA. 154910187SKrishna.Elango@Sun.COM */ 155010187SKrishna.Elango@Sun.COM if (rdip == dip) 155110187SKrishna.Elango@Sun.COM return (PCIE_INVALID_BDF); 155210187SKrishna.Elango@Sun.COM 155310187SKrishna.Elango@Sun.COM cdip = pcie_get_my_childs_dip(dip, rdip); 155410187SKrishna.Elango@Sun.COM 155510187SKrishna.Elango@Sun.COM /* 155610187SKrishna.Elango@Sun.COM * For a given rdip, return the bdf value of dip's (px or pcieb) 155710187SKrishna.Elango@Sun.COM * immediate child or secondary bus-id if dip is a PCIe2PCI bridge. 155810187SKrishna.Elango@Sun.COM * 155910187SKrishna.Elango@Sun.COM * XXX - For now, return a invalid bdf value for all PCI and PCI-X 156010187SKrishna.Elango@Sun.COM * devices since this needs more work. 156110187SKrishna.Elango@Sun.COM */ 156210187SKrishna.Elango@Sun.COM return (PCI_GET_PCIE2PCI_SECBUS(cdip) ? 156310187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF : PCI_GET_BDF(cdip)); 156410187SKrishna.Elango@Sun.COM } 156510187SKrishna.Elango@Sun.COM 156610187SKrishna.Elango@Sun.COM uint32_t 156710187SKrishna.Elango@Sun.COM pcie_get_aer_uce_mask() { 156810187SKrishna.Elango@Sun.COM return (pcie_aer_uce_mask); 156910187SKrishna.Elango@Sun.COM } 157010187SKrishna.Elango@Sun.COM uint32_t 157110187SKrishna.Elango@Sun.COM pcie_get_aer_ce_mask() { 157210187SKrishna.Elango@Sun.COM return (pcie_aer_ce_mask); 157310187SKrishna.Elango@Sun.COM } 157410187SKrishna.Elango@Sun.COM uint32_t 157510187SKrishna.Elango@Sun.COM pcie_get_aer_suce_mask() { 157610187SKrishna.Elango@Sun.COM return (pcie_aer_suce_mask); 157710187SKrishna.Elango@Sun.COM } 157810187SKrishna.Elango@Sun.COM uint32_t 157910187SKrishna.Elango@Sun.COM pcie_get_serr_mask() { 158010187SKrishna.Elango@Sun.COM return (pcie_serr_disable_flag); 158110187SKrishna.Elango@Sun.COM } 158210187SKrishna.Elango@Sun.COM 158310187SKrishna.Elango@Sun.COM void 158410187SKrishna.Elango@Sun.COM pcie_set_aer_uce_mask(uint32_t mask) { 158510187SKrishna.Elango@Sun.COM pcie_aer_uce_mask = mask; 158610187SKrishna.Elango@Sun.COM if (mask & PCIE_AER_UCE_UR) 158710187SKrishna.Elango@Sun.COM pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN; 158810187SKrishna.Elango@Sun.COM else 158910187SKrishna.Elango@Sun.COM pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN; 159010187SKrishna.Elango@Sun.COM 159110187SKrishna.Elango@Sun.COM if (mask & PCIE_AER_UCE_ECRC) 159210187SKrishna.Elango@Sun.COM pcie_ecrc_value = 0; 159310187SKrishna.Elango@Sun.COM } 159410187SKrishna.Elango@Sun.COM 159510187SKrishna.Elango@Sun.COM void 159610187SKrishna.Elango@Sun.COM pcie_set_aer_ce_mask(uint32_t mask) { 159710187SKrishna.Elango@Sun.COM pcie_aer_ce_mask = mask; 159810187SKrishna.Elango@Sun.COM } 159910187SKrishna.Elango@Sun.COM void 160010187SKrishna.Elango@Sun.COM pcie_set_aer_suce_mask(uint32_t mask) { 160110187SKrishna.Elango@Sun.COM pcie_aer_suce_mask = mask; 160210187SKrishna.Elango@Sun.COM } 160310187SKrishna.Elango@Sun.COM void 160410187SKrishna.Elango@Sun.COM pcie_set_serr_mask(uint32_t mask) { 160510187SKrishna.Elango@Sun.COM pcie_serr_disable_flag = mask; 160610187SKrishna.Elango@Sun.COM } 160710187SKrishna.Elango@Sun.COM 160810187SKrishna.Elango@Sun.COM /* 160910187SKrishna.Elango@Sun.COM * Is the rdip a child of dip. Used for checking certain CTLOPS from bubbling 161010187SKrishna.Elango@Sun.COM * up erronously. Ex. ISA ctlops to a PCI-PCI Bridge. 161110187SKrishna.Elango@Sun.COM */ 161210187SKrishna.Elango@Sun.COM boolean_t 161310187SKrishna.Elango@Sun.COM pcie_is_child(dev_info_t *dip, dev_info_t *rdip) 161410187SKrishna.Elango@Sun.COM { 161510187SKrishna.Elango@Sun.COM dev_info_t *cdip = ddi_get_child(dip); 161610187SKrishna.Elango@Sun.COM for (; cdip; cdip = ddi_get_next_sibling(cdip)) 161710187SKrishna.Elango@Sun.COM if (cdip == rdip) 161810187SKrishna.Elango@Sun.COM break; 161910187SKrishna.Elango@Sun.COM return (cdip != NULL); 162010187SKrishna.Elango@Sun.COM } 162110187SKrishna.Elango@Sun.COM 162210187SKrishna.Elango@Sun.COM boolean_t 162310187SKrishna.Elango@Sun.COM pcie_is_link_disabled(dev_info_t *dip) 162410187SKrishna.Elango@Sun.COM { 162510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 162610187SKrishna.Elango@Sun.COM 162710187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 162810187SKrishna.Elango@Sun.COM if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) & 162910187SKrishna.Elango@Sun.COM PCIE_LINKCTL_LINK_DISABLE) 163010187SKrishna.Elango@Sun.COM return (B_TRUE); 163110187SKrishna.Elango@Sun.COM } 163210187SKrishna.Elango@Sun.COM return (B_FALSE); 163310187SKrishna.Elango@Sun.COM } 163410187SKrishna.Elango@Sun.COM 163510187SKrishna.Elango@Sun.COM /* 163610187SKrishna.Elango@Sun.COM * Initialize the MPS for a root port. 163710187SKrishna.Elango@Sun.COM * 163810187SKrishna.Elango@Sun.COM * dip - dip of root port device. 163910187SKrishna.Elango@Sun.COM */ 164010187SKrishna.Elango@Sun.COM void 164110187SKrishna.Elango@Sun.COM pcie_init_root_port_mps(dev_info_t *dip) 164210187SKrishna.Elango@Sun.COM { 164310187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 164410187SKrishna.Elango@Sun.COM int rp_cap, max_supported = pcie_max_mps; 164510187SKrishna.Elango@Sun.COM 164610187SKrishna.Elango@Sun.COM (void) pcie_get_fabric_mps(ddi_get_parent(dip), 164710187SKrishna.Elango@Sun.COM ddi_get_child(dip), &max_supported); 164810187SKrishna.Elango@Sun.COM 164910187SKrishna.Elango@Sun.COM rp_cap = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL, 165010187SKrishna.Elango@Sun.COM bus_p->bus_pcie_off, PCIE_DEVCAP) & 165110187SKrishna.Elango@Sun.COM PCIE_DEVCAP_MAX_PAYLOAD_MASK; 165210187SKrishna.Elango@Sun.COM 165310187SKrishna.Elango@Sun.COM if (rp_cap < max_supported) 165410187SKrishna.Elango@Sun.COM max_supported = rp_cap; 165510187SKrishna.Elango@Sun.COM 165610187SKrishna.Elango@Sun.COM bus_p->bus_mps = max_supported; 165710187SKrishna.Elango@Sun.COM (void) pcie_initchild_mps(dip); 165810187SKrishna.Elango@Sun.COM } 165910187SKrishna.Elango@Sun.COM 166010187SKrishna.Elango@Sun.COM /* 166110187SKrishna.Elango@Sun.COM * Initialize the Maximum Payload Size of a device. 166210187SKrishna.Elango@Sun.COM * 166310187SKrishna.Elango@Sun.COM * cdip - dip of device. 166410187SKrishna.Elango@Sun.COM * 166510187SKrishna.Elango@Sun.COM * returns - DDI_SUCCESS or DDI_FAILURE 166610187SKrishna.Elango@Sun.COM */ 166710187SKrishna.Elango@Sun.COM int 166810187SKrishna.Elango@Sun.COM pcie_initchild_mps(dev_info_t *cdip) 166910187SKrishna.Elango@Sun.COM { 167010187SKrishna.Elango@Sun.COM int max_payload_size; 167110187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 167210187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(cdip); 167310923SEvan.Yan@Sun.COM uint8_t dev_type; 167410187SKrishna.Elango@Sun.COM 167510187SKrishna.Elango@Sun.COM bus_p = PCIE_DIP2BUS(cdip); 167610187SKrishna.Elango@Sun.COM if (bus_p == NULL) { 167710187SKrishna.Elango@Sun.COM PCIE_DBG("%s: BUS not found.\n", 167810187SKrishna.Elango@Sun.COM ddi_driver_name(cdip)); 167910187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 168010187SKrishna.Elango@Sun.COM } 168110187SKrishna.Elango@Sun.COM 168210923SEvan.Yan@Sun.COM dev_type = bus_p->bus_dev_type; 168310923SEvan.Yan@Sun.COM 168410923SEvan.Yan@Sun.COM /* 168510923SEvan.Yan@Sun.COM * For ARI Devices, only function zero's MPS needs to be set. 168610923SEvan.Yan@Sun.COM */ 168710923SEvan.Yan@Sun.COM if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) && 168810923SEvan.Yan@Sun.COM (pcie_ari_is_enabled(pdip) == PCIE_ARI_FORW_ENABLED)) { 168910923SEvan.Yan@Sun.COM pcie_req_id_t child_bdf; 169010923SEvan.Yan@Sun.COM 169110923SEvan.Yan@Sun.COM if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE) 169210923SEvan.Yan@Sun.COM return (DDI_FAILURE); 169310923SEvan.Yan@Sun.COM if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) != 0) 169410923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 169510923SEvan.Yan@Sun.COM } 169610923SEvan.Yan@Sun.COM 169710187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) { 169810187SKrishna.Elango@Sun.COM /* 169910187SKrishna.Elango@Sun.COM * If this device is a root port, then the mps scan 170010187SKrishna.Elango@Sun.COM * saved the mps in the root ports bus_p. 170110187SKrishna.Elango@Sun.COM */ 170210187SKrishna.Elango@Sun.COM max_payload_size = bus_p->bus_mps; 170310187SKrishna.Elango@Sun.COM } else { 170410187SKrishna.Elango@Sun.COM /* 170510187SKrishna.Elango@Sun.COM * If the device is not a root port, then the mps of 170610187SKrishna.Elango@Sun.COM * its parent should be used. 170710187SKrishna.Elango@Sun.COM */ 170810187SKrishna.Elango@Sun.COM pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip); 170910187SKrishna.Elango@Sun.COM max_payload_size = parent_bus_p->bus_mps; 171010187SKrishna.Elango@Sun.COM } 171110187SKrishna.Elango@Sun.COM 171210187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p) && (max_payload_size >= 0)) { 171310187SKrishna.Elango@Sun.COM pcie_bus_t *rootp_bus_p = PCIE_DIP2BUS(bus_p->bus_rp_dip); 171410187SKrishna.Elango@Sun.COM uint16_t mask, dev_ctrl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL), 171510187SKrishna.Elango@Sun.COM mps = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) & 171610187SKrishna.Elango@Sun.COM PCIE_DEVCAP_MAX_PAYLOAD_MASK; 171710187SKrishna.Elango@Sun.COM 171810187SKrishna.Elango@Sun.COM mps = MIN(mps, (uint16_t)max_payload_size); 171910187SKrishna.Elango@Sun.COM 172010187SKrishna.Elango@Sun.COM /* 172110187SKrishna.Elango@Sun.COM * If the MPS to be set is less than the root ports 172210187SKrishna.Elango@Sun.COM * MPS, then MRRS will have to be set the same as MPS. 172310187SKrishna.Elango@Sun.COM */ 172410187SKrishna.Elango@Sun.COM mask = ((mps < rootp_bus_p->bus_mps) ? 172510187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_READ_REQ_MASK : 0) | 172610187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK; 172710187SKrishna.Elango@Sun.COM 172810187SKrishna.Elango@Sun.COM dev_ctrl &= ~mask; 172910187SKrishna.Elango@Sun.COM mask = ((mps < rootp_bus_p->bus_mps) 173010187SKrishna.Elango@Sun.COM ? mps << PCIE_DEVCTL_MAX_READ_REQ_SHIFT : 0) 173110187SKrishna.Elango@Sun.COM | (mps << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT); 173210187SKrishna.Elango@Sun.COM 173310187SKrishna.Elango@Sun.COM dev_ctrl |= mask; 173410187SKrishna.Elango@Sun.COM 173510187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl); 173610187SKrishna.Elango@Sun.COM 173710187SKrishna.Elango@Sun.COM bus_p->bus_mps = mps; 173810187SKrishna.Elango@Sun.COM } 173910923SEvan.Yan@Sun.COM 174010187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 174110187SKrishna.Elango@Sun.COM } 174210187SKrishna.Elango@Sun.COM 174310187SKrishna.Elango@Sun.COM /* 174410187SKrishna.Elango@Sun.COM * Scans a device tree/branch for a maximum payload size capabilities. 174510187SKrishna.Elango@Sun.COM * 174610187SKrishna.Elango@Sun.COM * rc_dip - dip of Root Complex. 174710187SKrishna.Elango@Sun.COM * dip - dip of device where scan will begin. 174810187SKrishna.Elango@Sun.COM * max_supported (IN) - maximum allowable MPS. 174910187SKrishna.Elango@Sun.COM * max_supported (OUT) - maximum payload size capability of fabric. 175010187SKrishna.Elango@Sun.COM */ 175110187SKrishna.Elango@Sun.COM void 175210187SKrishna.Elango@Sun.COM pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported) 175310187SKrishna.Elango@Sun.COM { 175410187SKrishna.Elango@Sun.COM if (dip == NULL) 175510187SKrishna.Elango@Sun.COM return; 175610187SKrishna.Elango@Sun.COM 175710187SKrishna.Elango@Sun.COM /* 175810187SKrishna.Elango@Sun.COM * Perform a fabric scan to obtain Maximum Payload Capabilities 175910187SKrishna.Elango@Sun.COM */ 176010187SKrishna.Elango@Sun.COM (void) pcie_scan_mps(rc_dip, dip, max_supported); 176110187SKrishna.Elango@Sun.COM 176210187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: Highest Common MPS= %x\n", max_supported); 176310187SKrishna.Elango@Sun.COM } 176410187SKrishna.Elango@Sun.COM 176510187SKrishna.Elango@Sun.COM /* 176610187SKrishna.Elango@Sun.COM * Scans fabric and determines Maximum Payload Size based on 176710187SKrishna.Elango@Sun.COM * highest common denominator alogorithm 176810187SKrishna.Elango@Sun.COM */ 176910187SKrishna.Elango@Sun.COM static void 177010187SKrishna.Elango@Sun.COM pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported) 177110187SKrishna.Elango@Sun.COM { 177210187SKrishna.Elango@Sun.COM int circular_count; 177310187SKrishna.Elango@Sun.COM pcie_max_supported_t max_pay_load_supported; 177410187SKrishna.Elango@Sun.COM 177510187SKrishna.Elango@Sun.COM max_pay_load_supported.dip = rc_dip; 177610187SKrishna.Elango@Sun.COM max_pay_load_supported.highest_common_mps = *max_supported; 177710187SKrishna.Elango@Sun.COM 177810187SKrishna.Elango@Sun.COM ndi_devi_enter(ddi_get_parent(dip), &circular_count); 177910187SKrishna.Elango@Sun.COM ddi_walk_devs(dip, pcie_get_max_supported, 178010187SKrishna.Elango@Sun.COM (void *)&max_pay_load_supported); 178110187SKrishna.Elango@Sun.COM ndi_devi_exit(ddi_get_parent(dip), circular_count); 178210923SEvan.Yan@Sun.COM 178310187SKrishna.Elango@Sun.COM *max_supported = max_pay_load_supported.highest_common_mps; 178410187SKrishna.Elango@Sun.COM } 178510187SKrishna.Elango@Sun.COM 178610187SKrishna.Elango@Sun.COM /* 178710187SKrishna.Elango@Sun.COM * Called as part of the Maximum Payload Size scan. 178810187SKrishna.Elango@Sun.COM */ 178910187SKrishna.Elango@Sun.COM static int 179010187SKrishna.Elango@Sun.COM pcie_get_max_supported(dev_info_t *dip, void *arg) 179110187SKrishna.Elango@Sun.COM { 179210187SKrishna.Elango@Sun.COM uint32_t max_supported; 179310187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 179410187SKrishna.Elango@Sun.COM pcie_max_supported_t *current = (pcie_max_supported_t *)arg; 179510187SKrishna.Elango@Sun.COM pci_regspec_t *reg; 179610187SKrishna.Elango@Sun.COM int rlen; 179710187SKrishna.Elango@Sun.COM caddr_t virt; 179810187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle; 179910187SKrishna.Elango@Sun.COM 180010187SKrishna.Elango@Sun.COM if (ddi_get_child(current->dip) == NULL) { 180110187SKrishna.Elango@Sun.COM goto fail1; 180210187SKrishna.Elango@Sun.COM } 180310187SKrishna.Elango@Sun.COM 180410187SKrishna.Elango@Sun.COM if (pcie_dev(dip) == DDI_FAILURE) { 180510187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: " 180610187SKrishna.Elango@Sun.COM "Not a PCIe dev\n", ddi_driver_name(dip)); 180710187SKrishna.Elango@Sun.COM goto fail1; 180810187SKrishna.Elango@Sun.COM } 180910187SKrishna.Elango@Sun.COM 181010187SKrishna.Elango@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 181110187SKrishna.Elango@Sun.COM (caddr_t)®, &rlen) != DDI_PROP_SUCCESS) { 181210187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: " 181310187SKrishna.Elango@Sun.COM "Can not read reg\n", ddi_driver_name(dip)); 181410187SKrishna.Elango@Sun.COM goto fail1; 181510187SKrishna.Elango@Sun.COM } 181610187SKrishna.Elango@Sun.COM 181710187SKrishna.Elango@Sun.COM if (pcie_map_phys(ddi_get_child(current->dip), reg, &virt, 181810187SKrishna.Elango@Sun.COM &config_handle) != DDI_SUCCESS) { 181910187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: pcie_map_phys " 182010187SKrishna.Elango@Sun.COM "failed\n", ddi_driver_name(dip)); 182110187SKrishna.Elango@Sun.COM goto fail2; 182210187SKrishna.Elango@Sun.COM } 182310187SKrishna.Elango@Sun.COM 182410187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) == 182510187SKrishna.Elango@Sun.COM DDI_FAILURE) { 182610187SKrishna.Elango@Sun.COM goto fail3; 182710187SKrishna.Elango@Sun.COM } 182810187SKrishna.Elango@Sun.COM 182910187SKrishna.Elango@Sun.COM max_supported = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 183010187SKrishna.Elango@Sun.COM PCIE_DEVCAP) & PCIE_DEVCAP_MAX_PAYLOAD_MASK; 183110187SKrishna.Elango@Sun.COM 183210187SKrishna.Elango@Sun.COM PCIE_DBG("PCIE MPS: %s: MPS Capabilities %x\n", ddi_driver_name(dip), 183310187SKrishna.Elango@Sun.COM max_supported); 183410187SKrishna.Elango@Sun.COM 183510187SKrishna.Elango@Sun.COM if (max_supported < current->highest_common_mps) 183610187SKrishna.Elango@Sun.COM current->highest_common_mps = max_supported; 183710187SKrishna.Elango@Sun.COM 183810187SKrishna.Elango@Sun.COM fail3: 183910187SKrishna.Elango@Sun.COM pcie_unmap_phys(&config_handle, reg); 184010187SKrishna.Elango@Sun.COM fail2: 184110187SKrishna.Elango@Sun.COM kmem_free(reg, rlen); 184210187SKrishna.Elango@Sun.COM fail1: 184310187SKrishna.Elango@Sun.COM return (DDI_WALK_CONTINUE); 184410187SKrishna.Elango@Sun.COM } 184510187SKrishna.Elango@Sun.COM 184610187SKrishna.Elango@Sun.COM /* 184710187SKrishna.Elango@Sun.COM * Determines if there are any root ports attached to a root complex. 184810187SKrishna.Elango@Sun.COM * 184910187SKrishna.Elango@Sun.COM * dip - dip of root complex 185010187SKrishna.Elango@Sun.COM * 185110187SKrishna.Elango@Sun.COM * Returns - DDI_SUCCESS if there is at least one root port otherwise 185210923SEvan.Yan@Sun.COM * DDI_FAILURE. 185310187SKrishna.Elango@Sun.COM */ 185410187SKrishna.Elango@Sun.COM int 185510187SKrishna.Elango@Sun.COM pcie_root_port(dev_info_t *dip) 185610187SKrishna.Elango@Sun.COM { 185710187SKrishna.Elango@Sun.COM int port_type; 185810187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 185910187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle; 186010187SKrishna.Elango@Sun.COM dev_info_t *cdip = ddi_get_child(dip); 186110187SKrishna.Elango@Sun.COM 186210187SKrishna.Elango@Sun.COM /* 186310187SKrishna.Elango@Sun.COM * Determine if any of the children of the passed in dip 186410187SKrishna.Elango@Sun.COM * are root ports. 186510187SKrishna.Elango@Sun.COM */ 186610187SKrishna.Elango@Sun.COM for (; cdip; cdip = ddi_get_next_sibling(cdip)) { 186710187SKrishna.Elango@Sun.COM 186810187SKrishna.Elango@Sun.COM if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS) 186910187SKrishna.Elango@Sun.COM continue; 187010187SKrishna.Elango@Sun.COM 187110187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, 187210187SKrishna.Elango@Sun.COM &cap_ptr)) == DDI_FAILURE) { 187310187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle); 187410187SKrishna.Elango@Sun.COM continue; 187510187SKrishna.Elango@Sun.COM } 187610187SKrishna.Elango@Sun.COM 187710187SKrishna.Elango@Sun.COM port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 187810187SKrishna.Elango@Sun.COM PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 187910187SKrishna.Elango@Sun.COM 188010187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle); 188110187SKrishna.Elango@Sun.COM 188210187SKrishna.Elango@Sun.COM if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) 188310187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 188410187SKrishna.Elango@Sun.COM } 188510187SKrishna.Elango@Sun.COM 188610187SKrishna.Elango@Sun.COM /* No root ports were found */ 188710187SKrishna.Elango@Sun.COM 188810187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 188910187SKrishna.Elango@Sun.COM } 189010187SKrishna.Elango@Sun.COM 189110187SKrishna.Elango@Sun.COM /* 189210187SKrishna.Elango@Sun.COM * Function that determines if a device a PCIe device. 189310187SKrishna.Elango@Sun.COM * 189410187SKrishna.Elango@Sun.COM * dip - dip of device. 189510187SKrishna.Elango@Sun.COM * 189610187SKrishna.Elango@Sun.COM * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE. 189710187SKrishna.Elango@Sun.COM */ 189810187SKrishna.Elango@Sun.COM int 189910187SKrishna.Elango@Sun.COM pcie_dev(dev_info_t *dip) 190010187SKrishna.Elango@Sun.COM { 190110187SKrishna.Elango@Sun.COM /* get parent device's device_type property */ 190210187SKrishna.Elango@Sun.COM char *device_type; 190310187SKrishna.Elango@Sun.COM int rc = DDI_FAILURE; 190410187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(dip); 190510187SKrishna.Elango@Sun.COM 190610187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 190710187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "device_type", &device_type) 190810187SKrishna.Elango@Sun.COM != DDI_PROP_SUCCESS) { 190910187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 191010187SKrishna.Elango@Sun.COM } 191110187SKrishna.Elango@Sun.COM 191210187SKrishna.Elango@Sun.COM if (strcmp(device_type, "pciex") == 0) 191310187SKrishna.Elango@Sun.COM rc = DDI_SUCCESS; 191410187SKrishna.Elango@Sun.COM else 191510187SKrishna.Elango@Sun.COM rc = DDI_FAILURE; 191610187SKrishna.Elango@Sun.COM 191710187SKrishna.Elango@Sun.COM ddi_prop_free(device_type); 191810187SKrishna.Elango@Sun.COM return (rc); 191910187SKrishna.Elango@Sun.COM } 192010187SKrishna.Elango@Sun.COM 192110187SKrishna.Elango@Sun.COM /* 192210187SKrishna.Elango@Sun.COM * Function to map in a device's memory space. 192310187SKrishna.Elango@Sun.COM */ 192410187SKrishna.Elango@Sun.COM static int 192510187SKrishna.Elango@Sun.COM pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 192610187SKrishna.Elango@Sun.COM caddr_t *addrp, ddi_acc_handle_t *handlep) 192710187SKrishna.Elango@Sun.COM { 192810187SKrishna.Elango@Sun.COM ddi_map_req_t mr; 192910187SKrishna.Elango@Sun.COM ddi_acc_hdl_t *hp; 193010187SKrishna.Elango@Sun.COM int result; 193110187SKrishna.Elango@Sun.COM ddi_device_acc_attr_t attr; 193210187SKrishna.Elango@Sun.COM 193310187SKrishna.Elango@Sun.COM attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 193410187SKrishna.Elango@Sun.COM attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 193510187SKrishna.Elango@Sun.COM attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 193610187SKrishna.Elango@Sun.COM attr.devacc_attr_access = DDI_CAUTIOUS_ACC; 193710187SKrishna.Elango@Sun.COM 193810187SKrishna.Elango@Sun.COM *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 193910187SKrishna.Elango@Sun.COM hp = impl_acc_hdl_get(*handlep); 194010187SKrishna.Elango@Sun.COM hp->ah_vers = VERS_ACCHDL; 194110187SKrishna.Elango@Sun.COM hp->ah_dip = dip; 194210187SKrishna.Elango@Sun.COM hp->ah_rnumber = 0; 194310187SKrishna.Elango@Sun.COM hp->ah_offset = 0; 194410187SKrishna.Elango@Sun.COM hp->ah_len = 0; 194510187SKrishna.Elango@Sun.COM hp->ah_acc = attr; 194610187SKrishna.Elango@Sun.COM 194710187SKrishna.Elango@Sun.COM mr.map_op = DDI_MO_MAP_LOCKED; 194810187SKrishna.Elango@Sun.COM mr.map_type = DDI_MT_REGSPEC; 194910187SKrishna.Elango@Sun.COM mr.map_obj.rp = (struct regspec *)phys_spec; 195010187SKrishna.Elango@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE; 195110187SKrishna.Elango@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING; 195210187SKrishna.Elango@Sun.COM mr.map_handlep = hp; 195310187SKrishna.Elango@Sun.COM mr.map_vers = DDI_MAP_VERSION; 195410187SKrishna.Elango@Sun.COM 195510187SKrishna.Elango@Sun.COM result = ddi_map(dip, &mr, 0, 0, addrp); 195610187SKrishna.Elango@Sun.COM 195710187SKrishna.Elango@Sun.COM if (result != DDI_SUCCESS) { 195810187SKrishna.Elango@Sun.COM impl_acc_hdl_free(*handlep); 195910187SKrishna.Elango@Sun.COM *handlep = (ddi_acc_handle_t)NULL; 196010187SKrishna.Elango@Sun.COM } else { 196110187SKrishna.Elango@Sun.COM hp->ah_addr = *addrp; 196210187SKrishna.Elango@Sun.COM } 196310187SKrishna.Elango@Sun.COM 196410187SKrishna.Elango@Sun.COM return (result); 196510187SKrishna.Elango@Sun.COM } 196610187SKrishna.Elango@Sun.COM 196710187SKrishna.Elango@Sun.COM /* 196810187SKrishna.Elango@Sun.COM * Map out memory that was mapped in with pcie_map_phys(); 196910187SKrishna.Elango@Sun.COM */ 197010187SKrishna.Elango@Sun.COM static void 197110187SKrishna.Elango@Sun.COM pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph) 197210187SKrishna.Elango@Sun.COM { 197310187SKrishna.Elango@Sun.COM ddi_map_req_t mr; 197410187SKrishna.Elango@Sun.COM ddi_acc_hdl_t *hp; 197510187SKrishna.Elango@Sun.COM 197610187SKrishna.Elango@Sun.COM hp = impl_acc_hdl_get(*handlep); 197710187SKrishna.Elango@Sun.COM ASSERT(hp); 197810187SKrishna.Elango@Sun.COM 197910187SKrishna.Elango@Sun.COM mr.map_op = DDI_MO_UNMAP; 198010187SKrishna.Elango@Sun.COM mr.map_type = DDI_MT_REGSPEC; 198110187SKrishna.Elango@Sun.COM mr.map_obj.rp = (struct regspec *)ph; 198210187SKrishna.Elango@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE; 198310187SKrishna.Elango@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING; 198410187SKrishna.Elango@Sun.COM mr.map_handlep = hp; 198510187SKrishna.Elango@Sun.COM mr.map_vers = DDI_MAP_VERSION; 198610187SKrishna.Elango@Sun.COM 198710187SKrishna.Elango@Sun.COM (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 198810187SKrishna.Elango@Sun.COM hp->ah_len, &hp->ah_addr); 198910187SKrishna.Elango@Sun.COM 199010187SKrishna.Elango@Sun.COM impl_acc_hdl_free(*handlep); 199110187SKrishna.Elango@Sun.COM *handlep = (ddi_acc_handle_t)NULL; 199210187SKrishna.Elango@Sun.COM } 199310187SKrishna.Elango@Sun.COM 199410187SKrishna.Elango@Sun.COM void 199510187SKrishna.Elango@Sun.COM pcie_set_rber_fatal(dev_info_t *dip, boolean_t val) 199610187SKrishna.Elango@Sun.COM { 199710187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 199810187SKrishna.Elango@Sun.COM bus_p->bus_pfd->pe_rber_fatal = val; 199910187SKrishna.Elango@Sun.COM } 200010187SKrishna.Elango@Sun.COM 200110187SKrishna.Elango@Sun.COM /* 200210187SKrishna.Elango@Sun.COM * Return parent Root Port's pe_rber_fatal value. 200310187SKrishna.Elango@Sun.COM */ 200410187SKrishna.Elango@Sun.COM boolean_t 200510187SKrishna.Elango@Sun.COM pcie_get_rber_fatal(dev_info_t *dip) 200610187SKrishna.Elango@Sun.COM { 200710187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 200810187SKrishna.Elango@Sun.COM pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip); 200910187SKrishna.Elango@Sun.COM return (rp_bus_p->bus_pfd->pe_rber_fatal); 201010187SKrishna.Elango@Sun.COM } 201110187SKrishna.Elango@Sun.COM 201210923SEvan.Yan@Sun.COM int 201310923SEvan.Yan@Sun.COM pcie_ari_supported(dev_info_t *dip) 201410923SEvan.Yan@Sun.COM { 201510923SEvan.Yan@Sun.COM uint32_t devcap2; 201610923SEvan.Yan@Sun.COM uint16_t pciecap; 201710923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 201810923SEvan.Yan@Sun.COM uint8_t dev_type; 201910923SEvan.Yan@Sun.COM 202010923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p\n", dip); 202110923SEvan.Yan@Sun.COM 202210923SEvan.Yan@Sun.COM if (bus_p == NULL) 202310923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 202410923SEvan.Yan@Sun.COM 202510923SEvan.Yan@Sun.COM dev_type = bus_p->bus_dev_type; 202610923SEvan.Yan@Sun.COM 202710923SEvan.Yan@Sun.COM if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) && 202810923SEvan.Yan@Sun.COM (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT)) 202910923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 203010923SEvan.Yan@Sun.COM 203110923SEvan.Yan@Sun.COM if (pcie_disable_ari) { 203210923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip); 203310923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 203410923SEvan.Yan@Sun.COM } 203510923SEvan.Yan@Sun.COM 203610923SEvan.Yan@Sun.COM pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP); 203710923SEvan.Yan@Sun.COM 203810923SEvan.Yan@Sun.COM if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) { 203910923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip); 204010923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 204110923SEvan.Yan@Sun.COM } 204210923SEvan.Yan@Sun.COM 204310923SEvan.Yan@Sun.COM devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2); 204410923SEvan.Yan@Sun.COM 204510923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n", 204610923SEvan.Yan@Sun.COM dip, devcap2); 204710923SEvan.Yan@Sun.COM 204810923SEvan.Yan@Sun.COM if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) { 204910923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: " 205010923SEvan.Yan@Sun.COM "dip=%p: ARI Forwarding is supported\n", dip); 205110923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_SUPPORTED); 205210923SEvan.Yan@Sun.COM } 205310923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 205410923SEvan.Yan@Sun.COM } 205510923SEvan.Yan@Sun.COM 205610923SEvan.Yan@Sun.COM int 205710923SEvan.Yan@Sun.COM pcie_ari_enable(dev_info_t *dip) 205810923SEvan.Yan@Sun.COM { 205910923SEvan.Yan@Sun.COM uint16_t devctl2; 206010923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 206110923SEvan.Yan@Sun.COM 206210923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_enable: dip=%p\n", dip); 206310923SEvan.Yan@Sun.COM 206410923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 206510923SEvan.Yan@Sun.COM return (DDI_FAILURE); 206610923SEvan.Yan@Sun.COM 206710923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2); 206810923SEvan.Yan@Sun.COM devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN; 206910923SEvan.Yan@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2); 207010923SEvan.Yan@Sun.COM 207110923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n", 207210923SEvan.Yan@Sun.COM dip, devctl2); 207310923SEvan.Yan@Sun.COM 207410923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 207510923SEvan.Yan@Sun.COM } 207610923SEvan.Yan@Sun.COM 207710923SEvan.Yan@Sun.COM int 207810923SEvan.Yan@Sun.COM pcie_ari_disable(dev_info_t *dip) 207910923SEvan.Yan@Sun.COM { 208010923SEvan.Yan@Sun.COM uint16_t devctl2; 208110923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 208210923SEvan.Yan@Sun.COM 208310923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_disable: dip=%p\n", dip); 208410923SEvan.Yan@Sun.COM 208510923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 208610923SEvan.Yan@Sun.COM return (DDI_FAILURE); 208710923SEvan.Yan@Sun.COM 208810923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2); 208910923SEvan.Yan@Sun.COM devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN; 209010923SEvan.Yan@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2); 209110923SEvan.Yan@Sun.COM 209210923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n", 209310923SEvan.Yan@Sun.COM dip, devctl2); 209410923SEvan.Yan@Sun.COM 209510923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 209610923SEvan.Yan@Sun.COM } 209710923SEvan.Yan@Sun.COM 209810923SEvan.Yan@Sun.COM int 209910923SEvan.Yan@Sun.COM pcie_ari_is_enabled(dev_info_t *dip) 210010923SEvan.Yan@Sun.COM { 210110923SEvan.Yan@Sun.COM uint16_t devctl2; 210210923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 210310923SEvan.Yan@Sun.COM 210410923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip); 210510923SEvan.Yan@Sun.COM 210610923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 210710923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_DISABLED); 210810923SEvan.Yan@Sun.COM 210910923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2); 211010923SEvan.Yan@Sun.COM 211110923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n", 211210923SEvan.Yan@Sun.COM dip, devctl2); 211310923SEvan.Yan@Sun.COM 211410923SEvan.Yan@Sun.COM if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) { 211510923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: " 211610923SEvan.Yan@Sun.COM "dip=%p: ARI Forwarding is enabled\n", dip); 211710923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_ENABLED); 211810923SEvan.Yan@Sun.COM } 211910923SEvan.Yan@Sun.COM 212010923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_DISABLED); 212110923SEvan.Yan@Sun.COM } 212210923SEvan.Yan@Sun.COM 212310923SEvan.Yan@Sun.COM int 212410923SEvan.Yan@Sun.COM pcie_ari_device(dev_info_t *dip) 212510923SEvan.Yan@Sun.COM { 212610923SEvan.Yan@Sun.COM ddi_acc_handle_t handle; 212710923SEvan.Yan@Sun.COM uint16_t cap_ptr; 212810923SEvan.Yan@Sun.COM 212910923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_device: dip=%p\n", dip); 213010923SEvan.Yan@Sun.COM 213110923SEvan.Yan@Sun.COM /* 213210923SEvan.Yan@Sun.COM * XXX - This function may be called before the bus_p structure 213310923SEvan.Yan@Sun.COM * has been populated. This code can be changed to remove 213410923SEvan.Yan@Sun.COM * pci_config_setup()/pci_config_teardown() when the RFE 213510923SEvan.Yan@Sun.COM * to populate the bus_p structures early in boot is putback. 213610923SEvan.Yan@Sun.COM */ 213710923SEvan.Yan@Sun.COM 213810923SEvan.Yan@Sun.COM /* First make sure it is a PCIe device */ 213910923SEvan.Yan@Sun.COM 214010923SEvan.Yan@Sun.COM if (pci_config_setup(dip, &handle) != DDI_SUCCESS) 214110923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE); 214210923SEvan.Yan@Sun.COM 214310923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) 214410923SEvan.Yan@Sun.COM != DDI_SUCCESS) { 214510923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 214610923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE); 214710923SEvan.Yan@Sun.COM } 214810923SEvan.Yan@Sun.COM 214910923SEvan.Yan@Sun.COM /* Locate the ARI Capability */ 215010923SEvan.Yan@Sun.COM 215110923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), 215210923SEvan.Yan@Sun.COM &cap_ptr)) == DDI_FAILURE) { 215310923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 215410923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE); 215510923SEvan.Yan@Sun.COM } 215610923SEvan.Yan@Sun.COM 215710923SEvan.Yan@Sun.COM /* ARI Capability was found so it must be a ARI device */ 215810923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip); 215910923SEvan.Yan@Sun.COM 216010923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 216110923SEvan.Yan@Sun.COM return (PCIE_ARI_DEVICE); 216210923SEvan.Yan@Sun.COM } 216310923SEvan.Yan@Sun.COM 216410923SEvan.Yan@Sun.COM int 216510923SEvan.Yan@Sun.COM pcie_ari_get_next_function(dev_info_t *dip, int *func) 216610923SEvan.Yan@Sun.COM { 216710923SEvan.Yan@Sun.COM uint32_t val; 216810923SEvan.Yan@Sun.COM uint16_t cap_ptr, next_function; 216910923SEvan.Yan@Sun.COM ddi_acc_handle_t handle; 217010923SEvan.Yan@Sun.COM 217110923SEvan.Yan@Sun.COM /* 217210923SEvan.Yan@Sun.COM * XXX - This function may be called before the bus_p structure 217310923SEvan.Yan@Sun.COM * has been populated. This code can be changed to remove 217410923SEvan.Yan@Sun.COM * pci_config_setup()/pci_config_teardown() when the RFE 217510923SEvan.Yan@Sun.COM * to populate the bus_p structures early in boot is putback. 217610923SEvan.Yan@Sun.COM */ 217710923SEvan.Yan@Sun.COM 217810923SEvan.Yan@Sun.COM if (pci_config_setup(dip, &handle) != DDI_SUCCESS) 217910923SEvan.Yan@Sun.COM return (DDI_FAILURE); 218010923SEvan.Yan@Sun.COM 218110923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, 218210923SEvan.Yan@Sun.COM PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) { 218310923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 218410923SEvan.Yan@Sun.COM return (DDI_FAILURE); 218510923SEvan.Yan@Sun.COM } 218610923SEvan.Yan@Sun.COM 218710923SEvan.Yan@Sun.COM val = PCI_CAP_GET32(handle, NULL, cap_ptr, PCIE_ARI_CAP); 218810923SEvan.Yan@Sun.COM 218910923SEvan.Yan@Sun.COM next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) & 219010923SEvan.Yan@Sun.COM PCIE_ARI_CAP_NEXT_FUNC_MASK; 219110923SEvan.Yan@Sun.COM 219210923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 219310923SEvan.Yan@Sun.COM 219410923SEvan.Yan@Sun.COM *func = next_function; 219510923SEvan.Yan@Sun.COM 219610923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 219710923SEvan.Yan@Sun.COM } 219810923SEvan.Yan@Sun.COM 219910923SEvan.Yan@Sun.COM dev_info_t * 220010923SEvan.Yan@Sun.COM pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function) 220110923SEvan.Yan@Sun.COM { 220210923SEvan.Yan@Sun.COM pcie_req_id_t child_bdf; 220310923SEvan.Yan@Sun.COM dev_info_t *cdip; 220410923SEvan.Yan@Sun.COM 220510923SEvan.Yan@Sun.COM for (cdip = ddi_get_child(dip); cdip; 220610923SEvan.Yan@Sun.COM cdip = ddi_get_next_sibling(cdip)) { 220710923SEvan.Yan@Sun.COM 220810923SEvan.Yan@Sun.COM if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE) 220910923SEvan.Yan@Sun.COM return (NULL); 221010923SEvan.Yan@Sun.COM 221110923SEvan.Yan@Sun.COM if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function) 221210923SEvan.Yan@Sun.COM return (cdip); 221310923SEvan.Yan@Sun.COM } 221410923SEvan.Yan@Sun.COM return (NULL); 221510923SEvan.Yan@Sun.COM } 221610923SEvan.Yan@Sun.COM 221710187SKrishna.Elango@Sun.COM #ifdef DEBUG 221810187SKrishna.Elango@Sun.COM 221910187SKrishna.Elango@Sun.COM static void 222010187SKrishna.Elango@Sun.COM pcie_print_bus(pcie_bus_t *bus_p) 222110187SKrishna.Elango@Sun.COM { 222210187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip); 222310187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags); 222410187SKrishna.Elango@Sun.COM 222510187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf); 222610187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id); 222710187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id); 222810187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type); 222910187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type); 223010187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus); 223110187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off); 223210187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off); 223310187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off); 223410187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver); 223510187SKrishna.Elango@Sun.COM } 223610187SKrishna.Elango@Sun.COM 223710187SKrishna.Elango@Sun.COM /* 223810187SKrishna.Elango@Sun.COM * For debugging purposes set pcie_dbg_print != 0 to see printf messages 223910187SKrishna.Elango@Sun.COM * during interrupt. 224010187SKrishna.Elango@Sun.COM * 224110187SKrishna.Elango@Sun.COM * When a proper solution is in place this code will disappear. 224210187SKrishna.Elango@Sun.COM * Potential solutions are: 224310187SKrishna.Elango@Sun.COM * o circular buffers 224410187SKrishna.Elango@Sun.COM * o taskq to print at lower pil 224510187SKrishna.Elango@Sun.COM */ 224610187SKrishna.Elango@Sun.COM int pcie_dbg_print = 0; 224710187SKrishna.Elango@Sun.COM void 224810187SKrishna.Elango@Sun.COM pcie_dbg(char *fmt, ...) 224910187SKrishna.Elango@Sun.COM { 225010187SKrishna.Elango@Sun.COM va_list ap; 225110187SKrishna.Elango@Sun.COM 225210187SKrishna.Elango@Sun.COM if (!pcie_debug_flags) { 225310187SKrishna.Elango@Sun.COM return; 225410187SKrishna.Elango@Sun.COM } 225510187SKrishna.Elango@Sun.COM va_start(ap, fmt); 225610187SKrishna.Elango@Sun.COM if (servicing_interrupt()) { 225710187SKrishna.Elango@Sun.COM if (pcie_dbg_print) { 225810187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap); 225910187SKrishna.Elango@Sun.COM } 226010187SKrishna.Elango@Sun.COM } else { 226110187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap); 226210187SKrishna.Elango@Sun.COM } 226310187SKrishna.Elango@Sun.COM va_end(ap); 226410187SKrishna.Elango@Sun.COM } 226510187SKrishna.Elango@Sun.COM #endif /* DEBUG */ 226610187SKrishna.Elango@Sun.COM 226710187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64) 226810187SKrishna.Elango@Sun.COM static void 226910187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl, boolean_t *empty_io_range, 227010187SKrishna.Elango@Sun.COM boolean_t *empty_mem_range) 227110187SKrishna.Elango@Sun.COM { 227210187SKrishna.Elango@Sun.COM uint8_t class, subclass; 227310187SKrishna.Elango@Sun.COM uint_t val; 227410187SKrishna.Elango@Sun.COM 227510187SKrishna.Elango@Sun.COM class = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS); 227610187SKrishna.Elango@Sun.COM subclass = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS); 227710187SKrishna.Elango@Sun.COM 227810187SKrishna.Elango@Sun.COM if ((class == PCI_CLASS_BRIDGE) && (subclass == PCI_BRIDGE_PCI)) { 227910187SKrishna.Elango@Sun.COM val = (((uint_t)pci_config_get8(cfg_hdl, PCI_BCNF_IO_BASE_LOW) & 228010187SKrishna.Elango@Sun.COM PCI_BCNF_IO_MASK) << 8); 228110187SKrishna.Elango@Sun.COM /* 228210187SKrishna.Elango@Sun.COM * Assuming that a zero based io_range[0] implies an 228310187SKrishna.Elango@Sun.COM * invalid I/O range. Likewise for mem_range[0]. 228410187SKrishna.Elango@Sun.COM */ 228510187SKrishna.Elango@Sun.COM if (val == 0) 228610187SKrishna.Elango@Sun.COM *empty_io_range = B_TRUE; 228710187SKrishna.Elango@Sun.COM val = (((uint_t)pci_config_get16(cfg_hdl, PCI_BCNF_MEM_BASE) & 228810187SKrishna.Elango@Sun.COM PCI_BCNF_MEM_MASK) << 16); 228910187SKrishna.Elango@Sun.COM if (val == 0) 229010187SKrishna.Elango@Sun.COM *empty_mem_range = B_TRUE; 229110187SKrishna.Elango@Sun.COM } 229210187SKrishna.Elango@Sun.COM } 229311245SZhijun.Fu@Sun.COM 229410187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */ 2295