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> 37*10923SEvan.Yan@Sun.COM #include <sys/stat.h> 38*10923SEvan.Yan@Sun.COM #include <sys/file.h> 3910187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h> 40*10923SEvan.Yan@Sun.COM #include <sys/pci_impl.h> 4110187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h> 42*10923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcie_hp.h> 43*10923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcicfg.h> 4410187SKrishna.Elango@Sun.COM 45*10923SEvan.Yan@Sun.COM /* Local functions prototypes */ 4610187SKrishna.Elango@Sun.COM static void pcie_init_pfd(dev_info_t *); 4710187SKrishna.Elango@Sun.COM static void pcie_fini_pfd(dev_info_t *); 4810187SKrishna.Elango@Sun.COM 4910187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64) 5010187SKrishna.Elango@Sun.COM static void pcie_check_io_mem_range(ddi_acc_handle_t, boolean_t *, boolean_t *); 5110187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */ 5210187SKrishna.Elango@Sun.COM 5310187SKrishna.Elango@Sun.COM #ifdef DEBUG 5410187SKrishna.Elango@Sun.COM uint_t pcie_debug_flags = 0; 5510187SKrishna.Elango@Sun.COM static void pcie_print_bus(pcie_bus_t *bus_p); 56*10923SEvan.Yan@Sun.COM void pcie_dbg(char *fmt, ...); 5710187SKrishna.Elango@Sun.COM #endif /* DEBUG */ 5810187SKrishna.Elango@Sun.COM 5910187SKrishna.Elango@Sun.COM /* Variable to control default PCI-Express config settings */ 6010187SKrishna.Elango@Sun.COM ushort_t pcie_command_default = 6110187SKrishna.Elango@Sun.COM PCI_COMM_SERR_ENABLE | 6210187SKrishna.Elango@Sun.COM PCI_COMM_WAIT_CYC_ENAB | 6310187SKrishna.Elango@Sun.COM PCI_COMM_PARITY_DETECT | 6410187SKrishna.Elango@Sun.COM PCI_COMM_ME | 6510187SKrishna.Elango@Sun.COM PCI_COMM_MAE | 6610187SKrishna.Elango@Sun.COM PCI_COMM_IO; 6710187SKrishna.Elango@Sun.COM 6810187SKrishna.Elango@Sun.COM /* xxx_fw are bits that are controlled by FW and should not be modified */ 6910187SKrishna.Elango@Sun.COM ushort_t pcie_command_default_fw = 7010187SKrishna.Elango@Sun.COM PCI_COMM_SPEC_CYC | 7110187SKrishna.Elango@Sun.COM PCI_COMM_MEMWR_INVAL | 7210187SKrishna.Elango@Sun.COM PCI_COMM_PALETTE_SNOOP | 7310187SKrishna.Elango@Sun.COM PCI_COMM_WAIT_CYC_ENAB | 7410187SKrishna.Elango@Sun.COM 0xF800; /* Reserved Bits */ 7510187SKrishna.Elango@Sun.COM 7610187SKrishna.Elango@Sun.COM ushort_t pcie_bdg_command_default_fw = 7710187SKrishna.Elango@Sun.COM PCI_BCNF_BCNTRL_ISA_ENABLE | 7810187SKrishna.Elango@Sun.COM PCI_BCNF_BCNTRL_VGA_ENABLE | 7910187SKrishna.Elango@Sun.COM 0xF000; /* Reserved Bits */ 8010187SKrishna.Elango@Sun.COM 8110187SKrishna.Elango@Sun.COM /* PCI-Express Base error defaults */ 8210187SKrishna.Elango@Sun.COM ushort_t pcie_base_err_default = 8310187SKrishna.Elango@Sun.COM PCIE_DEVCTL_CE_REPORTING_EN | 8410187SKrishna.Elango@Sun.COM PCIE_DEVCTL_NFE_REPORTING_EN | 8510187SKrishna.Elango@Sun.COM PCIE_DEVCTL_FE_REPORTING_EN | 8610187SKrishna.Elango@Sun.COM PCIE_DEVCTL_UR_REPORTING_EN; 8710187SKrishna.Elango@Sun.COM 8810187SKrishna.Elango@Sun.COM /* PCI-Express Device Control Register */ 8910187SKrishna.Elango@Sun.COM uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN | 9010187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_READ_REQ_512; 9110187SKrishna.Elango@Sun.COM 9210187SKrishna.Elango@Sun.COM /* PCI-Express AER Root Control Register */ 9310187SKrishna.Elango@Sun.COM #define PCIE_ROOT_SYS_ERR (PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \ 9410187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \ 9510187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_FE_EN) 9610187SKrishna.Elango@Sun.COM 9710187SKrishna.Elango@Sun.COM #if defined(__xpv) 9810187SKrishna.Elango@Sun.COM ushort_t pcie_root_ctrl_default = 9910187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | 10010187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_FE_EN; 10110187SKrishna.Elango@Sun.COM #else 10210187SKrishna.Elango@Sun.COM ushort_t pcie_root_ctrl_default = 10310187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | 10410187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | 10510187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_FE_EN; 10610187SKrishna.Elango@Sun.COM #endif /* __xpv */ 10710187SKrishna.Elango@Sun.COM 10810187SKrishna.Elango@Sun.COM /* PCI-Express Root Error Command Register */ 10910187SKrishna.Elango@Sun.COM ushort_t pcie_root_error_cmd_default = 11010187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_CE_REP_EN | 11110187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_NFE_REP_EN | 11210187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_FE_REP_EN; 11310187SKrishna.Elango@Sun.COM 11410187SKrishna.Elango@Sun.COM /* ECRC settings in the PCIe AER Control Register */ 11510187SKrishna.Elango@Sun.COM uint32_t pcie_ecrc_value = 11610187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_GEN_ENA | 11710187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_CHECK_ENA; 11810187SKrishna.Elango@Sun.COM 11910187SKrishna.Elango@Sun.COM /* 12010187SKrishna.Elango@Sun.COM * If a particular platform wants to disable certain errors such as UR/MA, 12110187SKrishna.Elango@Sun.COM * instead of using #defines have the platform's PCIe Root Complex driver set 12210187SKrishna.Elango@Sun.COM * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions. For 123*10923SEvan.Yan@Sun.COM * x86 the closest thing to a PCIe root complex driver is NPE. For SPARC the 12410187SKrishna.Elango@Sun.COM * closest PCIe root complex driver is PX. 12510187SKrishna.Elango@Sun.COM * 12610187SKrishna.Elango@Sun.COM * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86 12710187SKrishna.Elango@Sun.COM * systems may want to disable SERR in general. For root ports, enabling SERR 12810187SKrishna.Elango@Sun.COM * causes NMIs which are not handled and results in a watchdog timeout error. 12910187SKrishna.Elango@Sun.COM */ 13010187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_mask = 0; /* AER UE Mask */ 13110187SKrishna.Elango@Sun.COM uint32_t pcie_aer_ce_mask = 0; /* AER CE Mask */ 13210187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_mask = 0; /* AER Secondary UE Mask */ 13310187SKrishna.Elango@Sun.COM uint32_t pcie_serr_disable_flag = 0; /* Disable SERR */ 13410187SKrishna.Elango@Sun.COM 13510187SKrishna.Elango@Sun.COM /* Default severities needed for eversholt. Error handling doesn't care */ 13610187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \ 13710187SKrishna.Elango@Sun.COM PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \ 13810187SKrishna.Elango@Sun.COM PCIE_AER_UCE_TRAINING; 13910187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \ 14010187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \ 14110187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_USC_MSG_DATA_ERR; 14210187SKrishna.Elango@Sun.COM 14310187SKrishna.Elango@Sun.COM int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5; 144*10923SEvan.Yan@Sun.COM int pcie_disable_ari = 0; 14510187SKrishna.Elango@Sun.COM 14610187SKrishna.Elango@Sun.COM static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, 14710187SKrishna.Elango@Sun.COM int *max_supported); 14810187SKrishna.Elango@Sun.COM static int pcie_get_max_supported(dev_info_t *dip, void *arg); 14910187SKrishna.Elango@Sun.COM static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 15010187SKrishna.Elango@Sun.COM caddr_t *addrp, ddi_acc_handle_t *handlep); 151*10923SEvan.Yan@Sun.COM static void pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph); 15210187SKrishna.Elango@Sun.COM 15310187SKrishna.Elango@Sun.COM /* 15410187SKrishna.Elango@Sun.COM * modload support 15510187SKrishna.Elango@Sun.COM */ 15610187SKrishna.Elango@Sun.COM 15710187SKrishna.Elango@Sun.COM static struct modlmisc modlmisc = { 15810187SKrishna.Elango@Sun.COM &mod_miscops, /* Type of module */ 159*10923SEvan.Yan@Sun.COM "PCI Express Framework Module" 16010187SKrishna.Elango@Sun.COM }; 16110187SKrishna.Elango@Sun.COM 16210187SKrishna.Elango@Sun.COM static struct modlinkage modlinkage = { 16310187SKrishna.Elango@Sun.COM MODREV_1, 16410187SKrishna.Elango@Sun.COM (void *)&modlmisc, 16510187SKrishna.Elango@Sun.COM NULL 16610187SKrishna.Elango@Sun.COM }; 16710187SKrishna.Elango@Sun.COM 16810187SKrishna.Elango@Sun.COM /* 16910187SKrishna.Elango@Sun.COM * Global Variables needed for a non-atomic version of ddi_fm_ereport_post. 17010187SKrishna.Elango@Sun.COM * Currently used to send the pci.fabric ereports whose payload depends on the 17110187SKrishna.Elango@Sun.COM * type of PCI device it is being sent for. 17210187SKrishna.Elango@Sun.COM */ 17310187SKrishna.Elango@Sun.COM char *pcie_nv_buf; 17410187SKrishna.Elango@Sun.COM nv_alloc_t *pcie_nvap; 17510187SKrishna.Elango@Sun.COM nvlist_t *pcie_nvl; 17610187SKrishna.Elango@Sun.COM 17710187SKrishna.Elango@Sun.COM int 17810187SKrishna.Elango@Sun.COM _init(void) 17910187SKrishna.Elango@Sun.COM { 18010187SKrishna.Elango@Sun.COM int rval; 18110187SKrishna.Elango@Sun.COM 18210187SKrishna.Elango@Sun.COM pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP); 18310187SKrishna.Elango@Sun.COM pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ); 18410187SKrishna.Elango@Sun.COM pcie_nvl = fm_nvlist_create(pcie_nvap); 18510187SKrishna.Elango@Sun.COM 18610187SKrishna.Elango@Sun.COM rval = mod_install(&modlinkage); 18710187SKrishna.Elango@Sun.COM return (rval); 18810187SKrishna.Elango@Sun.COM } 18910187SKrishna.Elango@Sun.COM 19010187SKrishna.Elango@Sun.COM int 19110187SKrishna.Elango@Sun.COM _fini() 19210187SKrishna.Elango@Sun.COM { 19310187SKrishna.Elango@Sun.COM int rval; 19410187SKrishna.Elango@Sun.COM 19510187SKrishna.Elango@Sun.COM fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN); 19610187SKrishna.Elango@Sun.COM fm_nva_xdestroy(pcie_nvap); 19710187SKrishna.Elango@Sun.COM kmem_free(pcie_nv_buf, ERPT_DATA_SZ); 19810187SKrishna.Elango@Sun.COM 19910187SKrishna.Elango@Sun.COM rval = mod_remove(&modlinkage); 20010187SKrishna.Elango@Sun.COM return (rval); 20110187SKrishna.Elango@Sun.COM } 20210187SKrishna.Elango@Sun.COM 20310187SKrishna.Elango@Sun.COM int 20410187SKrishna.Elango@Sun.COM _info(struct modinfo *modinfop) 20510187SKrishna.Elango@Sun.COM { 20610187SKrishna.Elango@Sun.COM return (mod_info(&modlinkage, modinfop)); 20710187SKrishna.Elango@Sun.COM } 20810187SKrishna.Elango@Sun.COM 209*10923SEvan.Yan@Sun.COM /* ARGSUSED */ 210*10923SEvan.Yan@Sun.COM int 211*10923SEvan.Yan@Sun.COM pcie_init(dev_info_t *dip, caddr_t arg) 212*10923SEvan.Yan@Sun.COM { 213*10923SEvan.Yan@Sun.COM int ret = DDI_SUCCESS; 214*10923SEvan.Yan@Sun.COM 215*10923SEvan.Yan@Sun.COM /* 216*10923SEvan.Yan@Sun.COM * Create a "devctl" minor node to support DEVCTL_DEVICE_* 217*10923SEvan.Yan@Sun.COM * and DEVCTL_BUS_* ioctls to this bus. 218*10923SEvan.Yan@Sun.COM */ 219*10923SEvan.Yan@Sun.COM if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR, 220*10923SEvan.Yan@Sun.COM PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR), 221*10923SEvan.Yan@Sun.COM DDI_NT_NEXUS, 0)) != DDI_SUCCESS) { 222*10923SEvan.Yan@Sun.COM PCIE_DBG("Failed to create devctl minor node for %s%d\n", 223*10923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 224*10923SEvan.Yan@Sun.COM 225*10923SEvan.Yan@Sun.COM return (ret); 226*10923SEvan.Yan@Sun.COM } 227*10923SEvan.Yan@Sun.COM 228*10923SEvan.Yan@Sun.COM if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) { 229*10923SEvan.Yan@Sun.COM /* 230*10923SEvan.Yan@Sun.COM * On a few x86 platforms, we observed unexpected hotplug 231*10923SEvan.Yan@Sun.COM * initialization failures in recent years. Continue with 232*10923SEvan.Yan@Sun.COM * a message printed because we don't want to stop PCI 233*10923SEvan.Yan@Sun.COM * driver attach and system boot because of this hotplug 234*10923SEvan.Yan@Sun.COM * initialization failure before we address all those issues. 235*10923SEvan.Yan@Sun.COM */ 236*10923SEvan.Yan@Sun.COM cmn_err(CE_WARN, "%s%d: Failed setting hotplug framework\n", 237*10923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 238*10923SEvan.Yan@Sun.COM 239*10923SEvan.Yan@Sun.COM #if defined(__sparc) 240*10923SEvan.Yan@Sun.COM ddi_remove_minor_node(dip, "devctl"); 241*10923SEvan.Yan@Sun.COM 242*10923SEvan.Yan@Sun.COM return (ret); 243*10923SEvan.Yan@Sun.COM #endif /* defined(__sparc) */ 244*10923SEvan.Yan@Sun.COM } 245*10923SEvan.Yan@Sun.COM 246*10923SEvan.Yan@Sun.COM if ((pcie_ari_supported(dip) == PCIE_ARI_FORW_SUPPORTED) && 247*10923SEvan.Yan@Sun.COM (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_DISABLED)) 248*10923SEvan.Yan@Sun.COM (void) pcicfg_configure(dip, 0, PCICFG_ALL_FUNC, 249*10923SEvan.Yan@Sun.COM PCICFG_FLAG_ENABLE_ARI); 250*10923SEvan.Yan@Sun.COM 251*10923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 252*10923SEvan.Yan@Sun.COM } 253*10923SEvan.Yan@Sun.COM 254*10923SEvan.Yan@Sun.COM /* ARGSUSED */ 255*10923SEvan.Yan@Sun.COM int 256*10923SEvan.Yan@Sun.COM pcie_uninit(dev_info_t *dip) 257*10923SEvan.Yan@Sun.COM { 258*10923SEvan.Yan@Sun.COM int ret = DDI_SUCCESS; 259*10923SEvan.Yan@Sun.COM 260*10923SEvan.Yan@Sun.COM if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED) 261*10923SEvan.Yan@Sun.COM (void) pcie_ari_disable(dip); 262*10923SEvan.Yan@Sun.COM 263*10923SEvan.Yan@Sun.COM if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) { 264*10923SEvan.Yan@Sun.COM PCIE_DBG("Failed to uninitialize hotplug for %s%d\n", 265*10923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 266*10923SEvan.Yan@Sun.COM 267*10923SEvan.Yan@Sun.COM return (ret); 268*10923SEvan.Yan@Sun.COM } 269*10923SEvan.Yan@Sun.COM 270*10923SEvan.Yan@Sun.COM ddi_remove_minor_node(dip, "devctl"); 271*10923SEvan.Yan@Sun.COM 272*10923SEvan.Yan@Sun.COM return (ret); 273*10923SEvan.Yan@Sun.COM } 274*10923SEvan.Yan@Sun.COM 275*10923SEvan.Yan@Sun.COM /* ARGSUSED */ 276*10923SEvan.Yan@Sun.COM int 277*10923SEvan.Yan@Sun.COM pcie_intr(dev_info_t *dip) 278*10923SEvan.Yan@Sun.COM { 279*10923SEvan.Yan@Sun.COM return (pcie_hp_intr(dip)); 280*10923SEvan.Yan@Sun.COM } 281*10923SEvan.Yan@Sun.COM 282*10923SEvan.Yan@Sun.COM /* ARGSUSED */ 283*10923SEvan.Yan@Sun.COM int 284*10923SEvan.Yan@Sun.COM pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp) 285*10923SEvan.Yan@Sun.COM { 286*10923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 287*10923SEvan.Yan@Sun.COM 288*10923SEvan.Yan@Sun.COM /* 289*10923SEvan.Yan@Sun.COM * Make sure the open is for the right file type. 290*10923SEvan.Yan@Sun.COM */ 291*10923SEvan.Yan@Sun.COM if (otyp != OTYP_CHR) 292*10923SEvan.Yan@Sun.COM return (EINVAL); 293*10923SEvan.Yan@Sun.COM 294*10923SEvan.Yan@Sun.COM /* 295*10923SEvan.Yan@Sun.COM * Handle the open by tracking the device state. 296*10923SEvan.Yan@Sun.COM */ 297*10923SEvan.Yan@Sun.COM if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) || 298*10923SEvan.Yan@Sun.COM ((flags & FEXCL) && 299*10923SEvan.Yan@Sun.COM (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) { 300*10923SEvan.Yan@Sun.COM return (EBUSY); 301*10923SEvan.Yan@Sun.COM } 302*10923SEvan.Yan@Sun.COM 303*10923SEvan.Yan@Sun.COM if (flags & FEXCL) 304*10923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL; 305*10923SEvan.Yan@Sun.COM else 306*10923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN; 307*10923SEvan.Yan@Sun.COM 308*10923SEvan.Yan@Sun.COM return (0); 309*10923SEvan.Yan@Sun.COM } 310*10923SEvan.Yan@Sun.COM 311*10923SEvan.Yan@Sun.COM /* ARGSUSED */ 312*10923SEvan.Yan@Sun.COM int 313*10923SEvan.Yan@Sun.COM pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp) 314*10923SEvan.Yan@Sun.COM { 315*10923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 316*10923SEvan.Yan@Sun.COM 317*10923SEvan.Yan@Sun.COM if (otyp != OTYP_CHR) 318*10923SEvan.Yan@Sun.COM return (EINVAL); 319*10923SEvan.Yan@Sun.COM 320*10923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED; 321*10923SEvan.Yan@Sun.COM 322*10923SEvan.Yan@Sun.COM return (0); 323*10923SEvan.Yan@Sun.COM } 324*10923SEvan.Yan@Sun.COM 325*10923SEvan.Yan@Sun.COM /* ARGSUSED */ 326*10923SEvan.Yan@Sun.COM int 327*10923SEvan.Yan@Sun.COM pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode, 328*10923SEvan.Yan@Sun.COM cred_t *credp, int *rvalp) 329*10923SEvan.Yan@Sun.COM { 330*10923SEvan.Yan@Sun.COM struct devctl_iocdata *dcp; 331*10923SEvan.Yan@Sun.COM uint_t bus_state; 332*10923SEvan.Yan@Sun.COM int rv = DDI_SUCCESS; 333*10923SEvan.Yan@Sun.COM 334*10923SEvan.Yan@Sun.COM /* 335*10923SEvan.Yan@Sun.COM * We can use the generic implementation for devctl ioctl 336*10923SEvan.Yan@Sun.COM */ 337*10923SEvan.Yan@Sun.COM switch (cmd) { 338*10923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_GETSTATE: 339*10923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_ONLINE: 340*10923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_OFFLINE: 341*10923SEvan.Yan@Sun.COM case DEVCTL_BUS_GETSTATE: 342*10923SEvan.Yan@Sun.COM return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0)); 343*10923SEvan.Yan@Sun.COM default: 344*10923SEvan.Yan@Sun.COM break; 345*10923SEvan.Yan@Sun.COM } 346*10923SEvan.Yan@Sun.COM 347*10923SEvan.Yan@Sun.COM /* 348*10923SEvan.Yan@Sun.COM * read devctl ioctl data 349*10923SEvan.Yan@Sun.COM */ 350*10923SEvan.Yan@Sun.COM if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 351*10923SEvan.Yan@Sun.COM return (EFAULT); 352*10923SEvan.Yan@Sun.COM 353*10923SEvan.Yan@Sun.COM switch (cmd) { 354*10923SEvan.Yan@Sun.COM case DEVCTL_BUS_QUIESCE: 355*10923SEvan.Yan@Sun.COM if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) 356*10923SEvan.Yan@Sun.COM if (bus_state == BUS_QUIESCED) 357*10923SEvan.Yan@Sun.COM break; 358*10923SEvan.Yan@Sun.COM (void) ndi_set_bus_state(dip, BUS_QUIESCED); 359*10923SEvan.Yan@Sun.COM break; 360*10923SEvan.Yan@Sun.COM case DEVCTL_BUS_UNQUIESCE: 361*10923SEvan.Yan@Sun.COM if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) 362*10923SEvan.Yan@Sun.COM if (bus_state == BUS_ACTIVE) 363*10923SEvan.Yan@Sun.COM break; 364*10923SEvan.Yan@Sun.COM (void) ndi_set_bus_state(dip, BUS_ACTIVE); 365*10923SEvan.Yan@Sun.COM break; 366*10923SEvan.Yan@Sun.COM case DEVCTL_BUS_RESET: 367*10923SEvan.Yan@Sun.COM case DEVCTL_BUS_RESETALL: 368*10923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_RESET: 369*10923SEvan.Yan@Sun.COM rv = ENOTSUP; 370*10923SEvan.Yan@Sun.COM break; 371*10923SEvan.Yan@Sun.COM default: 372*10923SEvan.Yan@Sun.COM rv = ENOTTY; 373*10923SEvan.Yan@Sun.COM } 374*10923SEvan.Yan@Sun.COM 375*10923SEvan.Yan@Sun.COM ndi_dc_freehdl(dcp); 376*10923SEvan.Yan@Sun.COM return (rv); 377*10923SEvan.Yan@Sun.COM } 378*10923SEvan.Yan@Sun.COM 379*10923SEvan.Yan@Sun.COM /* ARGSUSED */ 380*10923SEvan.Yan@Sun.COM int 381*10923SEvan.Yan@Sun.COM pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 382*10923SEvan.Yan@Sun.COM int flags, char *name, caddr_t valuep, int *lengthp) 383*10923SEvan.Yan@Sun.COM { 384*10923SEvan.Yan@Sun.COM if (dev == DDI_DEV_T_ANY) 385*10923SEvan.Yan@Sun.COM goto skip; 386*10923SEvan.Yan@Sun.COM 387*10923SEvan.Yan@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip) && 388*10923SEvan.Yan@Sun.COM strcmp(name, "pci-occupant") == 0) { 389*10923SEvan.Yan@Sun.COM int pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev)); 390*10923SEvan.Yan@Sun.COM 391*10923SEvan.Yan@Sun.COM pcie_hp_create_occupant_props(dip, dev, pci_dev); 392*10923SEvan.Yan@Sun.COM } 393*10923SEvan.Yan@Sun.COM 394*10923SEvan.Yan@Sun.COM skip: 395*10923SEvan.Yan@Sun.COM return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); 396*10923SEvan.Yan@Sun.COM } 397*10923SEvan.Yan@Sun.COM 39810187SKrishna.Elango@Sun.COM /* 39910187SKrishna.Elango@Sun.COM * PCI-Express child device initialization. 40010187SKrishna.Elango@Sun.COM * This function enables generic pci-express interrupts and error 40110187SKrishna.Elango@Sun.COM * handling. 40210187SKrishna.Elango@Sun.COM * 40310187SKrishna.Elango@Sun.COM * @param pdip root dip (root nexus's dip) 40410187SKrishna.Elango@Sun.COM * @param cdip child's dip (device's dip) 40510187SKrishna.Elango@Sun.COM * @return DDI_SUCCESS or DDI_FAILURE 40610187SKrishna.Elango@Sun.COM */ 40710187SKrishna.Elango@Sun.COM /* ARGSUSED */ 40810187SKrishna.Elango@Sun.COM int 40910187SKrishna.Elango@Sun.COM pcie_initchild(dev_info_t *cdip) 41010187SKrishna.Elango@Sun.COM { 41110187SKrishna.Elango@Sun.COM uint16_t tmp16, reg16; 41210187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 41310187SKrishna.Elango@Sun.COM 41410187SKrishna.Elango@Sun.COM bus_p = PCIE_DIP2BUS(cdip); 41510187SKrishna.Elango@Sun.COM if (bus_p == NULL) { 41610187SKrishna.Elango@Sun.COM PCIE_DBG("%s: BUS not found.\n", 41710187SKrishna.Elango@Sun.COM ddi_driver_name(cdip)); 41810187SKrishna.Elango@Sun.COM 41910187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 42010187SKrishna.Elango@Sun.COM } 42110187SKrishna.Elango@Sun.COM 42210187SKrishna.Elango@Sun.COM /* Clear the device's status register */ 42310187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT); 42410187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16); 42510187SKrishna.Elango@Sun.COM 42610187SKrishna.Elango@Sun.COM /* Setup the device's command register */ 42710187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM); 42810187SKrishna.Elango@Sun.COM tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default; 42910187SKrishna.Elango@Sun.COM 43010187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64) 43110187SKrishna.Elango@Sun.COM boolean_t empty_io_range = B_FALSE; 43210187SKrishna.Elango@Sun.COM boolean_t empty_mem_range = B_FALSE; 43310187SKrishna.Elango@Sun.COM /* 43410187SKrishna.Elango@Sun.COM * Check for empty IO and Mem ranges on bridges. If so disable IO/Mem 43510187SKrishna.Elango@Sun.COM * access as it can cause a hang if enabled. 43610187SKrishna.Elango@Sun.COM */ 43710187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(bus_p->bus_cfg_hdl, &empty_io_range, 43810187SKrishna.Elango@Sun.COM &empty_mem_range); 43910187SKrishna.Elango@Sun.COM if ((empty_io_range == B_TRUE) && 44010187SKrishna.Elango@Sun.COM (pcie_command_default & PCI_COMM_IO)) { 44110187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_IO; 44210187SKrishna.Elango@Sun.COM PCIE_DBG("No I/O range found for %s, bdf 0x%x\n", 44310187SKrishna.Elango@Sun.COM ddi_driver_name(cdip), bus_p->bus_bdf); 44410187SKrishna.Elango@Sun.COM } 44510187SKrishna.Elango@Sun.COM if ((empty_mem_range == B_TRUE) && 44610187SKrishna.Elango@Sun.COM (pcie_command_default & PCI_COMM_MAE)) { 44710187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_MAE; 44810187SKrishna.Elango@Sun.COM PCIE_DBG("No Mem range found for %s, bdf 0x%x\n", 44910187SKrishna.Elango@Sun.COM ddi_driver_name(cdip), bus_p->bus_bdf); 45010187SKrishna.Elango@Sun.COM } 45110187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */ 45210187SKrishna.Elango@Sun.COM 45310187SKrishna.Elango@Sun.COM if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p)) 45410187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_SERR_ENABLE; 45510187SKrishna.Elango@Sun.COM 45610187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16); 45710187SKrishna.Elango@Sun.COM PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16); 45810187SKrishna.Elango@Sun.COM 45910187SKrishna.Elango@Sun.COM /* 46010187SKrishna.Elango@Sun.COM * If the device has a bus control register then program it 46110187SKrishna.Elango@Sun.COM * based on the settings in the command register. 46210187SKrishna.Elango@Sun.COM */ 46310187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 46410187SKrishna.Elango@Sun.COM /* Clear the device's secondary status register */ 46510187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS); 46610187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16); 46710187SKrishna.Elango@Sun.COM 46810187SKrishna.Elango@Sun.COM /* Setup the device's secondary command register */ 46910187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL); 47010187SKrishna.Elango@Sun.COM tmp16 = (reg16 & pcie_bdg_command_default_fw); 47110187SKrishna.Elango@Sun.COM 47210187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE; 47310187SKrishna.Elango@Sun.COM /* 47410187SKrishna.Elango@Sun.COM * Workaround for this Nvidia bridge. Don't enable the SERR 47510187SKrishna.Elango@Sun.COM * enable bit in the bridge control register as it could lead to 47610187SKrishna.Elango@Sun.COM * bogus NMIs. 47710187SKrishna.Elango@Sun.COM */ 47810187SKrishna.Elango@Sun.COM if (bus_p->bus_dev_ven_id == 0x037010DE) 47910187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE; 48010187SKrishna.Elango@Sun.COM 48110187SKrishna.Elango@Sun.COM if (pcie_command_default & PCI_COMM_PARITY_DETECT) 48210187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE; 48310187SKrishna.Elango@Sun.COM 48410187SKrishna.Elango@Sun.COM /* 48510187SKrishna.Elango@Sun.COM * Enable Master Abort Mode only if URs have not been masked. 48610187SKrishna.Elango@Sun.COM * For PCI and PCIe-PCI bridges, enabling this bit causes a 48710187SKrishna.Elango@Sun.COM * Master Aborts/UR to be forwarded as a UR/TA or SERR. If this 48810187SKrishna.Elango@Sun.COM * bit is masked, posted requests are dropped and non-posted 48910187SKrishna.Elango@Sun.COM * requests are returned with -1. 49010187SKrishna.Elango@Sun.COM */ 49110187SKrishna.Elango@Sun.COM if (pcie_aer_uce_mask & PCIE_AER_UCE_UR) 49210187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE; 49310187SKrishna.Elango@Sun.COM else 49410187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE; 49510187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16); 49610187SKrishna.Elango@Sun.COM PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL, 49710187SKrishna.Elango@Sun.COM reg16); 49810187SKrishna.Elango@Sun.COM } 49910187SKrishna.Elango@Sun.COM 50010187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 50110187SKrishna.Elango@Sun.COM /* Setup PCIe device control register */ 50210187SKrishna.Elango@Sun.COM reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 50310187SKrishna.Elango@Sun.COM tmp16 = pcie_devctl_default; 50410187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16); 50510187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16); 50610187SKrishna.Elango@Sun.COM 50710187SKrishna.Elango@Sun.COM /* Enable PCIe errors */ 50810187SKrishna.Elango@Sun.COM pcie_enable_errors(cdip); 50910187SKrishna.Elango@Sun.COM } 51010187SKrishna.Elango@Sun.COM 511*10923SEvan.Yan@Sun.COM bus_p->bus_ari = B_FALSE; 512*10923SEvan.Yan@Sun.COM if ((pcie_ari_is_enabled(ddi_get_parent(cdip)) 513*10923SEvan.Yan@Sun.COM == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip) 514*10923SEvan.Yan@Sun.COM == PCIE_ARI_DEVICE)) { 515*10923SEvan.Yan@Sun.COM bus_p->bus_ari = B_TRUE; 516*10923SEvan.Yan@Sun.COM } 517*10923SEvan.Yan@Sun.COM 51810187SKrishna.Elango@Sun.COM if (pcie_initchild_mps(cdip) == DDI_FAILURE) 51910187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 52010187SKrishna.Elango@Sun.COM 52110187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 52210187SKrishna.Elango@Sun.COM } 52310187SKrishna.Elango@Sun.COM 52410187SKrishna.Elango@Sun.COM #define PCIE_ZALLOC(data) kmem_zalloc(sizeof (data), KM_SLEEP) 52510187SKrishna.Elango@Sun.COM static void 52610187SKrishna.Elango@Sun.COM pcie_init_pfd(dev_info_t *dip) 52710187SKrishna.Elango@Sun.COM { 52810187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_ZALLOC(pf_data_t); 52910187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 53010187SKrishna.Elango@Sun.COM 53110187SKrishna.Elango@Sun.COM PCIE_DIP2PFD(dip) = pfd_p; 53210187SKrishna.Elango@Sun.COM 53310187SKrishna.Elango@Sun.COM pfd_p->pe_bus_p = bus_p; 53410187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = 0; 53510187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE; 53610187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE; 53710187SKrishna.Elango@Sun.COM 53810187SKrishna.Elango@Sun.COM /* Allocate the root fault struct for both RC and RP */ 53910187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) { 54010187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t); 54110187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF; 54210187SKrishna.Elango@Sun.COM } 54310187SKrishna.Elango@Sun.COM 54410187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t); 54510187SKrishna.Elango@Sun.COM 54610187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) 54710187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t); 54810187SKrishna.Elango@Sun.COM 54910187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 55010187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t); 55110187SKrishna.Elango@Sun.COM 55210187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 55310187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p) = 55410187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_rp_err_regs_t); 55510187SKrishna.Elango@Sun.COM 55610187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t); 55710187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF; 55810187SKrishna.Elango@Sun.COM 55910187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) { 56010187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p) = 56110187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t); 56210187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = 56310187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 56410187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = 56510187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 56610187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIE_BDG(bus_p)) { 56710187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p) = 56810187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t); 56910187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = 57010187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 57110187SKrishna.Elango@Sun.COM } 57210187SKrishna.Elango@Sun.COM 57310187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) { 57410187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p) = 57510187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_bdg_err_regs_t); 57610187SKrishna.Elango@Sun.COM 57710187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 57810187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0) = 57910187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 58010187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 1) = 58110187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 58210187SKrishna.Elango@Sun.COM } 58310187SKrishna.Elango@Sun.COM } 58410187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIX(bus_p)) { 58510187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 58610187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p) = 58710187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_bdg_err_regs_t); 58810187SKrishna.Elango@Sun.COM 58910187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 59010187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0) = 59110187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 59210187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 1) = 59310187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 59410187SKrishna.Elango@Sun.COM } 59510187SKrishna.Elango@Sun.COM } else { 59610187SKrishna.Elango@Sun.COM PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t); 59710187SKrishna.Elango@Sun.COM 59810187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) 59910187SKrishna.Elango@Sun.COM PCIX_ECC_REG(pfd_p) = 60010187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 60110187SKrishna.Elango@Sun.COM } 60210187SKrishna.Elango@Sun.COM } 60310187SKrishna.Elango@Sun.COM } 60410187SKrishna.Elango@Sun.COM 60510187SKrishna.Elango@Sun.COM static void 60610187SKrishna.Elango@Sun.COM pcie_fini_pfd(dev_info_t *dip) 60710187SKrishna.Elango@Sun.COM { 60810187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip); 60910187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 61010187SKrishna.Elango@Sun.COM 61110187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 61210187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) { 61310187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 61410187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0), 61510187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 61610187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1), 61710187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 61810187SKrishna.Elango@Sun.COM } 61910187SKrishna.Elango@Sun.COM 62010187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ERR_REG(pfd_p), 62110187SKrishna.Elango@Sun.COM sizeof (pf_pcix_bdg_err_regs_t)); 62210187SKrishna.Elango@Sun.COM } 62310187SKrishna.Elango@Sun.COM 62410187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 62510187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_RP_REG(pfd_p), 62610187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_rp_err_regs_t)); 62710187SKrishna.Elango@Sun.COM else if (PCIE_IS_PCIE_BDG(bus_p)) 62810187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_BDG_REG(pfd_p), 62910187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_bdg_err_regs_t)); 63010187SKrishna.Elango@Sun.COM 63110187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_REG(pfd_p), 63210187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_err_regs_t)); 63310187SKrishna.Elango@Sun.COM 63410187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 63510187SKrishna.Elango@Sun.COM kmem_free(PCIE_RP_REG(pfd_p), 63610187SKrishna.Elango@Sun.COM sizeof (pf_pcie_rp_err_regs_t)); 63710187SKrishna.Elango@Sun.COM 63810187SKrishna.Elango@Sun.COM kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t)); 63910187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIX(bus_p)) { 64010187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 64110187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 64210187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0), 64310187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 64410187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1), 64510187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 64610187SKrishna.Elango@Sun.COM } 64710187SKrishna.Elango@Sun.COM 64810187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ERR_REG(pfd_p), 64910187SKrishna.Elango@Sun.COM sizeof (pf_pcix_bdg_err_regs_t)); 65010187SKrishna.Elango@Sun.COM } else { 65110187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) 65210187SKrishna.Elango@Sun.COM kmem_free(PCIX_ECC_REG(pfd_p), 65310187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 65410187SKrishna.Elango@Sun.COM 65510187SKrishna.Elango@Sun.COM kmem_free(PCIX_ERR_REG(pfd_p), 65610187SKrishna.Elango@Sun.COM sizeof (pf_pcix_err_regs_t)); 65710187SKrishna.Elango@Sun.COM } 65810187SKrishna.Elango@Sun.COM } 65910187SKrishna.Elango@Sun.COM 66010187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) 66110187SKrishna.Elango@Sun.COM kmem_free(PCI_BDG_ERR_REG(pfd_p), 66210187SKrishna.Elango@Sun.COM sizeof (pf_pci_bdg_err_regs_t)); 66310187SKrishna.Elango@Sun.COM 66410187SKrishna.Elango@Sun.COM kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t)); 66510187SKrishna.Elango@Sun.COM 66610187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) 66710187SKrishna.Elango@Sun.COM kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t)); 66810187SKrishna.Elango@Sun.COM 66910187SKrishna.Elango@Sun.COM kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t)); 67010187SKrishna.Elango@Sun.COM 67110187SKrishna.Elango@Sun.COM PCIE_DIP2PFD(dip) = NULL; 67210187SKrishna.Elango@Sun.COM } 67310187SKrishna.Elango@Sun.COM 67410187SKrishna.Elango@Sun.COM 67510187SKrishna.Elango@Sun.COM /* 67610187SKrishna.Elango@Sun.COM * Special functions to allocate pf_data_t's for PCIe root complexes. 67710187SKrishna.Elango@Sun.COM * Note: Root Complex not Root Port 67810187SKrishna.Elango@Sun.COM */ 67910187SKrishna.Elango@Sun.COM void 68010187SKrishna.Elango@Sun.COM pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p) 68110187SKrishna.Elango@Sun.COM { 68210187SKrishna.Elango@Sun.COM pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip); 68310187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = 0; 68410187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE; 68510187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE; 68610187SKrishna.Elango@Sun.COM 68710187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t); 68810187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF; 68910187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t); 69010187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t); 69110187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t); 69210187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t); 69310187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t); 69410187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t); 69510187SKrishna.Elango@Sun.COM 69610187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity; 69710187SKrishna.Elango@Sun.COM } 69810187SKrishna.Elango@Sun.COM 69910187SKrishna.Elango@Sun.COM void 70010187SKrishna.Elango@Sun.COM pcie_rc_fini_pfd(pf_data_t *pfd_p) 70110187SKrishna.Elango@Sun.COM { 70210187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t)); 70310187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t)); 70410187SKrishna.Elango@Sun.COM kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t)); 70510187SKrishna.Elango@Sun.COM kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t)); 70610187SKrishna.Elango@Sun.COM kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t)); 70710187SKrishna.Elango@Sun.COM kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t)); 70810187SKrishna.Elango@Sun.COM kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t)); 70910187SKrishna.Elango@Sun.COM } 71010187SKrishna.Elango@Sun.COM 71110187SKrishna.Elango@Sun.COM void 71210187SKrishna.Elango@Sun.COM pcie_rc_init_bus(dev_info_t *dip) 71310187SKrishna.Elango@Sun.COM { 71410187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 71510187SKrishna.Elango@Sun.COM 71610187SKrishna.Elango@Sun.COM bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP); 71710187SKrishna.Elango@Sun.COM bus_p->bus_dip = dip; 71810187SKrishna.Elango@Sun.COM bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO; 71910187SKrishna.Elango@Sun.COM bus_p->bus_hdr_type = PCI_HEADER_ONE; 72010187SKrishna.Elango@Sun.COM 72110187SKrishna.Elango@Sun.COM /* Fake that there are AER logs */ 72210187SKrishna.Elango@Sun.COM bus_p->bus_aer_off = (uint16_t)-1; 72310187SKrishna.Elango@Sun.COM 72410187SKrishna.Elango@Sun.COM /* Needed only for handle lookup */ 72510187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags |= PF_FM_READY; 72610187SKrishna.Elango@Sun.COM 72710187SKrishna.Elango@Sun.COM ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p); 72810187SKrishna.Elango@Sun.COM } 72910187SKrishna.Elango@Sun.COM 73010187SKrishna.Elango@Sun.COM void 73110187SKrishna.Elango@Sun.COM pcie_rc_fini_bus(dev_info_t *dip) 73210187SKrishna.Elango@Sun.COM { 73310187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = (pcie_bus_t *)ndi_get_bus_private(dip, B_FALSE); 734*10923SEvan.Yan@Sun.COM 73510187SKrishna.Elango@Sun.COM ndi_set_bus_private(dip, B_FALSE, NULL, NULL); 73610187SKrishna.Elango@Sun.COM kmem_free(bus_p, sizeof (pcie_bus_t)); 73710187SKrishna.Elango@Sun.COM } 73810187SKrishna.Elango@Sun.COM 73910187SKrishna.Elango@Sun.COM /* 74010187SKrishna.Elango@Sun.COM * Initialize PCIe Bus Private Data 74110187SKrishna.Elango@Sun.COM * 74210187SKrishna.Elango@Sun.COM * PCIe Bus Private Data contains commonly used PCI/PCIe information and offsets 74310187SKrishna.Elango@Sun.COM * to key registers. 74410187SKrishna.Elango@Sun.COM */ 74510187SKrishna.Elango@Sun.COM pcie_bus_t * 74610187SKrishna.Elango@Sun.COM pcie_init_bus(dev_info_t *cdip) 74710187SKrishna.Elango@Sun.COM { 74810187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = 0; 74910187SKrishna.Elango@Sun.COM ddi_acc_handle_t eh = NULL; 75010187SKrishna.Elango@Sun.COM int range_size; 75110187SKrishna.Elango@Sun.COM dev_info_t *pdip; 75210187SKrishna.Elango@Sun.COM const char *errstr = NULL; 75310187SKrishna.Elango@Sun.COM 75410187SKrishna.Elango@Sun.COM ASSERT(PCIE_DIP2UPBUS(cdip) == NULL); 75510187SKrishna.Elango@Sun.COM 75610187SKrishna.Elango@Sun.COM /* allocate memory for pcie bus data */ 75710187SKrishna.Elango@Sun.COM bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP); 75810187SKrishna.Elango@Sun.COM 75910187SKrishna.Elango@Sun.COM /* Set back pointer to dip */ 76010187SKrishna.Elango@Sun.COM bus_p->bus_dip = cdip; 76110187SKrishna.Elango@Sun.COM 76210187SKrishna.Elango@Sun.COM /* Create an config access special to error handling */ 76310187SKrishna.Elango@Sun.COM if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) { 76410187SKrishna.Elango@Sun.COM errstr = "Cannot setup config access"; 76510187SKrishna.Elango@Sun.COM goto fail; 76610187SKrishna.Elango@Sun.COM } 767*10923SEvan.Yan@Sun.COM 76810187SKrishna.Elango@Sun.COM bus_p->bus_cfg_hdl = eh; 76910187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags = 0; 770*10923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED; 77110187SKrishna.Elango@Sun.COM 77210187SKrishna.Elango@Sun.COM /* get device's bus/dev/function number */ 77310187SKrishna.Elango@Sun.COM if (pcie_get_bdf_from_dip(cdip, &bus_p->bus_bdf) != DDI_SUCCESS) { 77410187SKrishna.Elango@Sun.COM errstr = "Cannot get device BDF"; 77510187SKrishna.Elango@Sun.COM goto fail; 77610187SKrishna.Elango@Sun.COM } 77710187SKrishna.Elango@Sun.COM 77810187SKrishna.Elango@Sun.COM /* Save the Vendor Id Device Id */ 77910187SKrishna.Elango@Sun.COM bus_p->bus_dev_ven_id = PCIE_GET(32, bus_p, PCI_CONF_VENID); 78010187SKrishna.Elango@Sun.COM bus_p->bus_rev_id = PCIE_GET(8, bus_p, PCI_CONF_REVID); 78110187SKrishna.Elango@Sun.COM 78210187SKrishna.Elango@Sun.COM /* Save the Header Type */ 78310187SKrishna.Elango@Sun.COM bus_p->bus_hdr_type = PCIE_GET(8, bus_p, PCI_CONF_HEADER); 78410187SKrishna.Elango@Sun.COM bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M; 78510187SKrishna.Elango@Sun.COM 78610187SKrishna.Elango@Sun.COM /* Figure out the device type and all the relavant capability offsets */ 78710187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCI_E, &bus_p->bus_pcie_off)) 78810187SKrishna.Elango@Sun.COM != DDI_FAILURE) { 78910187SKrishna.Elango@Sun.COM bus_p->bus_dev_type = PCI_CAP_GET16(eh, NULL, 79010187SKrishna.Elango@Sun.COM bus_p->bus_pcie_off, PCIE_PCIECAP) & 79110187SKrishna.Elango@Sun.COM PCIE_PCIECAP_DEV_TYPE_MASK; 79210187SKrishna.Elango@Sun.COM 79310187SKrishna.Elango@Sun.COM if (PCI_CAP_LOCATE(eh, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_AER), 79410187SKrishna.Elango@Sun.COM &bus_p->bus_aer_off) != DDI_SUCCESS) 79510187SKrishna.Elango@Sun.COM bus_p->bus_aer_off = NULL; 796*10923SEvan.Yan@Sun.COM 797*10923SEvan.Yan@Sun.COM /* Check and save PCIe hotplug capability information */ 798*10923SEvan.Yan@Sun.COM if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) && 799*10923SEvan.Yan@Sun.COM (PCI_CAP_GET16(eh, NULL, bus_p->bus_pcie_off, PCIE_PCIECAP) 800*10923SEvan.Yan@Sun.COM & PCIE_PCIECAP_SLOT_IMPL) && 801*10923SEvan.Yan@Sun.COM (PCI_CAP_GET32(eh, NULL, bus_p->bus_pcie_off, PCIE_SLOTCAP) 802*10923SEvan.Yan@Sun.COM & PCIE_SLOTCAP_HP_CAPABLE)) 803*10923SEvan.Yan@Sun.COM bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE; 80410187SKrishna.Elango@Sun.COM } else { 80510187SKrishna.Elango@Sun.COM bus_p->bus_pcie_off = NULL; 80610187SKrishna.Elango@Sun.COM bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO; 80710187SKrishna.Elango@Sun.COM } 80810187SKrishna.Elango@Sun.COM 80910187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCIX, &bus_p->bus_pcix_off)) 81010187SKrishna.Elango@Sun.COM != DDI_FAILURE) { 81110187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) 81210187SKrishna.Elango@Sun.COM bus_p->bus_ecc_ver = PCIX_CAP_GET(16, bus_p, 81310187SKrishna.Elango@Sun.COM PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 81410187SKrishna.Elango@Sun.COM else 81510187SKrishna.Elango@Sun.COM bus_p->bus_ecc_ver = PCIX_CAP_GET(16, bus_p, 81610187SKrishna.Elango@Sun.COM PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK; 81710187SKrishna.Elango@Sun.COM } else { 81810187SKrishna.Elango@Sun.COM bus_p->bus_pcix_off = NULL; 81910187SKrishna.Elango@Sun.COM bus_p->bus_ecc_ver = NULL; 82010187SKrishna.Elango@Sun.COM } 82110187SKrishna.Elango@Sun.COM 82210187SKrishna.Elango@Sun.COM /* Save the Range information if device is a switch/bridge */ 82310187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 824*10923SEvan.Yan@Sun.COM /* Check and save PCI hotplug (SHPC) capability information */ 825*10923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCI_HOTPLUG, 826*10923SEvan.Yan@Sun.COM &bus_p->bus_pci_hp_off)) == DDI_SUCCESS) 827*10923SEvan.Yan@Sun.COM bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE; 828*10923SEvan.Yan@Sun.COM 82910187SKrishna.Elango@Sun.COM /* get "bus_range" property */ 83010187SKrishna.Elango@Sun.COM range_size = sizeof (pci_bus_range_t); 83110187SKrishna.Elango@Sun.COM if (ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 83210187SKrishna.Elango@Sun.COM "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size) 83310187SKrishna.Elango@Sun.COM != DDI_PROP_SUCCESS) { 83410187SKrishna.Elango@Sun.COM errstr = "Cannot find \"bus-range\" property"; 83510187SKrishna.Elango@Sun.COM goto fail; 83610187SKrishna.Elango@Sun.COM } 83710187SKrishna.Elango@Sun.COM 83810187SKrishna.Elango@Sun.COM /* get secondary bus number */ 83910187SKrishna.Elango@Sun.COM bus_p->bus_bdg_secbus = PCIE_GET(8, bus_p, PCI_BCNF_SECBUS); 84010187SKrishna.Elango@Sun.COM 84110187SKrishna.Elango@Sun.COM /* Get "ranges" property */ 84210187SKrishna.Elango@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 84310187SKrishna.Elango@Sun.COM "ranges", (caddr_t)&bus_p->bus_addr_ranges, 84410187SKrishna.Elango@Sun.COM &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS) 84510187SKrishna.Elango@Sun.COM bus_p->bus_addr_entries = 0; 84610187SKrishna.Elango@Sun.COM bus_p->bus_addr_entries /= sizeof (ppb_ranges_t); 84710187SKrishna.Elango@Sun.COM } 84810187SKrishna.Elango@Sun.COM 84910187SKrishna.Elango@Sun.COM /* save "assigned-addresses" property array, ignore failues */ 85010187SKrishna.Elango@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 85110187SKrishna.Elango@Sun.COM "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr, 85210187SKrishna.Elango@Sun.COM &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS) 85310187SKrishna.Elango@Sun.COM bus_p->bus_assigned_entries /= sizeof (pci_regspec_t); 85410187SKrishna.Elango@Sun.COM else 85510187SKrishna.Elango@Sun.COM bus_p->bus_assigned_entries = 0; 85610187SKrishna.Elango@Sun.COM 85710187SKrishna.Elango@Sun.COM /* save RP dip and RP bdf */ 85810187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) { 85910187SKrishna.Elango@Sun.COM bus_p->bus_rp_dip = cdip; 86010187SKrishna.Elango@Sun.COM bus_p->bus_rp_bdf = bus_p->bus_bdf; 86110187SKrishna.Elango@Sun.COM } else { 86210187SKrishna.Elango@Sun.COM for (pdip = ddi_get_parent(cdip); pdip; 86310187SKrishna.Elango@Sun.COM pdip = ddi_get_parent(pdip)) { 86410187SKrishna.Elango@Sun.COM pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip); 86510187SKrishna.Elango@Sun.COM 86610187SKrishna.Elango@Sun.COM /* 86710187SKrishna.Elango@Sun.COM * When debugging be aware that some NVIDIA x86 86810187SKrishna.Elango@Sun.COM * architectures have 2 nodes for each RP, One at Bus 86910187SKrishna.Elango@Sun.COM * 0x0 and one at Bus 0x80. The requester is from Bus 87010187SKrishna.Elango@Sun.COM * 0x80 87110187SKrishna.Elango@Sun.COM */ 87210187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(parent_bus_p)) { 87310187SKrishna.Elango@Sun.COM bus_p->bus_rp_dip = pdip; 87410187SKrishna.Elango@Sun.COM bus_p->bus_rp_bdf = parent_bus_p->bus_bdf; 87510187SKrishna.Elango@Sun.COM break; 87610187SKrishna.Elango@Sun.COM } 87710187SKrishna.Elango@Sun.COM } 87810187SKrishna.Elango@Sun.COM } 87910187SKrishna.Elango@Sun.COM 88010187SKrishna.Elango@Sun.COM ndi_set_bus_private(cdip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p); 88110187SKrishna.Elango@Sun.COM 882*10923SEvan.Yan@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(cdip)) 883*10923SEvan.Yan@Sun.COM (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, 884*10923SEvan.Yan@Sun.COM "hotplug-capable"); 885*10923SEvan.Yan@Sun.COM 88610187SKrishna.Elango@Sun.COM pcie_init_pfd(cdip); 88710187SKrishna.Elango@Sun.COM 88810187SKrishna.Elango@Sun.COM bus_p->bus_mps = 0; 88910187SKrishna.Elango@Sun.COM 89010187SKrishna.Elango@Sun.COM pcie_init_plat(cdip); 89110187SKrishna.Elango@Sun.COM 89210187SKrishna.Elango@Sun.COM PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n", 89310187SKrishna.Elango@Sun.COM ddi_driver_name(cdip), (void *)cdip, bus_p->bus_bdf, 89410187SKrishna.Elango@Sun.COM bus_p->bus_bdg_secbus); 89510187SKrishna.Elango@Sun.COM #ifdef DEBUG 89610187SKrishna.Elango@Sun.COM pcie_print_bus(bus_p); 89710187SKrishna.Elango@Sun.COM #endif 89810187SKrishna.Elango@Sun.COM 89910187SKrishna.Elango@Sun.COM return (bus_p); 90010187SKrishna.Elango@Sun.COM fail: 90110187SKrishna.Elango@Sun.COM cmn_err(CE_WARN, "PCIE init err info failed BDF 0x%x:%s\n", 90210187SKrishna.Elango@Sun.COM bus_p->bus_bdf, errstr); 90310187SKrishna.Elango@Sun.COM if (eh) 90410187SKrishna.Elango@Sun.COM pci_config_teardown(&eh); 90510187SKrishna.Elango@Sun.COM kmem_free(bus_p, sizeof (pcie_bus_t)); 90610187SKrishna.Elango@Sun.COM return (NULL); 90710187SKrishna.Elango@Sun.COM } 90810187SKrishna.Elango@Sun.COM 90910187SKrishna.Elango@Sun.COM int 91010187SKrishna.Elango@Sun.COM pcie_postattach_child(dev_info_t *cdip) 91110187SKrishna.Elango@Sun.COM { 91210187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip); 91310187SKrishna.Elango@Sun.COM 91410187SKrishna.Elango@Sun.COM if (!bus_p) 91510187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 91610187SKrishna.Elango@Sun.COM 91710187SKrishna.Elango@Sun.COM return (pcie_enable_ce(cdip)); 91810187SKrishna.Elango@Sun.COM } 91910187SKrishna.Elango@Sun.COM 92010187SKrishna.Elango@Sun.COM /* 92110187SKrishna.Elango@Sun.COM * PCI-Express child device de-initialization. 92210187SKrishna.Elango@Sun.COM * This function disables generic pci-express interrupts and error 92310187SKrishna.Elango@Sun.COM * handling. 92410187SKrishna.Elango@Sun.COM */ 92510187SKrishna.Elango@Sun.COM void 92610187SKrishna.Elango@Sun.COM pcie_uninitchild(dev_info_t *cdip) 92710187SKrishna.Elango@Sun.COM { 92810187SKrishna.Elango@Sun.COM pcie_disable_errors(cdip); 92910187SKrishna.Elango@Sun.COM pcie_fini_bus(cdip); 93010187SKrishna.Elango@Sun.COM } 93110187SKrishna.Elango@Sun.COM 93210187SKrishna.Elango@Sun.COM void 93310187SKrishna.Elango@Sun.COM pcie_fini_bus(dev_info_t *cdip) 93410187SKrishna.Elango@Sun.COM { 93510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 93610187SKrishna.Elango@Sun.COM 93710187SKrishna.Elango@Sun.COM pcie_fini_plat(cdip); 93810187SKrishna.Elango@Sun.COM pcie_fini_pfd(cdip); 93910187SKrishna.Elango@Sun.COM 94010187SKrishna.Elango@Sun.COM bus_p = PCIE_DIP2UPBUS(cdip); 94110187SKrishna.Elango@Sun.COM ASSERT(bus_p); 942*10923SEvan.Yan@Sun.COM 943*10923SEvan.Yan@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(cdip)) 944*10923SEvan.Yan@Sun.COM (void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, "hotplug-capable"); 945*10923SEvan.Yan@Sun.COM 94610187SKrishna.Elango@Sun.COM pci_config_teardown(&bus_p->bus_cfg_hdl); 94710187SKrishna.Elango@Sun.COM ndi_set_bus_private(cdip, B_TRUE, NULL, NULL); 94810187SKrishna.Elango@Sun.COM kmem_free(bus_p->bus_assigned_addr, 94910187SKrishna.Elango@Sun.COM (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries)); 95010187SKrishna.Elango@Sun.COM kmem_free(bus_p->bus_addr_ranges, 95110187SKrishna.Elango@Sun.COM (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries)); 95210187SKrishna.Elango@Sun.COM 95310187SKrishna.Elango@Sun.COM kmem_free(bus_p, sizeof (pcie_bus_t)); 95410187SKrishna.Elango@Sun.COM } 95510187SKrishna.Elango@Sun.COM 95610187SKrishna.Elango@Sun.COM void 95710187SKrishna.Elango@Sun.COM pcie_enable_errors(dev_info_t *dip) 95810187SKrishna.Elango@Sun.COM { 95910187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 96010187SKrishna.Elango@Sun.COM uint16_t reg16, tmp16; 96110187SKrishna.Elango@Sun.COM uint32_t reg32, tmp32; 96210187SKrishna.Elango@Sun.COM 96310187SKrishna.Elango@Sun.COM ASSERT(bus_p); 96410187SKrishna.Elango@Sun.COM 96510187SKrishna.Elango@Sun.COM /* 96610187SKrishna.Elango@Sun.COM * Clear any pending errors 96710187SKrishna.Elango@Sun.COM */ 96810187SKrishna.Elango@Sun.COM pcie_clear_errors(dip); 96910187SKrishna.Elango@Sun.COM 97010187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 97110187SKrishna.Elango@Sun.COM return; 97210187SKrishna.Elango@Sun.COM 97310187SKrishna.Elango@Sun.COM /* 97410187SKrishna.Elango@Sun.COM * Enable Baseline Error Handling but leave CE reporting off (poweron 97510187SKrishna.Elango@Sun.COM * default). 97610187SKrishna.Elango@Sun.COM */ 97710187SKrishna.Elango@Sun.COM if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) != 97810187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 97910187SKrishna.Elango@Sun.COM tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK | 98010187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 98110187SKrishna.Elango@Sun.COM (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 98210187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 98310187SKrishna.Elango@Sun.COM (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN)); 98410187SKrishna.Elango@Sun.COM 98510187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16); 98610187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16); 98710187SKrishna.Elango@Sun.COM } 98810187SKrishna.Elango@Sun.COM 98910187SKrishna.Elango@Sun.COM /* Enable Root Port Baseline Error Receiving */ 99010187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p) && 99110187SKrishna.Elango@Sun.COM (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) != 99210187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 99310187SKrishna.Elango@Sun.COM 99410187SKrishna.Elango@Sun.COM #if defined(__xpv) 99510187SKrishna.Elango@Sun.COM /* 99610187SKrishna.Elango@Sun.COM * When we're booted under the hypervisor we won't receive 99710187SKrishna.Elango@Sun.COM * MSI's, so to ensure that uncorrectable errors aren't ignored 99810187SKrishna.Elango@Sun.COM * we set the SERR_FAT and SERR_NONFAT bits in the Root Control 99910187SKrishna.Elango@Sun.COM * Register. 100010187SKrishna.Elango@Sun.COM */ 100110187SKrishna.Elango@Sun.COM tmp16 = pcie_root_ctrl_default; 100210187SKrishna.Elango@Sun.COM #else 100310187SKrishna.Elango@Sun.COM tmp16 = pcie_serr_disable_flag ? 100410187SKrishna.Elango@Sun.COM (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) : 100510187SKrishna.Elango@Sun.COM pcie_root_ctrl_default; 100610187SKrishna.Elango@Sun.COM #endif /* __xpv */ 100710187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16); 100810187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL, 100910187SKrishna.Elango@Sun.COM reg16); 101010187SKrishna.Elango@Sun.COM } 101110187SKrishna.Elango@Sun.COM 101210187SKrishna.Elango@Sun.COM /* 101310187SKrishna.Elango@Sun.COM * Enable PCI-Express Advanced Error Handling if Exists 101410187SKrishna.Elango@Sun.COM */ 101510187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 101610187SKrishna.Elango@Sun.COM return; 101710187SKrishna.Elango@Sun.COM 101810187SKrishna.Elango@Sun.COM /* Set Uncorrectable Severity */ 101910187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) != 102010187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 102110187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_uce_severity; 102210187SKrishna.Elango@Sun.COM 102310187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32); 102410187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV, 102510187SKrishna.Elango@Sun.COM reg32); 102610187SKrishna.Elango@Sun.COM } 102710187SKrishna.Elango@Sun.COM 102810187SKrishna.Elango@Sun.COM /* Enable Uncorrectable errors */ 102910187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) != 103010187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 103110187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_uce_mask; 103210187SKrishna.Elango@Sun.COM 103310187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32); 103410187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK, 103510187SKrishna.Elango@Sun.COM reg32); 103610187SKrishna.Elango@Sun.COM } 103710187SKrishna.Elango@Sun.COM 103810187SKrishna.Elango@Sun.COM /* Enable ECRC generation and checking */ 103910187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) != 104010187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 104110187SKrishna.Elango@Sun.COM tmp32 = reg32 | pcie_ecrc_value; 104210187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32); 104310187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32); 104410187SKrishna.Elango@Sun.COM } 104510187SKrishna.Elango@Sun.COM 104610187SKrishna.Elango@Sun.COM /* Enable Secondary Uncorrectable errors if this is a bridge */ 104710187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) 104810187SKrishna.Elango@Sun.COM goto root; 104910187SKrishna.Elango@Sun.COM 105010187SKrishna.Elango@Sun.COM /* Set Uncorrectable Severity */ 105110187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) != 105210187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 105310187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_suce_severity; 105410187SKrishna.Elango@Sun.COM 105510187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32); 105610187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV, 105710187SKrishna.Elango@Sun.COM reg32); 105810187SKrishna.Elango@Sun.COM } 105910187SKrishna.Elango@Sun.COM 106010187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) != 106110187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 106210187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask); 106310187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32, 106410187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MASK, reg32); 106510187SKrishna.Elango@Sun.COM } 106610187SKrishna.Elango@Sun.COM 106710187SKrishna.Elango@Sun.COM root: 106810187SKrishna.Elango@Sun.COM /* 106910187SKrishna.Elango@Sun.COM * Enable Root Control this is a Root device 107010187SKrishna.Elango@Sun.COM */ 107110187SKrishna.Elango@Sun.COM if (!PCIE_IS_ROOT(bus_p)) 107210187SKrishna.Elango@Sun.COM return; 107310187SKrishna.Elango@Sun.COM 107410187SKrishna.Elango@Sun.COM #if !defined(__xpv) 107510187SKrishna.Elango@Sun.COM if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) != 107610187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 107710187SKrishna.Elango@Sun.COM PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD, 107810187SKrishna.Elango@Sun.COM pcie_root_error_cmd_default); 107910187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16, 108010187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD, reg16); 108110187SKrishna.Elango@Sun.COM } 108210187SKrishna.Elango@Sun.COM #endif /* __xpv */ 108310187SKrishna.Elango@Sun.COM } 108410187SKrishna.Elango@Sun.COM 108510187SKrishna.Elango@Sun.COM /* 108610187SKrishna.Elango@Sun.COM * This function is used for enabling CE reporting and setting the AER CE mask. 108710187SKrishna.Elango@Sun.COM * When called from outside the pcie module it should always be preceded by 108810187SKrishna.Elango@Sun.COM * a call to pcie_enable_errors. 108910187SKrishna.Elango@Sun.COM */ 109010187SKrishna.Elango@Sun.COM int 109110187SKrishna.Elango@Sun.COM pcie_enable_ce(dev_info_t *dip) 109210187SKrishna.Elango@Sun.COM { 109310187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 109410187SKrishna.Elango@Sun.COM uint16_t device_sts, device_ctl; 109510187SKrishna.Elango@Sun.COM uint32_t tmp_pcie_aer_ce_mask; 109610187SKrishna.Elango@Sun.COM 109710187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 109810187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 109910187SKrishna.Elango@Sun.COM 110010187SKrishna.Elango@Sun.COM /* 110110187SKrishna.Elango@Sun.COM * The "pcie_ce_mask" property is used to control both the CE reporting 110210187SKrishna.Elango@Sun.COM * enable field in the device control register and the AER CE mask. We 110310187SKrishna.Elango@Sun.COM * leave CE reporting disabled if pcie_ce_mask is set to -1. 110410187SKrishna.Elango@Sun.COM */ 110510187SKrishna.Elango@Sun.COM 110610187SKrishna.Elango@Sun.COM tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 110710187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask); 110810187SKrishna.Elango@Sun.COM 110910187SKrishna.Elango@Sun.COM if (tmp_pcie_aer_ce_mask == (uint32_t)-1) { 111010187SKrishna.Elango@Sun.COM /* 111110187SKrishna.Elango@Sun.COM * Nothing to do since CE reporting has already been disabled. 111210187SKrishna.Elango@Sun.COM */ 111310187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 111410187SKrishna.Elango@Sun.COM } 111510187SKrishna.Elango@Sun.COM 111610187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(bus_p)) { 111710187SKrishna.Elango@Sun.COM /* Enable AER CE */ 111810187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask); 111910187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK, 112010187SKrishna.Elango@Sun.COM 0); 112110187SKrishna.Elango@Sun.COM 112210187SKrishna.Elango@Sun.COM /* Clear any pending AER CE errors */ 112310187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1); 112410187SKrishna.Elango@Sun.COM } 112510187SKrishna.Elango@Sun.COM 112610187SKrishna.Elango@Sun.COM /* clear any pending CE errors */ 112710187SKrishna.Elango@Sun.COM if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) != 112810187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) 112910187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS, 113010187SKrishna.Elango@Sun.COM device_sts & (~PCIE_DEVSTS_CE_DETECTED)); 113110187SKrishna.Elango@Sun.COM 113210187SKrishna.Elango@Sun.COM /* Enable CE reporting */ 113310187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 113410187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, 113510187SKrishna.Elango@Sun.COM (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default); 113610187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl); 113710187SKrishna.Elango@Sun.COM 113810187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 113910187SKrishna.Elango@Sun.COM } 114010187SKrishna.Elango@Sun.COM 114110187SKrishna.Elango@Sun.COM /* ARGSUSED */ 114210187SKrishna.Elango@Sun.COM void 114310187SKrishna.Elango@Sun.COM pcie_disable_errors(dev_info_t *dip) 114410187SKrishna.Elango@Sun.COM { 114510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 114610187SKrishna.Elango@Sun.COM uint16_t device_ctl; 114710187SKrishna.Elango@Sun.COM uint32_t aer_reg; 114810187SKrishna.Elango@Sun.COM 114910187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 115010187SKrishna.Elango@Sun.COM return; 115110187SKrishna.Elango@Sun.COM 115210187SKrishna.Elango@Sun.COM /* 115310187SKrishna.Elango@Sun.COM * Disable PCI-Express Baseline Error Handling 115410187SKrishna.Elango@Sun.COM */ 115510187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 115610187SKrishna.Elango@Sun.COM device_ctl &= ~PCIE_DEVCTL_ERR_MASK; 115710187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl); 115810187SKrishna.Elango@Sun.COM 115910187SKrishna.Elango@Sun.COM /* 116010187SKrishna.Elango@Sun.COM * Disable PCI-Express Advanced Error Handling if Exists 116110187SKrishna.Elango@Sun.COM */ 116210187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 116310187SKrishna.Elango@Sun.COM goto root; 116410187SKrishna.Elango@Sun.COM 116510187SKrishna.Elango@Sun.COM /* Disable Uncorrectable errors */ 116610187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS); 116710187SKrishna.Elango@Sun.COM 116810187SKrishna.Elango@Sun.COM /* Disable Correctable errors */ 116910187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS); 117010187SKrishna.Elango@Sun.COM 117110187SKrishna.Elango@Sun.COM /* Disable ECRC generation and checking */ 117210187SKrishna.Elango@Sun.COM if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) != 117310187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 117410187SKrishna.Elango@Sun.COM aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA | 117510187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_CHECK_ENA); 117610187SKrishna.Elango@Sun.COM 117710187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg); 117810187SKrishna.Elango@Sun.COM } 117910187SKrishna.Elango@Sun.COM /* 118010187SKrishna.Elango@Sun.COM * Disable Secondary Uncorrectable errors if this is a bridge 118110187SKrishna.Elango@Sun.COM */ 118210187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) 118310187SKrishna.Elango@Sun.COM goto root; 118410187SKrishna.Elango@Sun.COM 118510187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS); 118610187SKrishna.Elango@Sun.COM 118710187SKrishna.Elango@Sun.COM root: 118810187SKrishna.Elango@Sun.COM /* 118910187SKrishna.Elango@Sun.COM * disable Root Control this is a Root device 119010187SKrishna.Elango@Sun.COM */ 119110187SKrishna.Elango@Sun.COM if (!PCIE_IS_ROOT(bus_p)) 119210187SKrishna.Elango@Sun.COM return; 119310187SKrishna.Elango@Sun.COM 119410187SKrishna.Elango@Sun.COM if (!pcie_serr_disable_flag) { 119510187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL); 119610187SKrishna.Elango@Sun.COM device_ctl &= ~PCIE_ROOT_SYS_ERR; 119710187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl); 119810187SKrishna.Elango@Sun.COM } 119910187SKrishna.Elango@Sun.COM 120010187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 120110187SKrishna.Elango@Sun.COM return; 120210187SKrishna.Elango@Sun.COM 120310187SKrishna.Elango@Sun.COM if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) != 120410187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 120510187SKrishna.Elango@Sun.COM device_ctl &= ~pcie_root_error_cmd_default; 120610187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl); 120710187SKrishna.Elango@Sun.COM } 120810187SKrishna.Elango@Sun.COM } 120910187SKrishna.Elango@Sun.COM 121010187SKrishna.Elango@Sun.COM /* 121110187SKrishna.Elango@Sun.COM * Extract bdf from "reg" property. 121210187SKrishna.Elango@Sun.COM */ 121310187SKrishna.Elango@Sun.COM int 121410187SKrishna.Elango@Sun.COM pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf) 121510187SKrishna.Elango@Sun.COM { 121610187SKrishna.Elango@Sun.COM pci_regspec_t *regspec; 121710187SKrishna.Elango@Sun.COM int reglen; 121810187SKrishna.Elango@Sun.COM 121910187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 122010187SKrishna.Elango@Sun.COM "reg", (int **)®spec, (uint_t *)®len) != DDI_SUCCESS) 122110187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 122210187SKrishna.Elango@Sun.COM 122310187SKrishna.Elango@Sun.COM if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) { 122410187SKrishna.Elango@Sun.COM ddi_prop_free(regspec); 122510187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 122610187SKrishna.Elango@Sun.COM } 122710187SKrishna.Elango@Sun.COM 122810187SKrishna.Elango@Sun.COM /* Get phys_hi from first element. All have same bdf. */ 122910187SKrishna.Elango@Sun.COM *bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8; 123010187SKrishna.Elango@Sun.COM 123110187SKrishna.Elango@Sun.COM ddi_prop_free(regspec); 123210187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 123310187SKrishna.Elango@Sun.COM } 123410187SKrishna.Elango@Sun.COM 123510187SKrishna.Elango@Sun.COM dev_info_t * 123610187SKrishna.Elango@Sun.COM pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 123710187SKrishna.Elango@Sun.COM { 123810187SKrishna.Elango@Sun.COM dev_info_t *cdip = rdip; 123910187SKrishna.Elango@Sun.COM 124010187SKrishna.Elango@Sun.COM for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 124110187SKrishna.Elango@Sun.COM ; 124210187SKrishna.Elango@Sun.COM 124310187SKrishna.Elango@Sun.COM return (cdip); 124410187SKrishna.Elango@Sun.COM } 124510187SKrishna.Elango@Sun.COM 124610187SKrishna.Elango@Sun.COM uint32_t 124710187SKrishna.Elango@Sun.COM pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip) 124810187SKrishna.Elango@Sun.COM { 124910187SKrishna.Elango@Sun.COM dev_info_t *cdip; 125010187SKrishna.Elango@Sun.COM 125110187SKrishna.Elango@Sun.COM /* 125210187SKrishna.Elango@Sun.COM * As part of the probing, the PCI fcode interpreter may setup a DMA 125310187SKrishna.Elango@Sun.COM * request if a given card has a fcode on it using dip and rdip of the 1254*10923SEvan.Yan@Sun.COM * hotplug connector i.e, dip and rdip of px/pcieb driver. In this 125510187SKrishna.Elango@Sun.COM * case, return a invalid value for the bdf since we cannot get to the 125610187SKrishna.Elango@Sun.COM * bdf value of the actual device which will be initiating this DMA. 125710187SKrishna.Elango@Sun.COM */ 125810187SKrishna.Elango@Sun.COM if (rdip == dip) 125910187SKrishna.Elango@Sun.COM return (PCIE_INVALID_BDF); 126010187SKrishna.Elango@Sun.COM 126110187SKrishna.Elango@Sun.COM cdip = pcie_get_my_childs_dip(dip, rdip); 126210187SKrishna.Elango@Sun.COM 126310187SKrishna.Elango@Sun.COM /* 126410187SKrishna.Elango@Sun.COM * For a given rdip, return the bdf value of dip's (px or pcieb) 126510187SKrishna.Elango@Sun.COM * immediate child or secondary bus-id if dip is a PCIe2PCI bridge. 126610187SKrishna.Elango@Sun.COM * 126710187SKrishna.Elango@Sun.COM * XXX - For now, return a invalid bdf value for all PCI and PCI-X 126810187SKrishna.Elango@Sun.COM * devices since this needs more work. 126910187SKrishna.Elango@Sun.COM */ 127010187SKrishna.Elango@Sun.COM return (PCI_GET_PCIE2PCI_SECBUS(cdip) ? 127110187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF : PCI_GET_BDF(cdip)); 127210187SKrishna.Elango@Sun.COM } 127310187SKrishna.Elango@Sun.COM 127410187SKrishna.Elango@Sun.COM uint32_t 127510187SKrishna.Elango@Sun.COM pcie_get_aer_uce_mask() { 127610187SKrishna.Elango@Sun.COM return (pcie_aer_uce_mask); 127710187SKrishna.Elango@Sun.COM } 127810187SKrishna.Elango@Sun.COM uint32_t 127910187SKrishna.Elango@Sun.COM pcie_get_aer_ce_mask() { 128010187SKrishna.Elango@Sun.COM return (pcie_aer_ce_mask); 128110187SKrishna.Elango@Sun.COM } 128210187SKrishna.Elango@Sun.COM uint32_t 128310187SKrishna.Elango@Sun.COM pcie_get_aer_suce_mask() { 128410187SKrishna.Elango@Sun.COM return (pcie_aer_suce_mask); 128510187SKrishna.Elango@Sun.COM } 128610187SKrishna.Elango@Sun.COM uint32_t 128710187SKrishna.Elango@Sun.COM pcie_get_serr_mask() { 128810187SKrishna.Elango@Sun.COM return (pcie_serr_disable_flag); 128910187SKrishna.Elango@Sun.COM } 129010187SKrishna.Elango@Sun.COM 129110187SKrishna.Elango@Sun.COM void 129210187SKrishna.Elango@Sun.COM pcie_set_aer_uce_mask(uint32_t mask) { 129310187SKrishna.Elango@Sun.COM pcie_aer_uce_mask = mask; 129410187SKrishna.Elango@Sun.COM if (mask & PCIE_AER_UCE_UR) 129510187SKrishna.Elango@Sun.COM pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN; 129610187SKrishna.Elango@Sun.COM else 129710187SKrishna.Elango@Sun.COM pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN; 129810187SKrishna.Elango@Sun.COM 129910187SKrishna.Elango@Sun.COM if (mask & PCIE_AER_UCE_ECRC) 130010187SKrishna.Elango@Sun.COM pcie_ecrc_value = 0; 130110187SKrishna.Elango@Sun.COM } 130210187SKrishna.Elango@Sun.COM 130310187SKrishna.Elango@Sun.COM void 130410187SKrishna.Elango@Sun.COM pcie_set_aer_ce_mask(uint32_t mask) { 130510187SKrishna.Elango@Sun.COM pcie_aer_ce_mask = mask; 130610187SKrishna.Elango@Sun.COM } 130710187SKrishna.Elango@Sun.COM void 130810187SKrishna.Elango@Sun.COM pcie_set_aer_suce_mask(uint32_t mask) { 130910187SKrishna.Elango@Sun.COM pcie_aer_suce_mask = mask; 131010187SKrishna.Elango@Sun.COM } 131110187SKrishna.Elango@Sun.COM void 131210187SKrishna.Elango@Sun.COM pcie_set_serr_mask(uint32_t mask) { 131310187SKrishna.Elango@Sun.COM pcie_serr_disable_flag = mask; 131410187SKrishna.Elango@Sun.COM } 131510187SKrishna.Elango@Sun.COM 131610187SKrishna.Elango@Sun.COM /* 131710187SKrishna.Elango@Sun.COM * Is the rdip a child of dip. Used for checking certain CTLOPS from bubbling 131810187SKrishna.Elango@Sun.COM * up erronously. Ex. ISA ctlops to a PCI-PCI Bridge. 131910187SKrishna.Elango@Sun.COM */ 132010187SKrishna.Elango@Sun.COM boolean_t 132110187SKrishna.Elango@Sun.COM pcie_is_child(dev_info_t *dip, dev_info_t *rdip) 132210187SKrishna.Elango@Sun.COM { 132310187SKrishna.Elango@Sun.COM dev_info_t *cdip = ddi_get_child(dip); 132410187SKrishna.Elango@Sun.COM for (; cdip; cdip = ddi_get_next_sibling(cdip)) 132510187SKrishna.Elango@Sun.COM if (cdip == rdip) 132610187SKrishna.Elango@Sun.COM break; 132710187SKrishna.Elango@Sun.COM return (cdip != NULL); 132810187SKrishna.Elango@Sun.COM } 132910187SKrishna.Elango@Sun.COM 133010187SKrishna.Elango@Sun.COM boolean_t 133110187SKrishna.Elango@Sun.COM pcie_is_link_disabled(dev_info_t *dip) 133210187SKrishna.Elango@Sun.COM { 133310187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 133410187SKrishna.Elango@Sun.COM 133510187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 133610187SKrishna.Elango@Sun.COM if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) & 133710187SKrishna.Elango@Sun.COM PCIE_LINKCTL_LINK_DISABLE) 133810187SKrishna.Elango@Sun.COM return (B_TRUE); 133910187SKrishna.Elango@Sun.COM } 134010187SKrishna.Elango@Sun.COM return (B_FALSE); 134110187SKrishna.Elango@Sun.COM } 134210187SKrishna.Elango@Sun.COM 134310187SKrishna.Elango@Sun.COM /* 134410187SKrishna.Elango@Sun.COM * Initialize the MPS for a root port. 134510187SKrishna.Elango@Sun.COM * 134610187SKrishna.Elango@Sun.COM * dip - dip of root port device. 134710187SKrishna.Elango@Sun.COM */ 134810187SKrishna.Elango@Sun.COM void 134910187SKrishna.Elango@Sun.COM pcie_init_root_port_mps(dev_info_t *dip) 135010187SKrishna.Elango@Sun.COM { 135110187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 135210187SKrishna.Elango@Sun.COM int rp_cap, max_supported = pcie_max_mps; 135310187SKrishna.Elango@Sun.COM 135410187SKrishna.Elango@Sun.COM (void) pcie_get_fabric_mps(ddi_get_parent(dip), 135510187SKrishna.Elango@Sun.COM ddi_get_child(dip), &max_supported); 135610187SKrishna.Elango@Sun.COM 135710187SKrishna.Elango@Sun.COM rp_cap = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL, 135810187SKrishna.Elango@Sun.COM bus_p->bus_pcie_off, PCIE_DEVCAP) & 135910187SKrishna.Elango@Sun.COM PCIE_DEVCAP_MAX_PAYLOAD_MASK; 136010187SKrishna.Elango@Sun.COM 136110187SKrishna.Elango@Sun.COM if (rp_cap < max_supported) 136210187SKrishna.Elango@Sun.COM max_supported = rp_cap; 136310187SKrishna.Elango@Sun.COM 136410187SKrishna.Elango@Sun.COM bus_p->bus_mps = max_supported; 136510187SKrishna.Elango@Sun.COM (void) pcie_initchild_mps(dip); 136610187SKrishna.Elango@Sun.COM } 136710187SKrishna.Elango@Sun.COM 136810187SKrishna.Elango@Sun.COM /* 136910187SKrishna.Elango@Sun.COM * Initialize the Maximum Payload Size of a device. 137010187SKrishna.Elango@Sun.COM * 137110187SKrishna.Elango@Sun.COM * cdip - dip of device. 137210187SKrishna.Elango@Sun.COM * 137310187SKrishna.Elango@Sun.COM * returns - DDI_SUCCESS or DDI_FAILURE 137410187SKrishna.Elango@Sun.COM */ 137510187SKrishna.Elango@Sun.COM int 137610187SKrishna.Elango@Sun.COM pcie_initchild_mps(dev_info_t *cdip) 137710187SKrishna.Elango@Sun.COM { 137810187SKrishna.Elango@Sun.COM int max_payload_size; 137910187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 138010187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(cdip); 1381*10923SEvan.Yan@Sun.COM uint8_t dev_type; 138210187SKrishna.Elango@Sun.COM 138310187SKrishna.Elango@Sun.COM bus_p = PCIE_DIP2BUS(cdip); 138410187SKrishna.Elango@Sun.COM if (bus_p == NULL) { 138510187SKrishna.Elango@Sun.COM PCIE_DBG("%s: BUS not found.\n", 138610187SKrishna.Elango@Sun.COM ddi_driver_name(cdip)); 138710187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 138810187SKrishna.Elango@Sun.COM } 138910187SKrishna.Elango@Sun.COM 1390*10923SEvan.Yan@Sun.COM dev_type = bus_p->bus_dev_type; 1391*10923SEvan.Yan@Sun.COM 1392*10923SEvan.Yan@Sun.COM /* 1393*10923SEvan.Yan@Sun.COM * For ARI Devices, only function zero's MPS needs to be set. 1394*10923SEvan.Yan@Sun.COM */ 1395*10923SEvan.Yan@Sun.COM if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) && 1396*10923SEvan.Yan@Sun.COM (pcie_ari_is_enabled(pdip) == PCIE_ARI_FORW_ENABLED)) { 1397*10923SEvan.Yan@Sun.COM pcie_req_id_t child_bdf; 1398*10923SEvan.Yan@Sun.COM 1399*10923SEvan.Yan@Sun.COM if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE) 1400*10923SEvan.Yan@Sun.COM return (DDI_FAILURE); 1401*10923SEvan.Yan@Sun.COM if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) != 0) 1402*10923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 1403*10923SEvan.Yan@Sun.COM } 1404*10923SEvan.Yan@Sun.COM 140510187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) { 140610187SKrishna.Elango@Sun.COM /* 140710187SKrishna.Elango@Sun.COM * If this device is a root port, then the mps scan 140810187SKrishna.Elango@Sun.COM * saved the mps in the root ports bus_p. 140910187SKrishna.Elango@Sun.COM */ 141010187SKrishna.Elango@Sun.COM max_payload_size = bus_p->bus_mps; 141110187SKrishna.Elango@Sun.COM } else { 141210187SKrishna.Elango@Sun.COM /* 141310187SKrishna.Elango@Sun.COM * If the device is not a root port, then the mps of 141410187SKrishna.Elango@Sun.COM * its parent should be used. 141510187SKrishna.Elango@Sun.COM */ 141610187SKrishna.Elango@Sun.COM pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip); 141710187SKrishna.Elango@Sun.COM max_payload_size = parent_bus_p->bus_mps; 141810187SKrishna.Elango@Sun.COM } 141910187SKrishna.Elango@Sun.COM 142010187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p) && (max_payload_size >= 0)) { 142110187SKrishna.Elango@Sun.COM pcie_bus_t *rootp_bus_p = PCIE_DIP2BUS(bus_p->bus_rp_dip); 142210187SKrishna.Elango@Sun.COM uint16_t mask, dev_ctrl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL), 142310187SKrishna.Elango@Sun.COM mps = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) & 142410187SKrishna.Elango@Sun.COM PCIE_DEVCAP_MAX_PAYLOAD_MASK; 142510187SKrishna.Elango@Sun.COM 142610187SKrishna.Elango@Sun.COM mps = MIN(mps, (uint16_t)max_payload_size); 142710187SKrishna.Elango@Sun.COM 142810187SKrishna.Elango@Sun.COM /* 142910187SKrishna.Elango@Sun.COM * If the MPS to be set is less than the root ports 143010187SKrishna.Elango@Sun.COM * MPS, then MRRS will have to be set the same as MPS. 143110187SKrishna.Elango@Sun.COM */ 143210187SKrishna.Elango@Sun.COM mask = ((mps < rootp_bus_p->bus_mps) ? 143310187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_READ_REQ_MASK : 0) | 143410187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK; 143510187SKrishna.Elango@Sun.COM 143610187SKrishna.Elango@Sun.COM dev_ctrl &= ~mask; 143710187SKrishna.Elango@Sun.COM mask = ((mps < rootp_bus_p->bus_mps) 143810187SKrishna.Elango@Sun.COM ? mps << PCIE_DEVCTL_MAX_READ_REQ_SHIFT : 0) 143910187SKrishna.Elango@Sun.COM | (mps << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT); 144010187SKrishna.Elango@Sun.COM 144110187SKrishna.Elango@Sun.COM dev_ctrl |= mask; 144210187SKrishna.Elango@Sun.COM 144310187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl); 144410187SKrishna.Elango@Sun.COM 144510187SKrishna.Elango@Sun.COM bus_p->bus_mps = mps; 144610187SKrishna.Elango@Sun.COM } 1447*10923SEvan.Yan@Sun.COM 144810187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 144910187SKrishna.Elango@Sun.COM } 145010187SKrishna.Elango@Sun.COM 145110187SKrishna.Elango@Sun.COM /* 145210187SKrishna.Elango@Sun.COM * Scans a device tree/branch for a maximum payload size capabilities. 145310187SKrishna.Elango@Sun.COM * 145410187SKrishna.Elango@Sun.COM * rc_dip - dip of Root Complex. 145510187SKrishna.Elango@Sun.COM * dip - dip of device where scan will begin. 145610187SKrishna.Elango@Sun.COM * max_supported (IN) - maximum allowable MPS. 145710187SKrishna.Elango@Sun.COM * max_supported (OUT) - maximum payload size capability of fabric. 145810187SKrishna.Elango@Sun.COM */ 145910187SKrishna.Elango@Sun.COM void 146010187SKrishna.Elango@Sun.COM pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported) 146110187SKrishna.Elango@Sun.COM { 146210187SKrishna.Elango@Sun.COM if (dip == NULL) 146310187SKrishna.Elango@Sun.COM return; 146410187SKrishna.Elango@Sun.COM 146510187SKrishna.Elango@Sun.COM /* 146610187SKrishna.Elango@Sun.COM * Perform a fabric scan to obtain Maximum Payload Capabilities 146710187SKrishna.Elango@Sun.COM */ 146810187SKrishna.Elango@Sun.COM (void) pcie_scan_mps(rc_dip, dip, max_supported); 146910187SKrishna.Elango@Sun.COM 147010187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: Highest Common MPS= %x\n", max_supported); 147110187SKrishna.Elango@Sun.COM } 147210187SKrishna.Elango@Sun.COM 147310187SKrishna.Elango@Sun.COM /* 147410187SKrishna.Elango@Sun.COM * Scans fabric and determines Maximum Payload Size based on 147510187SKrishna.Elango@Sun.COM * highest common denominator alogorithm 147610187SKrishna.Elango@Sun.COM */ 147710187SKrishna.Elango@Sun.COM static void 147810187SKrishna.Elango@Sun.COM pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported) 147910187SKrishna.Elango@Sun.COM { 148010187SKrishna.Elango@Sun.COM int circular_count; 148110187SKrishna.Elango@Sun.COM pcie_max_supported_t max_pay_load_supported; 148210187SKrishna.Elango@Sun.COM 148310187SKrishna.Elango@Sun.COM max_pay_load_supported.dip = rc_dip; 148410187SKrishna.Elango@Sun.COM max_pay_load_supported.highest_common_mps = *max_supported; 148510187SKrishna.Elango@Sun.COM 148610187SKrishna.Elango@Sun.COM ndi_devi_enter(ddi_get_parent(dip), &circular_count); 148710187SKrishna.Elango@Sun.COM ddi_walk_devs(dip, pcie_get_max_supported, 148810187SKrishna.Elango@Sun.COM (void *)&max_pay_load_supported); 148910187SKrishna.Elango@Sun.COM ndi_devi_exit(ddi_get_parent(dip), circular_count); 1490*10923SEvan.Yan@Sun.COM 149110187SKrishna.Elango@Sun.COM *max_supported = max_pay_load_supported.highest_common_mps; 149210187SKrishna.Elango@Sun.COM } 149310187SKrishna.Elango@Sun.COM 149410187SKrishna.Elango@Sun.COM /* 149510187SKrishna.Elango@Sun.COM * Called as part of the Maximum Payload Size scan. 149610187SKrishna.Elango@Sun.COM */ 149710187SKrishna.Elango@Sun.COM static int 149810187SKrishna.Elango@Sun.COM pcie_get_max_supported(dev_info_t *dip, void *arg) 149910187SKrishna.Elango@Sun.COM { 150010187SKrishna.Elango@Sun.COM uint32_t max_supported; 150110187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 150210187SKrishna.Elango@Sun.COM pcie_max_supported_t *current = (pcie_max_supported_t *)arg; 150310187SKrishna.Elango@Sun.COM pci_regspec_t *reg; 150410187SKrishna.Elango@Sun.COM int rlen; 150510187SKrishna.Elango@Sun.COM caddr_t virt; 150610187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle; 150710187SKrishna.Elango@Sun.COM 150810187SKrishna.Elango@Sun.COM if (ddi_get_child(current->dip) == NULL) { 150910187SKrishna.Elango@Sun.COM goto fail1; 151010187SKrishna.Elango@Sun.COM } 151110187SKrishna.Elango@Sun.COM 151210187SKrishna.Elango@Sun.COM if (pcie_dev(dip) == DDI_FAILURE) { 151310187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: " 151410187SKrishna.Elango@Sun.COM "Not a PCIe dev\n", ddi_driver_name(dip)); 151510187SKrishna.Elango@Sun.COM goto fail1; 151610187SKrishna.Elango@Sun.COM } 151710187SKrishna.Elango@Sun.COM 151810187SKrishna.Elango@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 151910187SKrishna.Elango@Sun.COM (caddr_t)®, &rlen) != DDI_PROP_SUCCESS) { 152010187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: " 152110187SKrishna.Elango@Sun.COM "Can not read reg\n", ddi_driver_name(dip)); 152210187SKrishna.Elango@Sun.COM goto fail1; 152310187SKrishna.Elango@Sun.COM } 152410187SKrishna.Elango@Sun.COM 152510187SKrishna.Elango@Sun.COM if (pcie_map_phys(ddi_get_child(current->dip), reg, &virt, 152610187SKrishna.Elango@Sun.COM &config_handle) != DDI_SUCCESS) { 152710187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: pcie_map_phys " 152810187SKrishna.Elango@Sun.COM "failed\n", ddi_driver_name(dip)); 152910187SKrishna.Elango@Sun.COM goto fail2; 153010187SKrishna.Elango@Sun.COM } 153110187SKrishna.Elango@Sun.COM 153210187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) == 153310187SKrishna.Elango@Sun.COM DDI_FAILURE) { 153410187SKrishna.Elango@Sun.COM goto fail3; 153510187SKrishna.Elango@Sun.COM } 153610187SKrishna.Elango@Sun.COM 153710187SKrishna.Elango@Sun.COM max_supported = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 153810187SKrishna.Elango@Sun.COM PCIE_DEVCAP) & PCIE_DEVCAP_MAX_PAYLOAD_MASK; 153910187SKrishna.Elango@Sun.COM 154010187SKrishna.Elango@Sun.COM PCIE_DBG("PCIE MPS: %s: MPS Capabilities %x\n", ddi_driver_name(dip), 154110187SKrishna.Elango@Sun.COM max_supported); 154210187SKrishna.Elango@Sun.COM 154310187SKrishna.Elango@Sun.COM if (max_supported < current->highest_common_mps) 154410187SKrishna.Elango@Sun.COM current->highest_common_mps = max_supported; 154510187SKrishna.Elango@Sun.COM 154610187SKrishna.Elango@Sun.COM fail3: 154710187SKrishna.Elango@Sun.COM pcie_unmap_phys(&config_handle, reg); 154810187SKrishna.Elango@Sun.COM fail2: 154910187SKrishna.Elango@Sun.COM kmem_free(reg, rlen); 155010187SKrishna.Elango@Sun.COM fail1: 155110187SKrishna.Elango@Sun.COM return (DDI_WALK_CONTINUE); 155210187SKrishna.Elango@Sun.COM } 155310187SKrishna.Elango@Sun.COM 155410187SKrishna.Elango@Sun.COM /* 155510187SKrishna.Elango@Sun.COM * Determines if there are any root ports attached to a root complex. 155610187SKrishna.Elango@Sun.COM * 155710187SKrishna.Elango@Sun.COM * dip - dip of root complex 155810187SKrishna.Elango@Sun.COM * 155910187SKrishna.Elango@Sun.COM * Returns - DDI_SUCCESS if there is at least one root port otherwise 1560*10923SEvan.Yan@Sun.COM * DDI_FAILURE. 156110187SKrishna.Elango@Sun.COM */ 156210187SKrishna.Elango@Sun.COM int 156310187SKrishna.Elango@Sun.COM pcie_root_port(dev_info_t *dip) 156410187SKrishna.Elango@Sun.COM { 156510187SKrishna.Elango@Sun.COM int port_type; 156610187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 156710187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle; 156810187SKrishna.Elango@Sun.COM dev_info_t *cdip = ddi_get_child(dip); 156910187SKrishna.Elango@Sun.COM 157010187SKrishna.Elango@Sun.COM /* 157110187SKrishna.Elango@Sun.COM * Determine if any of the children of the passed in dip 157210187SKrishna.Elango@Sun.COM * are root ports. 157310187SKrishna.Elango@Sun.COM */ 157410187SKrishna.Elango@Sun.COM for (; cdip; cdip = ddi_get_next_sibling(cdip)) { 157510187SKrishna.Elango@Sun.COM 157610187SKrishna.Elango@Sun.COM if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS) 157710187SKrishna.Elango@Sun.COM continue; 157810187SKrishna.Elango@Sun.COM 157910187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, 158010187SKrishna.Elango@Sun.COM &cap_ptr)) == DDI_FAILURE) { 158110187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle); 158210187SKrishna.Elango@Sun.COM continue; 158310187SKrishna.Elango@Sun.COM } 158410187SKrishna.Elango@Sun.COM 158510187SKrishna.Elango@Sun.COM port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 158610187SKrishna.Elango@Sun.COM PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 158710187SKrishna.Elango@Sun.COM 158810187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle); 158910187SKrishna.Elango@Sun.COM 159010187SKrishna.Elango@Sun.COM if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) 159110187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 159210187SKrishna.Elango@Sun.COM } 159310187SKrishna.Elango@Sun.COM 159410187SKrishna.Elango@Sun.COM /* No root ports were found */ 159510187SKrishna.Elango@Sun.COM 159610187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 159710187SKrishna.Elango@Sun.COM } 159810187SKrishna.Elango@Sun.COM 159910187SKrishna.Elango@Sun.COM /* 160010187SKrishna.Elango@Sun.COM * Function that determines if a device a PCIe device. 160110187SKrishna.Elango@Sun.COM * 160210187SKrishna.Elango@Sun.COM * dip - dip of device. 160310187SKrishna.Elango@Sun.COM * 160410187SKrishna.Elango@Sun.COM * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE. 160510187SKrishna.Elango@Sun.COM */ 160610187SKrishna.Elango@Sun.COM int 160710187SKrishna.Elango@Sun.COM pcie_dev(dev_info_t *dip) 160810187SKrishna.Elango@Sun.COM { 160910187SKrishna.Elango@Sun.COM /* get parent device's device_type property */ 161010187SKrishna.Elango@Sun.COM char *device_type; 161110187SKrishna.Elango@Sun.COM int rc = DDI_FAILURE; 161210187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(dip); 161310187SKrishna.Elango@Sun.COM 161410187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 161510187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "device_type", &device_type) 161610187SKrishna.Elango@Sun.COM != DDI_PROP_SUCCESS) { 161710187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 161810187SKrishna.Elango@Sun.COM } 161910187SKrishna.Elango@Sun.COM 162010187SKrishna.Elango@Sun.COM if (strcmp(device_type, "pciex") == 0) 162110187SKrishna.Elango@Sun.COM rc = DDI_SUCCESS; 162210187SKrishna.Elango@Sun.COM else 162310187SKrishna.Elango@Sun.COM rc = DDI_FAILURE; 162410187SKrishna.Elango@Sun.COM 162510187SKrishna.Elango@Sun.COM ddi_prop_free(device_type); 162610187SKrishna.Elango@Sun.COM return (rc); 162710187SKrishna.Elango@Sun.COM } 162810187SKrishna.Elango@Sun.COM 162910187SKrishna.Elango@Sun.COM /* 163010187SKrishna.Elango@Sun.COM * Function to map in a device's memory space. 163110187SKrishna.Elango@Sun.COM */ 163210187SKrishna.Elango@Sun.COM static int 163310187SKrishna.Elango@Sun.COM pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 163410187SKrishna.Elango@Sun.COM caddr_t *addrp, ddi_acc_handle_t *handlep) 163510187SKrishna.Elango@Sun.COM { 163610187SKrishna.Elango@Sun.COM ddi_map_req_t mr; 163710187SKrishna.Elango@Sun.COM ddi_acc_hdl_t *hp; 163810187SKrishna.Elango@Sun.COM int result; 163910187SKrishna.Elango@Sun.COM ddi_device_acc_attr_t attr; 164010187SKrishna.Elango@Sun.COM 164110187SKrishna.Elango@Sun.COM attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 164210187SKrishna.Elango@Sun.COM attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 164310187SKrishna.Elango@Sun.COM attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 164410187SKrishna.Elango@Sun.COM attr.devacc_attr_access = DDI_CAUTIOUS_ACC; 164510187SKrishna.Elango@Sun.COM 164610187SKrishna.Elango@Sun.COM *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 164710187SKrishna.Elango@Sun.COM hp = impl_acc_hdl_get(*handlep); 164810187SKrishna.Elango@Sun.COM hp->ah_vers = VERS_ACCHDL; 164910187SKrishna.Elango@Sun.COM hp->ah_dip = dip; 165010187SKrishna.Elango@Sun.COM hp->ah_rnumber = 0; 165110187SKrishna.Elango@Sun.COM hp->ah_offset = 0; 165210187SKrishna.Elango@Sun.COM hp->ah_len = 0; 165310187SKrishna.Elango@Sun.COM hp->ah_acc = attr; 165410187SKrishna.Elango@Sun.COM 165510187SKrishna.Elango@Sun.COM mr.map_op = DDI_MO_MAP_LOCKED; 165610187SKrishna.Elango@Sun.COM mr.map_type = DDI_MT_REGSPEC; 165710187SKrishna.Elango@Sun.COM mr.map_obj.rp = (struct regspec *)phys_spec; 165810187SKrishna.Elango@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE; 165910187SKrishna.Elango@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING; 166010187SKrishna.Elango@Sun.COM mr.map_handlep = hp; 166110187SKrishna.Elango@Sun.COM mr.map_vers = DDI_MAP_VERSION; 166210187SKrishna.Elango@Sun.COM 166310187SKrishna.Elango@Sun.COM result = ddi_map(dip, &mr, 0, 0, addrp); 166410187SKrishna.Elango@Sun.COM 166510187SKrishna.Elango@Sun.COM if (result != DDI_SUCCESS) { 166610187SKrishna.Elango@Sun.COM impl_acc_hdl_free(*handlep); 166710187SKrishna.Elango@Sun.COM *handlep = (ddi_acc_handle_t)NULL; 166810187SKrishna.Elango@Sun.COM } else { 166910187SKrishna.Elango@Sun.COM hp->ah_addr = *addrp; 167010187SKrishna.Elango@Sun.COM } 167110187SKrishna.Elango@Sun.COM 167210187SKrishna.Elango@Sun.COM return (result); 167310187SKrishna.Elango@Sun.COM } 167410187SKrishna.Elango@Sun.COM 167510187SKrishna.Elango@Sun.COM /* 167610187SKrishna.Elango@Sun.COM * Map out memory that was mapped in with pcie_map_phys(); 167710187SKrishna.Elango@Sun.COM */ 167810187SKrishna.Elango@Sun.COM static void 167910187SKrishna.Elango@Sun.COM pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph) 168010187SKrishna.Elango@Sun.COM { 168110187SKrishna.Elango@Sun.COM ddi_map_req_t mr; 168210187SKrishna.Elango@Sun.COM ddi_acc_hdl_t *hp; 168310187SKrishna.Elango@Sun.COM 168410187SKrishna.Elango@Sun.COM hp = impl_acc_hdl_get(*handlep); 168510187SKrishna.Elango@Sun.COM ASSERT(hp); 168610187SKrishna.Elango@Sun.COM 168710187SKrishna.Elango@Sun.COM mr.map_op = DDI_MO_UNMAP; 168810187SKrishna.Elango@Sun.COM mr.map_type = DDI_MT_REGSPEC; 168910187SKrishna.Elango@Sun.COM mr.map_obj.rp = (struct regspec *)ph; 169010187SKrishna.Elango@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE; 169110187SKrishna.Elango@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING; 169210187SKrishna.Elango@Sun.COM mr.map_handlep = hp; 169310187SKrishna.Elango@Sun.COM mr.map_vers = DDI_MAP_VERSION; 169410187SKrishna.Elango@Sun.COM 169510187SKrishna.Elango@Sun.COM (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 169610187SKrishna.Elango@Sun.COM hp->ah_len, &hp->ah_addr); 169710187SKrishna.Elango@Sun.COM 169810187SKrishna.Elango@Sun.COM impl_acc_hdl_free(*handlep); 169910187SKrishna.Elango@Sun.COM *handlep = (ddi_acc_handle_t)NULL; 170010187SKrishna.Elango@Sun.COM } 170110187SKrishna.Elango@Sun.COM 170210187SKrishna.Elango@Sun.COM void 170310187SKrishna.Elango@Sun.COM pcie_set_rber_fatal(dev_info_t *dip, boolean_t val) 170410187SKrishna.Elango@Sun.COM { 170510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 170610187SKrishna.Elango@Sun.COM bus_p->bus_pfd->pe_rber_fatal = val; 170710187SKrishna.Elango@Sun.COM } 170810187SKrishna.Elango@Sun.COM 170910187SKrishna.Elango@Sun.COM /* 171010187SKrishna.Elango@Sun.COM * Return parent Root Port's pe_rber_fatal value. 171110187SKrishna.Elango@Sun.COM */ 171210187SKrishna.Elango@Sun.COM boolean_t 171310187SKrishna.Elango@Sun.COM pcie_get_rber_fatal(dev_info_t *dip) 171410187SKrishna.Elango@Sun.COM { 171510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 171610187SKrishna.Elango@Sun.COM pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip); 171710187SKrishna.Elango@Sun.COM return (rp_bus_p->bus_pfd->pe_rber_fatal); 171810187SKrishna.Elango@Sun.COM } 171910187SKrishna.Elango@Sun.COM 1720*10923SEvan.Yan@Sun.COM int 1721*10923SEvan.Yan@Sun.COM pcie_ari_supported(dev_info_t *dip) 1722*10923SEvan.Yan@Sun.COM { 1723*10923SEvan.Yan@Sun.COM uint32_t devcap2; 1724*10923SEvan.Yan@Sun.COM uint16_t pciecap; 1725*10923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1726*10923SEvan.Yan@Sun.COM uint8_t dev_type; 1727*10923SEvan.Yan@Sun.COM 1728*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p\n", dip); 1729*10923SEvan.Yan@Sun.COM 1730*10923SEvan.Yan@Sun.COM if (bus_p == NULL) 1731*10923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 1732*10923SEvan.Yan@Sun.COM 1733*10923SEvan.Yan@Sun.COM dev_type = bus_p->bus_dev_type; 1734*10923SEvan.Yan@Sun.COM 1735*10923SEvan.Yan@Sun.COM if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) && 1736*10923SEvan.Yan@Sun.COM (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT)) 1737*10923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 1738*10923SEvan.Yan@Sun.COM 1739*10923SEvan.Yan@Sun.COM if (pcie_disable_ari) { 1740*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip); 1741*10923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 1742*10923SEvan.Yan@Sun.COM } 1743*10923SEvan.Yan@Sun.COM 1744*10923SEvan.Yan@Sun.COM pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP); 1745*10923SEvan.Yan@Sun.COM 1746*10923SEvan.Yan@Sun.COM if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) { 1747*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip); 1748*10923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 1749*10923SEvan.Yan@Sun.COM } 1750*10923SEvan.Yan@Sun.COM 1751*10923SEvan.Yan@Sun.COM devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2); 1752*10923SEvan.Yan@Sun.COM 1753*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n", 1754*10923SEvan.Yan@Sun.COM dip, devcap2); 1755*10923SEvan.Yan@Sun.COM 1756*10923SEvan.Yan@Sun.COM if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) { 1757*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: " 1758*10923SEvan.Yan@Sun.COM "dip=%p: ARI Forwarding is supported\n", dip); 1759*10923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_SUPPORTED); 1760*10923SEvan.Yan@Sun.COM } 1761*10923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 1762*10923SEvan.Yan@Sun.COM } 1763*10923SEvan.Yan@Sun.COM 1764*10923SEvan.Yan@Sun.COM int 1765*10923SEvan.Yan@Sun.COM pcie_ari_enable(dev_info_t *dip) 1766*10923SEvan.Yan@Sun.COM { 1767*10923SEvan.Yan@Sun.COM uint16_t devctl2; 1768*10923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1769*10923SEvan.Yan@Sun.COM 1770*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_enable: dip=%p\n", dip); 1771*10923SEvan.Yan@Sun.COM 1772*10923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 1773*10923SEvan.Yan@Sun.COM return (DDI_FAILURE); 1774*10923SEvan.Yan@Sun.COM 1775*10923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2); 1776*10923SEvan.Yan@Sun.COM devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN; 1777*10923SEvan.Yan@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2); 1778*10923SEvan.Yan@Sun.COM 1779*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n", 1780*10923SEvan.Yan@Sun.COM dip, devctl2); 1781*10923SEvan.Yan@Sun.COM 1782*10923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 1783*10923SEvan.Yan@Sun.COM } 1784*10923SEvan.Yan@Sun.COM 1785*10923SEvan.Yan@Sun.COM int 1786*10923SEvan.Yan@Sun.COM pcie_ari_disable(dev_info_t *dip) 1787*10923SEvan.Yan@Sun.COM { 1788*10923SEvan.Yan@Sun.COM uint16_t devctl2; 1789*10923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1790*10923SEvan.Yan@Sun.COM 1791*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_disable: dip=%p\n", dip); 1792*10923SEvan.Yan@Sun.COM 1793*10923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 1794*10923SEvan.Yan@Sun.COM return (DDI_FAILURE); 1795*10923SEvan.Yan@Sun.COM 1796*10923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2); 1797*10923SEvan.Yan@Sun.COM devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN; 1798*10923SEvan.Yan@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2); 1799*10923SEvan.Yan@Sun.COM 1800*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n", 1801*10923SEvan.Yan@Sun.COM dip, devctl2); 1802*10923SEvan.Yan@Sun.COM 1803*10923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 1804*10923SEvan.Yan@Sun.COM } 1805*10923SEvan.Yan@Sun.COM 1806*10923SEvan.Yan@Sun.COM int 1807*10923SEvan.Yan@Sun.COM pcie_ari_is_enabled(dev_info_t *dip) 1808*10923SEvan.Yan@Sun.COM { 1809*10923SEvan.Yan@Sun.COM uint16_t devctl2; 1810*10923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1811*10923SEvan.Yan@Sun.COM 1812*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip); 1813*10923SEvan.Yan@Sun.COM 1814*10923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 1815*10923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_DISABLED); 1816*10923SEvan.Yan@Sun.COM 1817*10923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2); 1818*10923SEvan.Yan@Sun.COM 1819*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n", 1820*10923SEvan.Yan@Sun.COM dip, devctl2); 1821*10923SEvan.Yan@Sun.COM 1822*10923SEvan.Yan@Sun.COM if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) { 1823*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: " 1824*10923SEvan.Yan@Sun.COM "dip=%p: ARI Forwarding is enabled\n", dip); 1825*10923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_ENABLED); 1826*10923SEvan.Yan@Sun.COM } 1827*10923SEvan.Yan@Sun.COM 1828*10923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_DISABLED); 1829*10923SEvan.Yan@Sun.COM } 1830*10923SEvan.Yan@Sun.COM 1831*10923SEvan.Yan@Sun.COM int 1832*10923SEvan.Yan@Sun.COM pcie_ari_device(dev_info_t *dip) 1833*10923SEvan.Yan@Sun.COM { 1834*10923SEvan.Yan@Sun.COM ddi_acc_handle_t handle; 1835*10923SEvan.Yan@Sun.COM uint16_t cap_ptr; 1836*10923SEvan.Yan@Sun.COM 1837*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_device: dip=%p\n", dip); 1838*10923SEvan.Yan@Sun.COM 1839*10923SEvan.Yan@Sun.COM /* 1840*10923SEvan.Yan@Sun.COM * XXX - This function may be called before the bus_p structure 1841*10923SEvan.Yan@Sun.COM * has been populated. This code can be changed to remove 1842*10923SEvan.Yan@Sun.COM * pci_config_setup()/pci_config_teardown() when the RFE 1843*10923SEvan.Yan@Sun.COM * to populate the bus_p structures early in boot is putback. 1844*10923SEvan.Yan@Sun.COM */ 1845*10923SEvan.Yan@Sun.COM 1846*10923SEvan.Yan@Sun.COM /* First make sure it is a PCIe device */ 1847*10923SEvan.Yan@Sun.COM 1848*10923SEvan.Yan@Sun.COM if (pci_config_setup(dip, &handle) != DDI_SUCCESS) 1849*10923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE); 1850*10923SEvan.Yan@Sun.COM 1851*10923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) 1852*10923SEvan.Yan@Sun.COM != DDI_SUCCESS) { 1853*10923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 1854*10923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE); 1855*10923SEvan.Yan@Sun.COM } 1856*10923SEvan.Yan@Sun.COM 1857*10923SEvan.Yan@Sun.COM /* Locate the ARI Capability */ 1858*10923SEvan.Yan@Sun.COM 1859*10923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), 1860*10923SEvan.Yan@Sun.COM &cap_ptr)) == DDI_FAILURE) { 1861*10923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 1862*10923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE); 1863*10923SEvan.Yan@Sun.COM } 1864*10923SEvan.Yan@Sun.COM 1865*10923SEvan.Yan@Sun.COM /* ARI Capability was found so it must be a ARI device */ 1866*10923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip); 1867*10923SEvan.Yan@Sun.COM 1868*10923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 1869*10923SEvan.Yan@Sun.COM return (PCIE_ARI_DEVICE); 1870*10923SEvan.Yan@Sun.COM } 1871*10923SEvan.Yan@Sun.COM 1872*10923SEvan.Yan@Sun.COM int 1873*10923SEvan.Yan@Sun.COM pcie_ari_get_next_function(dev_info_t *dip, int *func) 1874*10923SEvan.Yan@Sun.COM { 1875*10923SEvan.Yan@Sun.COM uint32_t val; 1876*10923SEvan.Yan@Sun.COM uint16_t cap_ptr, next_function; 1877*10923SEvan.Yan@Sun.COM ddi_acc_handle_t handle; 1878*10923SEvan.Yan@Sun.COM 1879*10923SEvan.Yan@Sun.COM /* 1880*10923SEvan.Yan@Sun.COM * XXX - This function may be called before the bus_p structure 1881*10923SEvan.Yan@Sun.COM * has been populated. This code can be changed to remove 1882*10923SEvan.Yan@Sun.COM * pci_config_setup()/pci_config_teardown() when the RFE 1883*10923SEvan.Yan@Sun.COM * to populate the bus_p structures early in boot is putback. 1884*10923SEvan.Yan@Sun.COM */ 1885*10923SEvan.Yan@Sun.COM 1886*10923SEvan.Yan@Sun.COM if (pci_config_setup(dip, &handle) != DDI_SUCCESS) 1887*10923SEvan.Yan@Sun.COM return (DDI_FAILURE); 1888*10923SEvan.Yan@Sun.COM 1889*10923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, 1890*10923SEvan.Yan@Sun.COM PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) { 1891*10923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 1892*10923SEvan.Yan@Sun.COM return (DDI_FAILURE); 1893*10923SEvan.Yan@Sun.COM } 1894*10923SEvan.Yan@Sun.COM 1895*10923SEvan.Yan@Sun.COM val = PCI_CAP_GET32(handle, NULL, cap_ptr, PCIE_ARI_CAP); 1896*10923SEvan.Yan@Sun.COM 1897*10923SEvan.Yan@Sun.COM next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) & 1898*10923SEvan.Yan@Sun.COM PCIE_ARI_CAP_NEXT_FUNC_MASK; 1899*10923SEvan.Yan@Sun.COM 1900*10923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 1901*10923SEvan.Yan@Sun.COM 1902*10923SEvan.Yan@Sun.COM *func = next_function; 1903*10923SEvan.Yan@Sun.COM 1904*10923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 1905*10923SEvan.Yan@Sun.COM } 1906*10923SEvan.Yan@Sun.COM 1907*10923SEvan.Yan@Sun.COM dev_info_t * 1908*10923SEvan.Yan@Sun.COM pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function) 1909*10923SEvan.Yan@Sun.COM { 1910*10923SEvan.Yan@Sun.COM pcie_req_id_t child_bdf; 1911*10923SEvan.Yan@Sun.COM dev_info_t *cdip; 1912*10923SEvan.Yan@Sun.COM 1913*10923SEvan.Yan@Sun.COM for (cdip = ddi_get_child(dip); cdip; 1914*10923SEvan.Yan@Sun.COM cdip = ddi_get_next_sibling(cdip)) { 1915*10923SEvan.Yan@Sun.COM 1916*10923SEvan.Yan@Sun.COM if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE) 1917*10923SEvan.Yan@Sun.COM return (NULL); 1918*10923SEvan.Yan@Sun.COM 1919*10923SEvan.Yan@Sun.COM if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function) 1920*10923SEvan.Yan@Sun.COM return (cdip); 1921*10923SEvan.Yan@Sun.COM } 1922*10923SEvan.Yan@Sun.COM return (NULL); 1923*10923SEvan.Yan@Sun.COM } 1924*10923SEvan.Yan@Sun.COM 192510187SKrishna.Elango@Sun.COM #ifdef DEBUG 192610187SKrishna.Elango@Sun.COM 192710187SKrishna.Elango@Sun.COM static void 192810187SKrishna.Elango@Sun.COM pcie_print_bus(pcie_bus_t *bus_p) 192910187SKrishna.Elango@Sun.COM { 193010187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip); 193110187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags); 193210187SKrishna.Elango@Sun.COM 193310187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf); 193410187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id); 193510187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id); 193610187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type); 193710187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type); 193810187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus); 193910187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off); 194010187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off); 194110187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off); 194210187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver); 194310187SKrishna.Elango@Sun.COM } 194410187SKrishna.Elango@Sun.COM 194510187SKrishna.Elango@Sun.COM /* 194610187SKrishna.Elango@Sun.COM * For debugging purposes set pcie_dbg_print != 0 to see printf messages 194710187SKrishna.Elango@Sun.COM * during interrupt. 194810187SKrishna.Elango@Sun.COM * 194910187SKrishna.Elango@Sun.COM * When a proper solution is in place this code will disappear. 195010187SKrishna.Elango@Sun.COM * Potential solutions are: 195110187SKrishna.Elango@Sun.COM * o circular buffers 195210187SKrishna.Elango@Sun.COM * o taskq to print at lower pil 195310187SKrishna.Elango@Sun.COM */ 195410187SKrishna.Elango@Sun.COM int pcie_dbg_print = 0; 195510187SKrishna.Elango@Sun.COM void 195610187SKrishna.Elango@Sun.COM pcie_dbg(char *fmt, ...) 195710187SKrishna.Elango@Sun.COM { 195810187SKrishna.Elango@Sun.COM va_list ap; 195910187SKrishna.Elango@Sun.COM 196010187SKrishna.Elango@Sun.COM if (!pcie_debug_flags) { 196110187SKrishna.Elango@Sun.COM return; 196210187SKrishna.Elango@Sun.COM } 196310187SKrishna.Elango@Sun.COM va_start(ap, fmt); 196410187SKrishna.Elango@Sun.COM if (servicing_interrupt()) { 196510187SKrishna.Elango@Sun.COM if (pcie_dbg_print) { 196610187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap); 196710187SKrishna.Elango@Sun.COM } 196810187SKrishna.Elango@Sun.COM } else { 196910187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap); 197010187SKrishna.Elango@Sun.COM } 197110187SKrishna.Elango@Sun.COM va_end(ap); 197210187SKrishna.Elango@Sun.COM } 197310187SKrishna.Elango@Sun.COM #endif /* DEBUG */ 197410187SKrishna.Elango@Sun.COM 197510187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64) 197610187SKrishna.Elango@Sun.COM static void 197710187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl, boolean_t *empty_io_range, 197810187SKrishna.Elango@Sun.COM boolean_t *empty_mem_range) 197910187SKrishna.Elango@Sun.COM { 198010187SKrishna.Elango@Sun.COM uint8_t class, subclass; 198110187SKrishna.Elango@Sun.COM uint_t val; 198210187SKrishna.Elango@Sun.COM 198310187SKrishna.Elango@Sun.COM class = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS); 198410187SKrishna.Elango@Sun.COM subclass = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS); 198510187SKrishna.Elango@Sun.COM 198610187SKrishna.Elango@Sun.COM if ((class == PCI_CLASS_BRIDGE) && (subclass == PCI_BRIDGE_PCI)) { 198710187SKrishna.Elango@Sun.COM val = (((uint_t)pci_config_get8(cfg_hdl, PCI_BCNF_IO_BASE_LOW) & 198810187SKrishna.Elango@Sun.COM PCI_BCNF_IO_MASK) << 8); 198910187SKrishna.Elango@Sun.COM /* 199010187SKrishna.Elango@Sun.COM * Assuming that a zero based io_range[0] implies an 199110187SKrishna.Elango@Sun.COM * invalid I/O range. Likewise for mem_range[0]. 199210187SKrishna.Elango@Sun.COM */ 199310187SKrishna.Elango@Sun.COM if (val == 0) 199410187SKrishna.Elango@Sun.COM *empty_io_range = B_TRUE; 199510187SKrishna.Elango@Sun.COM val = (((uint_t)pci_config_get16(cfg_hdl, PCI_BCNF_MEM_BASE) & 199610187SKrishna.Elango@Sun.COM PCI_BCNF_MEM_MASK) << 16); 199710187SKrishna.Elango@Sun.COM if (val == 0) 199810187SKrishna.Elango@Sun.COM *empty_mem_range = B_TRUE; 199910187SKrishna.Elango@Sun.COM } 200010187SKrishna.Elango@Sun.COM } 200110187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */ 2002