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 */ 2112059SAlan.Adamson@Sun.COM 2210187SKrishna.Elango@Sun.COM /* 23*12330SDaniel.Ice@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 2410187SKrishna.Elango@Sun.COM */ 2510187SKrishna.Elango@Sun.COM 2610187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h> 2710187SKrishna.Elango@Sun.COM #include <sys/types.h> 2810187SKrishna.Elango@Sun.COM #include <sys/kmem.h> 2910187SKrishna.Elango@Sun.COM #include <sys/modctl.h> 3010187SKrishna.Elango@Sun.COM #include <sys/ddi.h> 3110187SKrishna.Elango@Sun.COM #include <sys/sunddi.h> 3210187SKrishna.Elango@Sun.COM #include <sys/sunndi.h> 3310187SKrishna.Elango@Sun.COM #include <sys/fm/protocol.h> 3410187SKrishna.Elango@Sun.COM #include <sys/fm/util.h> 3510187SKrishna.Elango@Sun.COM #include <sys/promif.h> 3610187SKrishna.Elango@Sun.COM #include <sys/disp.h> 3710923SEvan.Yan@Sun.COM #include <sys/stat.h> 3810923SEvan.Yan@Sun.COM #include <sys/file.h> 3910187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h> 4010923SEvan.Yan@Sun.COM #include <sys/pci_impl.h> 4110187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h> 4210923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcie_hp.h> 4311445SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pciehpc.h> 4411445SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcishpc.h> 4510923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcicfg.h> 4611245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h> 4710187SKrishna.Elango@Sun.COM 4810923SEvan.Yan@Sun.COM /* Local functions prototypes */ 4910187SKrishna.Elango@Sun.COM static void pcie_init_pfd(dev_info_t *); 5010187SKrishna.Elango@Sun.COM static void pcie_fini_pfd(dev_info_t *); 5110187SKrishna.Elango@Sun.COM 5210187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64) 5310187SKrishna.Elango@Sun.COM static void pcie_check_io_mem_range(ddi_acc_handle_t, boolean_t *, boolean_t *); 5410187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */ 5510187SKrishna.Elango@Sun.COM 5610187SKrishna.Elango@Sun.COM #ifdef DEBUG 5710187SKrishna.Elango@Sun.COM uint_t pcie_debug_flags = 0; 5810187SKrishna.Elango@Sun.COM static void pcie_print_bus(pcie_bus_t *bus_p); 5910923SEvan.Yan@Sun.COM void pcie_dbg(char *fmt, ...); 6010187SKrishna.Elango@Sun.COM #endif /* DEBUG */ 6110187SKrishna.Elango@Sun.COM 6210187SKrishna.Elango@Sun.COM /* Variable to control default PCI-Express config settings */ 6310187SKrishna.Elango@Sun.COM ushort_t pcie_command_default = 6410187SKrishna.Elango@Sun.COM PCI_COMM_SERR_ENABLE | 6510187SKrishna.Elango@Sun.COM PCI_COMM_WAIT_CYC_ENAB | 6610187SKrishna.Elango@Sun.COM PCI_COMM_PARITY_DETECT | 6710187SKrishna.Elango@Sun.COM PCI_COMM_ME | 6810187SKrishna.Elango@Sun.COM PCI_COMM_MAE | 6910187SKrishna.Elango@Sun.COM PCI_COMM_IO; 7010187SKrishna.Elango@Sun.COM 7110187SKrishna.Elango@Sun.COM /* xxx_fw are bits that are controlled by FW and should not be modified */ 7210187SKrishna.Elango@Sun.COM ushort_t pcie_command_default_fw = 7310187SKrishna.Elango@Sun.COM PCI_COMM_SPEC_CYC | 7410187SKrishna.Elango@Sun.COM PCI_COMM_MEMWR_INVAL | 7510187SKrishna.Elango@Sun.COM PCI_COMM_PALETTE_SNOOP | 7610187SKrishna.Elango@Sun.COM PCI_COMM_WAIT_CYC_ENAB | 7710187SKrishna.Elango@Sun.COM 0xF800; /* Reserved Bits */ 7810187SKrishna.Elango@Sun.COM 7910187SKrishna.Elango@Sun.COM ushort_t pcie_bdg_command_default_fw = 8010187SKrishna.Elango@Sun.COM PCI_BCNF_BCNTRL_ISA_ENABLE | 8110187SKrishna.Elango@Sun.COM PCI_BCNF_BCNTRL_VGA_ENABLE | 8210187SKrishna.Elango@Sun.COM 0xF000; /* Reserved Bits */ 8310187SKrishna.Elango@Sun.COM 8410187SKrishna.Elango@Sun.COM /* PCI-Express Base error defaults */ 8510187SKrishna.Elango@Sun.COM ushort_t pcie_base_err_default = 8610187SKrishna.Elango@Sun.COM PCIE_DEVCTL_CE_REPORTING_EN | 8710187SKrishna.Elango@Sun.COM PCIE_DEVCTL_NFE_REPORTING_EN | 8810187SKrishna.Elango@Sun.COM PCIE_DEVCTL_FE_REPORTING_EN | 8910187SKrishna.Elango@Sun.COM PCIE_DEVCTL_UR_REPORTING_EN; 9010187SKrishna.Elango@Sun.COM 9110187SKrishna.Elango@Sun.COM /* PCI-Express Device Control Register */ 9210187SKrishna.Elango@Sun.COM uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN | 9310187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_READ_REQ_512; 9410187SKrishna.Elango@Sun.COM 9510187SKrishna.Elango@Sun.COM /* PCI-Express AER Root Control Register */ 9610187SKrishna.Elango@Sun.COM #define PCIE_ROOT_SYS_ERR (PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \ 9710187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \ 9810187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_FE_EN) 9910187SKrishna.Elango@Sun.COM 10010187SKrishna.Elango@Sun.COM ushort_t pcie_root_ctrl_default = 10110187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | 10210187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | 10310187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_FE_EN; 10410187SKrishna.Elango@Sun.COM 10510187SKrishna.Elango@Sun.COM /* PCI-Express Root Error Command Register */ 10610187SKrishna.Elango@Sun.COM ushort_t pcie_root_error_cmd_default = 10710187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_CE_REP_EN | 10810187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_NFE_REP_EN | 10910187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_FE_REP_EN; 11010187SKrishna.Elango@Sun.COM 11110187SKrishna.Elango@Sun.COM /* ECRC settings in the PCIe AER Control Register */ 11210187SKrishna.Elango@Sun.COM uint32_t pcie_ecrc_value = 11310187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_GEN_ENA | 11410187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_CHECK_ENA; 11510187SKrishna.Elango@Sun.COM 11610187SKrishna.Elango@Sun.COM /* 11710187SKrishna.Elango@Sun.COM * If a particular platform wants to disable certain errors such as UR/MA, 11810187SKrishna.Elango@Sun.COM * instead of using #defines have the platform's PCIe Root Complex driver set 11910187SKrishna.Elango@Sun.COM * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions. For 12010923SEvan.Yan@Sun.COM * x86 the closest thing to a PCIe root complex driver is NPE. For SPARC the 12110187SKrishna.Elango@Sun.COM * closest PCIe root complex driver is PX. 12210187SKrishna.Elango@Sun.COM * 12310187SKrishna.Elango@Sun.COM * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86 12410187SKrishna.Elango@Sun.COM * systems may want to disable SERR in general. For root ports, enabling SERR 12510187SKrishna.Elango@Sun.COM * causes NMIs which are not handled and results in a watchdog timeout error. 12610187SKrishna.Elango@Sun.COM */ 12710187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_mask = 0; /* AER UE Mask */ 12810187SKrishna.Elango@Sun.COM uint32_t pcie_aer_ce_mask = 0; /* AER CE Mask */ 12910187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_mask = 0; /* AER Secondary UE Mask */ 13010187SKrishna.Elango@Sun.COM uint32_t pcie_serr_disable_flag = 0; /* Disable SERR */ 13110187SKrishna.Elango@Sun.COM 13210187SKrishna.Elango@Sun.COM /* Default severities needed for eversholt. Error handling doesn't care */ 13310187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \ 13410187SKrishna.Elango@Sun.COM PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \ 13510187SKrishna.Elango@Sun.COM PCIE_AER_UCE_TRAINING; 13610187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \ 13710187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \ 13810187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_USC_MSG_DATA_ERR; 13910187SKrishna.Elango@Sun.COM 14010187SKrishna.Elango@Sun.COM int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5; 14110923SEvan.Yan@Sun.COM int pcie_disable_ari = 0; 14210187SKrishna.Elango@Sun.COM 14310187SKrishna.Elango@Sun.COM static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, 14410187SKrishna.Elango@Sun.COM int *max_supported); 14510187SKrishna.Elango@Sun.COM static int pcie_get_max_supported(dev_info_t *dip, void *arg); 14610187SKrishna.Elango@Sun.COM static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 14710187SKrishna.Elango@Sun.COM caddr_t *addrp, ddi_acc_handle_t *handlep); 14810923SEvan.Yan@Sun.COM static void pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph); 14910187SKrishna.Elango@Sun.COM 15011245SZhijun.Fu@Sun.COM dev_info_t *pcie_get_rc_dip(dev_info_t *dip); 15111245SZhijun.Fu@Sun.COM 15210187SKrishna.Elango@Sun.COM /* 15310187SKrishna.Elango@Sun.COM * modload support 15410187SKrishna.Elango@Sun.COM */ 15510187SKrishna.Elango@Sun.COM 15610187SKrishna.Elango@Sun.COM static struct modlmisc modlmisc = { 15710187SKrishna.Elango@Sun.COM &mod_miscops, /* Type of module */ 15810923SEvan.Yan@Sun.COM "PCI Express Framework Module" 15910187SKrishna.Elango@Sun.COM }; 16010187SKrishna.Elango@Sun.COM 16110187SKrishna.Elango@Sun.COM static struct modlinkage modlinkage = { 16210187SKrishna.Elango@Sun.COM MODREV_1, 16310187SKrishna.Elango@Sun.COM (void *)&modlmisc, 16410187SKrishna.Elango@Sun.COM NULL 16510187SKrishna.Elango@Sun.COM }; 16610187SKrishna.Elango@Sun.COM 16710187SKrishna.Elango@Sun.COM /* 16810187SKrishna.Elango@Sun.COM * Global Variables needed for a non-atomic version of ddi_fm_ereport_post. 16910187SKrishna.Elango@Sun.COM * Currently used to send the pci.fabric ereports whose payload depends on the 17010187SKrishna.Elango@Sun.COM * type of PCI device it is being sent for. 17110187SKrishna.Elango@Sun.COM */ 17210187SKrishna.Elango@Sun.COM char *pcie_nv_buf; 17310187SKrishna.Elango@Sun.COM nv_alloc_t *pcie_nvap; 17410187SKrishna.Elango@Sun.COM nvlist_t *pcie_nvl; 17510187SKrishna.Elango@Sun.COM 17610187SKrishna.Elango@Sun.COM int 17710187SKrishna.Elango@Sun.COM _init(void) 17810187SKrishna.Elango@Sun.COM { 17910187SKrishna.Elango@Sun.COM int rval; 18010187SKrishna.Elango@Sun.COM 18110187SKrishna.Elango@Sun.COM pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP); 18210187SKrishna.Elango@Sun.COM pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ); 18310187SKrishna.Elango@Sun.COM pcie_nvl = fm_nvlist_create(pcie_nvap); 18410187SKrishna.Elango@Sun.COM 18510187SKrishna.Elango@Sun.COM rval = mod_install(&modlinkage); 18610187SKrishna.Elango@Sun.COM return (rval); 18710187SKrishna.Elango@Sun.COM } 18810187SKrishna.Elango@Sun.COM 18910187SKrishna.Elango@Sun.COM int 19010187SKrishna.Elango@Sun.COM _fini() 19110187SKrishna.Elango@Sun.COM { 19210187SKrishna.Elango@Sun.COM int rval; 19310187SKrishna.Elango@Sun.COM 19410187SKrishna.Elango@Sun.COM fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN); 19510187SKrishna.Elango@Sun.COM fm_nva_xdestroy(pcie_nvap); 19610187SKrishna.Elango@Sun.COM kmem_free(pcie_nv_buf, ERPT_DATA_SZ); 19710187SKrishna.Elango@Sun.COM 19810187SKrishna.Elango@Sun.COM rval = mod_remove(&modlinkage); 19910187SKrishna.Elango@Sun.COM return (rval); 20010187SKrishna.Elango@Sun.COM } 20110187SKrishna.Elango@Sun.COM 20210187SKrishna.Elango@Sun.COM int 20310187SKrishna.Elango@Sun.COM _info(struct modinfo *modinfop) 20410187SKrishna.Elango@Sun.COM { 20510187SKrishna.Elango@Sun.COM return (mod_info(&modlinkage, modinfop)); 20610187SKrishna.Elango@Sun.COM } 20710187SKrishna.Elango@Sun.COM 20810923SEvan.Yan@Sun.COM /* ARGSUSED */ 20910923SEvan.Yan@Sun.COM int 21010923SEvan.Yan@Sun.COM pcie_init(dev_info_t *dip, caddr_t arg) 21110923SEvan.Yan@Sun.COM { 21210923SEvan.Yan@Sun.COM int ret = DDI_SUCCESS; 21310923SEvan.Yan@Sun.COM 21410923SEvan.Yan@Sun.COM /* 21510923SEvan.Yan@Sun.COM * Create a "devctl" minor node to support DEVCTL_DEVICE_* 21610923SEvan.Yan@Sun.COM * and DEVCTL_BUS_* ioctls to this bus. 21710923SEvan.Yan@Sun.COM */ 21810923SEvan.Yan@Sun.COM if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR, 21910923SEvan.Yan@Sun.COM PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR), 22010923SEvan.Yan@Sun.COM DDI_NT_NEXUS, 0)) != DDI_SUCCESS) { 22110923SEvan.Yan@Sun.COM PCIE_DBG("Failed to create devctl minor node for %s%d\n", 22210923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 22310923SEvan.Yan@Sun.COM 22410923SEvan.Yan@Sun.COM return (ret); 22510923SEvan.Yan@Sun.COM } 22610923SEvan.Yan@Sun.COM 22710923SEvan.Yan@Sun.COM if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) { 22810923SEvan.Yan@Sun.COM /* 22911366SColin.Zou@Sun.COM * On some x86 platforms, we observed unexpected hotplug 23011366SColin.Zou@Sun.COM * initialization failures in recent years. The known cause 23111366SColin.Zou@Sun.COM * is a hardware issue: while the problem PCI bridges have 23211366SColin.Zou@Sun.COM * the Hotplug Capable registers set, the machine actually 23311366SColin.Zou@Sun.COM * does not implement the expected ACPI object. 23411366SColin.Zou@Sun.COM * 23511366SColin.Zou@Sun.COM * We don't want to stop PCI driver attach and system boot 23611366SColin.Zou@Sun.COM * just because of this hotplug initialization failure. 23711366SColin.Zou@Sun.COM * Continue with a debug message printed. 23810923SEvan.Yan@Sun.COM */ 23911366SColin.Zou@Sun.COM PCIE_DBG("%s%d: Failed setting hotplug framework\n", 24010923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 24110923SEvan.Yan@Sun.COM 24210923SEvan.Yan@Sun.COM #if defined(__sparc) 24310923SEvan.Yan@Sun.COM ddi_remove_minor_node(dip, "devctl"); 24410923SEvan.Yan@Sun.COM 24510923SEvan.Yan@Sun.COM return (ret); 24610923SEvan.Yan@Sun.COM #endif /* defined(__sparc) */ 24710923SEvan.Yan@Sun.COM } 24810923SEvan.Yan@Sun.COM 24910923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 25010923SEvan.Yan@Sun.COM } 25110923SEvan.Yan@Sun.COM 25210923SEvan.Yan@Sun.COM /* ARGSUSED */ 25310923SEvan.Yan@Sun.COM int 25410923SEvan.Yan@Sun.COM pcie_uninit(dev_info_t *dip) 25510923SEvan.Yan@Sun.COM { 25610923SEvan.Yan@Sun.COM int ret = DDI_SUCCESS; 25710923SEvan.Yan@Sun.COM 25810923SEvan.Yan@Sun.COM if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED) 25910923SEvan.Yan@Sun.COM (void) pcie_ari_disable(dip); 26010923SEvan.Yan@Sun.COM 26110923SEvan.Yan@Sun.COM if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) { 26210923SEvan.Yan@Sun.COM PCIE_DBG("Failed to uninitialize hotplug for %s%d\n", 26310923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip)); 26410923SEvan.Yan@Sun.COM 26510923SEvan.Yan@Sun.COM return (ret); 26610923SEvan.Yan@Sun.COM } 26710923SEvan.Yan@Sun.COM 26810923SEvan.Yan@Sun.COM ddi_remove_minor_node(dip, "devctl"); 26910923SEvan.Yan@Sun.COM 27010923SEvan.Yan@Sun.COM return (ret); 27110923SEvan.Yan@Sun.COM } 27210923SEvan.Yan@Sun.COM 27311445SEvan.Yan@Sun.COM /* 27411445SEvan.Yan@Sun.COM * PCIe module interface for enabling hotplug interrupt. 27511445SEvan.Yan@Sun.COM * 27611445SEvan.Yan@Sun.COM * It should be called after pcie_init() is done and bus driver's 27711445SEvan.Yan@Sun.COM * interrupt handlers have being attached. 27811445SEvan.Yan@Sun.COM */ 27911445SEvan.Yan@Sun.COM int 28011445SEvan.Yan@Sun.COM pcie_hpintr_enable(dev_info_t *dip) 28111445SEvan.Yan@Sun.COM { 28211445SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 28311445SEvan.Yan@Sun.COM pcie_hp_ctrl_t *ctrl_p = PCIE_GET_HP_CTRL(dip); 28411445SEvan.Yan@Sun.COM 28511445SEvan.Yan@Sun.COM if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) { 28611445SEvan.Yan@Sun.COM (void) (ctrl_p->hc_ops.enable_hpc_intr)(ctrl_p); 28711445SEvan.Yan@Sun.COM } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) { 28811445SEvan.Yan@Sun.COM (void) pcishpc_enable_irqs(ctrl_p); 28911445SEvan.Yan@Sun.COM } 29011445SEvan.Yan@Sun.COM return (DDI_SUCCESS); 29111445SEvan.Yan@Sun.COM } 29211445SEvan.Yan@Sun.COM 29311445SEvan.Yan@Sun.COM /* 29411445SEvan.Yan@Sun.COM * PCIe module interface for disabling hotplug interrupt. 29511445SEvan.Yan@Sun.COM * 29611445SEvan.Yan@Sun.COM * It should be called before pcie_uninit() is called and bus driver's 29711445SEvan.Yan@Sun.COM * interrupt handlers is dettached. 29811445SEvan.Yan@Sun.COM */ 29911445SEvan.Yan@Sun.COM int 30011445SEvan.Yan@Sun.COM pcie_hpintr_disable(dev_info_t *dip) 30111445SEvan.Yan@Sun.COM { 30211445SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 30311445SEvan.Yan@Sun.COM pcie_hp_ctrl_t *ctrl_p = PCIE_GET_HP_CTRL(dip); 30411445SEvan.Yan@Sun.COM 30511445SEvan.Yan@Sun.COM if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) { 30611445SEvan.Yan@Sun.COM (void) (ctrl_p->hc_ops.disable_hpc_intr)(ctrl_p); 30711445SEvan.Yan@Sun.COM } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) { 30811445SEvan.Yan@Sun.COM (void) pcishpc_disable_irqs(ctrl_p); 30911445SEvan.Yan@Sun.COM } 31011445SEvan.Yan@Sun.COM return (DDI_SUCCESS); 31111445SEvan.Yan@Sun.COM } 31211445SEvan.Yan@Sun.COM 31310923SEvan.Yan@Sun.COM /* ARGSUSED */ 31410923SEvan.Yan@Sun.COM int 31510923SEvan.Yan@Sun.COM pcie_intr(dev_info_t *dip) 31610923SEvan.Yan@Sun.COM { 31710923SEvan.Yan@Sun.COM return (pcie_hp_intr(dip)); 31810923SEvan.Yan@Sun.COM } 31910923SEvan.Yan@Sun.COM 32010923SEvan.Yan@Sun.COM /* ARGSUSED */ 32110923SEvan.Yan@Sun.COM int 32210923SEvan.Yan@Sun.COM pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp) 32310923SEvan.Yan@Sun.COM { 32410923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 32510923SEvan.Yan@Sun.COM 32610923SEvan.Yan@Sun.COM /* 32710923SEvan.Yan@Sun.COM * Make sure the open is for the right file type. 32810923SEvan.Yan@Sun.COM */ 32910923SEvan.Yan@Sun.COM if (otyp != OTYP_CHR) 33010923SEvan.Yan@Sun.COM return (EINVAL); 33110923SEvan.Yan@Sun.COM 33210923SEvan.Yan@Sun.COM /* 33310923SEvan.Yan@Sun.COM * Handle the open by tracking the device state. 33410923SEvan.Yan@Sun.COM */ 33510923SEvan.Yan@Sun.COM if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) || 33610923SEvan.Yan@Sun.COM ((flags & FEXCL) && 33710923SEvan.Yan@Sun.COM (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) { 33810923SEvan.Yan@Sun.COM return (EBUSY); 33910923SEvan.Yan@Sun.COM } 34010923SEvan.Yan@Sun.COM 34110923SEvan.Yan@Sun.COM if (flags & FEXCL) 34210923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL; 34310923SEvan.Yan@Sun.COM else 34410923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN; 34510923SEvan.Yan@Sun.COM 34610923SEvan.Yan@Sun.COM return (0); 34710923SEvan.Yan@Sun.COM } 34810923SEvan.Yan@Sun.COM 34910923SEvan.Yan@Sun.COM /* ARGSUSED */ 35010923SEvan.Yan@Sun.COM int 35110923SEvan.Yan@Sun.COM pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp) 35210923SEvan.Yan@Sun.COM { 35310923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 35410923SEvan.Yan@Sun.COM 35510923SEvan.Yan@Sun.COM if (otyp != OTYP_CHR) 35610923SEvan.Yan@Sun.COM return (EINVAL); 35710923SEvan.Yan@Sun.COM 35810923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED; 35910923SEvan.Yan@Sun.COM 36010923SEvan.Yan@Sun.COM return (0); 36110923SEvan.Yan@Sun.COM } 36210923SEvan.Yan@Sun.COM 36310923SEvan.Yan@Sun.COM /* ARGSUSED */ 36410923SEvan.Yan@Sun.COM int 36510923SEvan.Yan@Sun.COM pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode, 36610923SEvan.Yan@Sun.COM cred_t *credp, int *rvalp) 36710923SEvan.Yan@Sun.COM { 36810923SEvan.Yan@Sun.COM struct devctl_iocdata *dcp; 36910923SEvan.Yan@Sun.COM uint_t bus_state; 37010923SEvan.Yan@Sun.COM int rv = DDI_SUCCESS; 37110923SEvan.Yan@Sun.COM 37210923SEvan.Yan@Sun.COM /* 37310923SEvan.Yan@Sun.COM * We can use the generic implementation for devctl ioctl 37410923SEvan.Yan@Sun.COM */ 37510923SEvan.Yan@Sun.COM switch (cmd) { 37610923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_GETSTATE: 37710923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_ONLINE: 37810923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_OFFLINE: 37910923SEvan.Yan@Sun.COM case DEVCTL_BUS_GETSTATE: 38010923SEvan.Yan@Sun.COM return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0)); 38110923SEvan.Yan@Sun.COM default: 38210923SEvan.Yan@Sun.COM break; 38310923SEvan.Yan@Sun.COM } 38410923SEvan.Yan@Sun.COM 38510923SEvan.Yan@Sun.COM /* 38610923SEvan.Yan@Sun.COM * read devctl ioctl data 38710923SEvan.Yan@Sun.COM */ 38810923SEvan.Yan@Sun.COM if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 38910923SEvan.Yan@Sun.COM return (EFAULT); 39010923SEvan.Yan@Sun.COM 39110923SEvan.Yan@Sun.COM switch (cmd) { 39210923SEvan.Yan@Sun.COM case DEVCTL_BUS_QUIESCE: 39310923SEvan.Yan@Sun.COM if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) 39410923SEvan.Yan@Sun.COM if (bus_state == BUS_QUIESCED) 39510923SEvan.Yan@Sun.COM break; 39610923SEvan.Yan@Sun.COM (void) ndi_set_bus_state(dip, BUS_QUIESCED); 39710923SEvan.Yan@Sun.COM break; 39810923SEvan.Yan@Sun.COM case DEVCTL_BUS_UNQUIESCE: 39910923SEvan.Yan@Sun.COM if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) 40010923SEvan.Yan@Sun.COM if (bus_state == BUS_ACTIVE) 40110923SEvan.Yan@Sun.COM break; 40210923SEvan.Yan@Sun.COM (void) ndi_set_bus_state(dip, BUS_ACTIVE); 40310923SEvan.Yan@Sun.COM break; 40410923SEvan.Yan@Sun.COM case DEVCTL_BUS_RESET: 40510923SEvan.Yan@Sun.COM case DEVCTL_BUS_RESETALL: 40610923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_RESET: 40710923SEvan.Yan@Sun.COM rv = ENOTSUP; 40810923SEvan.Yan@Sun.COM break; 40910923SEvan.Yan@Sun.COM default: 41010923SEvan.Yan@Sun.COM rv = ENOTTY; 41110923SEvan.Yan@Sun.COM } 41210923SEvan.Yan@Sun.COM 41310923SEvan.Yan@Sun.COM ndi_dc_freehdl(dcp); 41410923SEvan.Yan@Sun.COM return (rv); 41510923SEvan.Yan@Sun.COM } 41610923SEvan.Yan@Sun.COM 41710923SEvan.Yan@Sun.COM /* ARGSUSED */ 41810923SEvan.Yan@Sun.COM int 41910923SEvan.Yan@Sun.COM pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 42010923SEvan.Yan@Sun.COM int flags, char *name, caddr_t valuep, int *lengthp) 42110923SEvan.Yan@Sun.COM { 42210923SEvan.Yan@Sun.COM if (dev == DDI_DEV_T_ANY) 42310923SEvan.Yan@Sun.COM goto skip; 42410923SEvan.Yan@Sun.COM 42510923SEvan.Yan@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip) && 42610923SEvan.Yan@Sun.COM strcmp(name, "pci-occupant") == 0) { 42710923SEvan.Yan@Sun.COM int pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev)); 42810923SEvan.Yan@Sun.COM 42910923SEvan.Yan@Sun.COM pcie_hp_create_occupant_props(dip, dev, pci_dev); 43010923SEvan.Yan@Sun.COM } 43110923SEvan.Yan@Sun.COM 43210923SEvan.Yan@Sun.COM skip: 43310923SEvan.Yan@Sun.COM return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); 43410923SEvan.Yan@Sun.COM } 43510923SEvan.Yan@Sun.COM 43611245SZhijun.Fu@Sun.COM int 43711245SZhijun.Fu@Sun.COM pcie_init_cfghdl(dev_info_t *cdip) 43811245SZhijun.Fu@Sun.COM { 43911245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p; 44011245SZhijun.Fu@Sun.COM ddi_acc_handle_t eh = NULL; 44111245SZhijun.Fu@Sun.COM 44211245SZhijun.Fu@Sun.COM bus_p = PCIE_DIP2BUS(cdip); 44311245SZhijun.Fu@Sun.COM if (bus_p == NULL) 44411245SZhijun.Fu@Sun.COM return (DDI_FAILURE); 44511245SZhijun.Fu@Sun.COM 44611245SZhijun.Fu@Sun.COM /* Create an config access special to error handling */ 44711245SZhijun.Fu@Sun.COM if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) { 44811245SZhijun.Fu@Sun.COM cmn_err(CE_WARN, "Cannot setup config access" 44911245SZhijun.Fu@Sun.COM " for BDF 0x%x\n", bus_p->bus_bdf); 45011245SZhijun.Fu@Sun.COM return (DDI_FAILURE); 45111245SZhijun.Fu@Sun.COM } 45211245SZhijun.Fu@Sun.COM 45311245SZhijun.Fu@Sun.COM bus_p->bus_cfg_hdl = eh; 45411245SZhijun.Fu@Sun.COM return (DDI_SUCCESS); 45511245SZhijun.Fu@Sun.COM } 45611245SZhijun.Fu@Sun.COM 45711245SZhijun.Fu@Sun.COM void 45811245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(dev_info_t *cdip) 45911245SZhijun.Fu@Sun.COM { 46011245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip); 46111245SZhijun.Fu@Sun.COM 46211245SZhijun.Fu@Sun.COM pci_config_teardown(&bus_p->bus_cfg_hdl); 46311245SZhijun.Fu@Sun.COM } 46411245SZhijun.Fu@Sun.COM 46510187SKrishna.Elango@Sun.COM /* 46610187SKrishna.Elango@Sun.COM * PCI-Express child device initialization. 46710187SKrishna.Elango@Sun.COM * This function enables generic pci-express interrupts and error 46810187SKrishna.Elango@Sun.COM * handling. 46910187SKrishna.Elango@Sun.COM * 47010187SKrishna.Elango@Sun.COM * @param pdip root dip (root nexus's dip) 47110187SKrishna.Elango@Sun.COM * @param cdip child's dip (device's dip) 47210187SKrishna.Elango@Sun.COM * @return DDI_SUCCESS or DDI_FAILURE 47310187SKrishna.Elango@Sun.COM */ 47410187SKrishna.Elango@Sun.COM /* ARGSUSED */ 47510187SKrishna.Elango@Sun.COM int 47610187SKrishna.Elango@Sun.COM pcie_initchild(dev_info_t *cdip) 47710187SKrishna.Elango@Sun.COM { 47810187SKrishna.Elango@Sun.COM uint16_t tmp16, reg16; 47910187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 48011596SJason.Beloro@Sun.COM uint32_t devid, venid; 48110187SKrishna.Elango@Sun.COM 48210187SKrishna.Elango@Sun.COM bus_p = PCIE_DIP2BUS(cdip); 48310187SKrishna.Elango@Sun.COM if (bus_p == NULL) { 48410187SKrishna.Elango@Sun.COM PCIE_DBG("%s: BUS not found.\n", 48510187SKrishna.Elango@Sun.COM ddi_driver_name(cdip)); 48610187SKrishna.Elango@Sun.COM 48710187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 48810187SKrishna.Elango@Sun.COM } 48910187SKrishna.Elango@Sun.COM 49011245SZhijun.Fu@Sun.COM if (pcie_init_cfghdl(cdip) != DDI_SUCCESS) 49111245SZhijun.Fu@Sun.COM return (DDI_FAILURE); 49211245SZhijun.Fu@Sun.COM 49311596SJason.Beloro@Sun.COM /* 49411596SJason.Beloro@Sun.COM * Update pcie_bus_t with real Vendor Id Device Id. 49511596SJason.Beloro@Sun.COM * 49611596SJason.Beloro@Sun.COM * For assigned devices in IOV environment, the OBP will return 49711596SJason.Beloro@Sun.COM * faked device id/vendor id on configration read and for both 49811596SJason.Beloro@Sun.COM * properties in root domain. translate_devid() function will 49911596SJason.Beloro@Sun.COM * update the properties with real device-id/vendor-id on such 50011596SJason.Beloro@Sun.COM * platforms, so that we can utilize the properties here to get 50111596SJason.Beloro@Sun.COM * real device-id/vendor-id and overwrite the faked ids. 50211596SJason.Beloro@Sun.COM * 50311596SJason.Beloro@Sun.COM * For unassigned devices or devices in non-IOV environment, the 50411596SJason.Beloro@Sun.COM * operation below won't make a difference. 50511596SJason.Beloro@Sun.COM * 50611596SJason.Beloro@Sun.COM * The IOV implementation only supports assignment of PCIE 50711596SJason.Beloro@Sun.COM * endpoint devices. Devices under pci-pci bridges don't need 50811596SJason.Beloro@Sun.COM * operation like this. 50911596SJason.Beloro@Sun.COM */ 51011596SJason.Beloro@Sun.COM devid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 51111596SJason.Beloro@Sun.COM "device-id", -1); 51211596SJason.Beloro@Sun.COM venid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 51311596SJason.Beloro@Sun.COM "vendor-id", -1); 51411596SJason.Beloro@Sun.COM bus_p->bus_dev_ven_id = (devid << 16) | (venid & 0xffff); 51511596SJason.Beloro@Sun.COM 51610187SKrishna.Elango@Sun.COM /* Clear the device's status register */ 51710187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT); 51810187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16); 51910187SKrishna.Elango@Sun.COM 52010187SKrishna.Elango@Sun.COM /* Setup the device's command register */ 52110187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM); 52210187SKrishna.Elango@Sun.COM tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default; 52310187SKrishna.Elango@Sun.COM 52410187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64) 52510187SKrishna.Elango@Sun.COM boolean_t empty_io_range = B_FALSE; 52610187SKrishna.Elango@Sun.COM boolean_t empty_mem_range = B_FALSE; 52710187SKrishna.Elango@Sun.COM /* 52810187SKrishna.Elango@Sun.COM * Check for empty IO and Mem ranges on bridges. If so disable IO/Mem 52910187SKrishna.Elango@Sun.COM * access as it can cause a hang if enabled. 53010187SKrishna.Elango@Sun.COM */ 53110187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(bus_p->bus_cfg_hdl, &empty_io_range, 53210187SKrishna.Elango@Sun.COM &empty_mem_range); 53310187SKrishna.Elango@Sun.COM if ((empty_io_range == B_TRUE) && 53410187SKrishna.Elango@Sun.COM (pcie_command_default & PCI_COMM_IO)) { 53510187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_IO; 53610187SKrishna.Elango@Sun.COM PCIE_DBG("No I/O range found for %s, bdf 0x%x\n", 53710187SKrishna.Elango@Sun.COM ddi_driver_name(cdip), bus_p->bus_bdf); 53810187SKrishna.Elango@Sun.COM } 53910187SKrishna.Elango@Sun.COM if ((empty_mem_range == B_TRUE) && 54010187SKrishna.Elango@Sun.COM (pcie_command_default & PCI_COMM_MAE)) { 54110187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_MAE; 54210187SKrishna.Elango@Sun.COM PCIE_DBG("No Mem range found for %s, bdf 0x%x\n", 54310187SKrishna.Elango@Sun.COM ddi_driver_name(cdip), bus_p->bus_bdf); 54410187SKrishna.Elango@Sun.COM } 54510187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */ 54610187SKrishna.Elango@Sun.COM 54710187SKrishna.Elango@Sun.COM if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p)) 54810187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_SERR_ENABLE; 54910187SKrishna.Elango@Sun.COM 55010187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16); 55110187SKrishna.Elango@Sun.COM PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16); 55210187SKrishna.Elango@Sun.COM 55310187SKrishna.Elango@Sun.COM /* 55410187SKrishna.Elango@Sun.COM * If the device has a bus control register then program it 55510187SKrishna.Elango@Sun.COM * based on the settings in the command register. 55610187SKrishna.Elango@Sun.COM */ 55710187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 55810187SKrishna.Elango@Sun.COM /* Clear the device's secondary status register */ 55910187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS); 56010187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16); 56110187SKrishna.Elango@Sun.COM 56210187SKrishna.Elango@Sun.COM /* Setup the device's secondary command register */ 56310187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL); 56410187SKrishna.Elango@Sun.COM tmp16 = (reg16 & pcie_bdg_command_default_fw); 56510187SKrishna.Elango@Sun.COM 56610187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE; 56710187SKrishna.Elango@Sun.COM /* 56810187SKrishna.Elango@Sun.COM * Workaround for this Nvidia bridge. Don't enable the SERR 56910187SKrishna.Elango@Sun.COM * enable bit in the bridge control register as it could lead to 57010187SKrishna.Elango@Sun.COM * bogus NMIs. 57110187SKrishna.Elango@Sun.COM */ 57210187SKrishna.Elango@Sun.COM if (bus_p->bus_dev_ven_id == 0x037010DE) 57310187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE; 57410187SKrishna.Elango@Sun.COM 57510187SKrishna.Elango@Sun.COM if (pcie_command_default & PCI_COMM_PARITY_DETECT) 57610187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE; 57710187SKrishna.Elango@Sun.COM 57810187SKrishna.Elango@Sun.COM /* 57910187SKrishna.Elango@Sun.COM * Enable Master Abort Mode only if URs have not been masked. 58010187SKrishna.Elango@Sun.COM * For PCI and PCIe-PCI bridges, enabling this bit causes a 58110187SKrishna.Elango@Sun.COM * Master Aborts/UR to be forwarded as a UR/TA or SERR. If this 58210187SKrishna.Elango@Sun.COM * bit is masked, posted requests are dropped and non-posted 58310187SKrishna.Elango@Sun.COM * requests are returned with -1. 58410187SKrishna.Elango@Sun.COM */ 58510187SKrishna.Elango@Sun.COM if (pcie_aer_uce_mask & PCIE_AER_UCE_UR) 58610187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE; 58710187SKrishna.Elango@Sun.COM else 58810187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE; 58910187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16); 59010187SKrishna.Elango@Sun.COM PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL, 59110187SKrishna.Elango@Sun.COM reg16); 59210187SKrishna.Elango@Sun.COM } 59310187SKrishna.Elango@Sun.COM 59410187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 59510187SKrishna.Elango@Sun.COM /* Setup PCIe device control register */ 59610187SKrishna.Elango@Sun.COM reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 597*12330SDaniel.Ice@Sun.COM /* note: MPS/MRRS are initialized in pcie_initchild_mps() */ 598*12330SDaniel.Ice@Sun.COM tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK | 599*12330SDaniel.Ice@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 600*12330SDaniel.Ice@Sun.COM (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 601*12330SDaniel.Ice@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)); 60210187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16); 60310187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16); 60410187SKrishna.Elango@Sun.COM 60510187SKrishna.Elango@Sun.COM /* Enable PCIe errors */ 60610187SKrishna.Elango@Sun.COM pcie_enable_errors(cdip); 60710187SKrishna.Elango@Sun.COM } 60810187SKrishna.Elango@Sun.COM 60910923SEvan.Yan@Sun.COM bus_p->bus_ari = B_FALSE; 61010923SEvan.Yan@Sun.COM if ((pcie_ari_is_enabled(ddi_get_parent(cdip)) 61110923SEvan.Yan@Sun.COM == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip) 61210923SEvan.Yan@Sun.COM == PCIE_ARI_DEVICE)) { 61310923SEvan.Yan@Sun.COM bus_p->bus_ari = B_TRUE; 61410923SEvan.Yan@Sun.COM } 61510923SEvan.Yan@Sun.COM 61611245SZhijun.Fu@Sun.COM if (pcie_initchild_mps(cdip) == DDI_FAILURE) { 61711245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(cdip); 61810187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 61911245SZhijun.Fu@Sun.COM } 62010187SKrishna.Elango@Sun.COM 62110187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 62210187SKrishna.Elango@Sun.COM } 62310187SKrishna.Elango@Sun.COM 62410187SKrishna.Elango@Sun.COM static void 62510187SKrishna.Elango@Sun.COM pcie_init_pfd(dev_info_t *dip) 62610187SKrishna.Elango@Sun.COM { 62710187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_ZALLOC(pf_data_t); 62810187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 62910187SKrishna.Elango@Sun.COM 63010187SKrishna.Elango@Sun.COM PCIE_DIP2PFD(dip) = pfd_p; 63110187SKrishna.Elango@Sun.COM 63210187SKrishna.Elango@Sun.COM pfd_p->pe_bus_p = bus_p; 63310187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = 0; 63411596SJason.Beloro@Sun.COM pfd_p->pe_orig_severity_flags = 0; 63510187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE; 63610187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE; 63710187SKrishna.Elango@Sun.COM 63810187SKrishna.Elango@Sun.COM /* Allocate the root fault struct for both RC and RP */ 63910187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) { 64010187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t); 64110187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF; 64211596SJason.Beloro@Sun.COM PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t); 64310187SKrishna.Elango@Sun.COM } 64410187SKrishna.Elango@Sun.COM 64510187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t); 64611596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t); 64711596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF; 64810187SKrishna.Elango@Sun.COM 64910187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) 65010187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t); 65110187SKrishna.Elango@Sun.COM 65210187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 65310187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t); 65410187SKrishna.Elango@Sun.COM 65510187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 65610187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p) = 65710187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_rp_err_regs_t); 65810187SKrishna.Elango@Sun.COM 65910187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t); 66010187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF; 66110187SKrishna.Elango@Sun.COM 66210187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) { 66310187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p) = 66410187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t); 66510187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = 66610187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 66710187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = 66810187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 66910187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIE_BDG(bus_p)) { 67010187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p) = 67110187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t); 67210187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = 67310187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF; 67410187SKrishna.Elango@Sun.COM } 67510187SKrishna.Elango@Sun.COM 67610187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) { 67710187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p) = 67810187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_bdg_err_regs_t); 67910187SKrishna.Elango@Sun.COM 68010187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 68110187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0) = 68210187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 68310187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 1) = 68410187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 68510187SKrishna.Elango@Sun.COM } 68610187SKrishna.Elango@Sun.COM } 68710187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIX(bus_p)) { 68810187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 68910187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p) = 69010187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_bdg_err_regs_t); 69110187SKrishna.Elango@Sun.COM 69210187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 69310187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0) = 69410187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 69510187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 1) = 69610187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 69710187SKrishna.Elango@Sun.COM } 69810187SKrishna.Elango@Sun.COM } else { 69910187SKrishna.Elango@Sun.COM PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t); 70010187SKrishna.Elango@Sun.COM 70110187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) 70210187SKrishna.Elango@Sun.COM PCIX_ECC_REG(pfd_p) = 70310187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t); 70410187SKrishna.Elango@Sun.COM } 70510187SKrishna.Elango@Sun.COM } 70610187SKrishna.Elango@Sun.COM } 70710187SKrishna.Elango@Sun.COM 70810187SKrishna.Elango@Sun.COM static void 70910187SKrishna.Elango@Sun.COM pcie_fini_pfd(dev_info_t *dip) 71010187SKrishna.Elango@Sun.COM { 71110187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip); 71210187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 71310187SKrishna.Elango@Sun.COM 71410187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 71510187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) { 71610187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 71710187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0), 71810187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 71910187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1), 72010187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 72110187SKrishna.Elango@Sun.COM } 72210187SKrishna.Elango@Sun.COM 72310187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ERR_REG(pfd_p), 72410187SKrishna.Elango@Sun.COM sizeof (pf_pcix_bdg_err_regs_t)); 72510187SKrishna.Elango@Sun.COM } 72610187SKrishna.Elango@Sun.COM 72710187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 72810187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_RP_REG(pfd_p), 72910187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_rp_err_regs_t)); 73010187SKrishna.Elango@Sun.COM else if (PCIE_IS_PCIE_BDG(bus_p)) 73110187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_BDG_REG(pfd_p), 73210187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_bdg_err_regs_t)); 73310187SKrishna.Elango@Sun.COM 73410187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_REG(pfd_p), 73510187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_err_regs_t)); 73610187SKrishna.Elango@Sun.COM 73710187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) 73810187SKrishna.Elango@Sun.COM kmem_free(PCIE_RP_REG(pfd_p), 73910187SKrishna.Elango@Sun.COM sizeof (pf_pcie_rp_err_regs_t)); 74010187SKrishna.Elango@Sun.COM 74110187SKrishna.Elango@Sun.COM kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t)); 74210187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIX(bus_p)) { 74310187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) { 74410187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) { 74510187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0), 74610187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 74710187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1), 74810187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 74910187SKrishna.Elango@Sun.COM } 75010187SKrishna.Elango@Sun.COM 75110187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ERR_REG(pfd_p), 75210187SKrishna.Elango@Sun.COM sizeof (pf_pcix_bdg_err_regs_t)); 75310187SKrishna.Elango@Sun.COM } else { 75410187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) 75510187SKrishna.Elango@Sun.COM kmem_free(PCIX_ECC_REG(pfd_p), 75610187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t)); 75710187SKrishna.Elango@Sun.COM 75810187SKrishna.Elango@Sun.COM kmem_free(PCIX_ERR_REG(pfd_p), 75910187SKrishna.Elango@Sun.COM sizeof (pf_pcix_err_regs_t)); 76010187SKrishna.Elango@Sun.COM } 76110187SKrishna.Elango@Sun.COM } 76210187SKrishna.Elango@Sun.COM 76310187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) 76410187SKrishna.Elango@Sun.COM kmem_free(PCI_BDG_ERR_REG(pfd_p), 76510187SKrishna.Elango@Sun.COM sizeof (pf_pci_bdg_err_regs_t)); 76610187SKrishna.Elango@Sun.COM 76711596SJason.Beloro@Sun.COM kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t)); 76810187SKrishna.Elango@Sun.COM kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t)); 76910187SKrishna.Elango@Sun.COM 77011596SJason.Beloro@Sun.COM if (PCIE_IS_ROOT(bus_p)) { 77110187SKrishna.Elango@Sun.COM kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t)); 77211596SJason.Beloro@Sun.COM kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t)); 77311596SJason.Beloro@Sun.COM } 77410187SKrishna.Elango@Sun.COM 77510187SKrishna.Elango@Sun.COM kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t)); 77610187SKrishna.Elango@Sun.COM 77710187SKrishna.Elango@Sun.COM PCIE_DIP2PFD(dip) = NULL; 77810187SKrishna.Elango@Sun.COM } 77910187SKrishna.Elango@Sun.COM 78010187SKrishna.Elango@Sun.COM 78110187SKrishna.Elango@Sun.COM /* 78210187SKrishna.Elango@Sun.COM * Special functions to allocate pf_data_t's for PCIe root complexes. 78310187SKrishna.Elango@Sun.COM * Note: Root Complex not Root Port 78410187SKrishna.Elango@Sun.COM */ 78510187SKrishna.Elango@Sun.COM void 78610187SKrishna.Elango@Sun.COM pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p) 78710187SKrishna.Elango@Sun.COM { 78810187SKrishna.Elango@Sun.COM pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip); 78910187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = 0; 79011596SJason.Beloro@Sun.COM pfd_p->pe_orig_severity_flags = 0; 79110187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE; 79210187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE; 79310187SKrishna.Elango@Sun.COM 79410187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t); 79510187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF; 79611596SJason.Beloro@Sun.COM PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t); 79710187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t); 79811596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t); 79911596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF; 80010187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t); 80110187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t); 80210187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t); 80310187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t); 80410187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t); 80511596SJason.Beloro@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = PCIE_INVALID_BDF; 80611596SJason.Beloro@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = PCIE_INVALID_BDF; 80710187SKrishna.Elango@Sun.COM 80810187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity; 80910187SKrishna.Elango@Sun.COM } 81010187SKrishna.Elango@Sun.COM 81110187SKrishna.Elango@Sun.COM void 81210187SKrishna.Elango@Sun.COM pcie_rc_fini_pfd(pf_data_t *pfd_p) 81310187SKrishna.Elango@Sun.COM { 81410187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t)); 81510187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t)); 81610187SKrishna.Elango@Sun.COM kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t)); 81710187SKrishna.Elango@Sun.COM kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t)); 81810187SKrishna.Elango@Sun.COM kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t)); 81911596SJason.Beloro@Sun.COM kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t)); 82010187SKrishna.Elango@Sun.COM kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t)); 82110187SKrishna.Elango@Sun.COM kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t)); 82211596SJason.Beloro@Sun.COM kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t)); 82310187SKrishna.Elango@Sun.COM } 82410187SKrishna.Elango@Sun.COM 82511245SZhijun.Fu@Sun.COM /* 82611245SZhijun.Fu@Sun.COM * init pcie_bus_t for root complex 82711245SZhijun.Fu@Sun.COM * 82811245SZhijun.Fu@Sun.COM * Only a few of the fields in bus_t is valid for root complex. 82911245SZhijun.Fu@Sun.COM * The fields that are bracketed are initialized in this routine: 83011245SZhijun.Fu@Sun.COM * 83111245SZhijun.Fu@Sun.COM * dev_info_t * <bus_dip> 83211245SZhijun.Fu@Sun.COM * dev_info_t * bus_rp_dip 83311245SZhijun.Fu@Sun.COM * ddi_acc_handle_t bus_cfg_hdl 83411245SZhijun.Fu@Sun.COM * uint_t <bus_fm_flags> 83511245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_bdf 83611245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_rp_bdf 83711245SZhijun.Fu@Sun.COM * uint32_t bus_dev_ven_id 83811245SZhijun.Fu@Sun.COM * uint8_t bus_rev_id 83911245SZhijun.Fu@Sun.COM * uint8_t <bus_hdr_type> 84011245SZhijun.Fu@Sun.COM * uint16_t <bus_dev_type> 84111245SZhijun.Fu@Sun.COM * uint8_t bus_bdg_secbus 84211245SZhijun.Fu@Sun.COM * uint16_t bus_pcie_off 84311245SZhijun.Fu@Sun.COM * uint16_t <bus_aer_off> 84411245SZhijun.Fu@Sun.COM * uint16_t bus_pcix_off 84511245SZhijun.Fu@Sun.COM * uint16_t bus_ecc_ver 84611245SZhijun.Fu@Sun.COM * pci_bus_range_t bus_bus_range 84711245SZhijun.Fu@Sun.COM * ppb_ranges_t * bus_addr_ranges 84811245SZhijun.Fu@Sun.COM * int bus_addr_entries 84911245SZhijun.Fu@Sun.COM * pci_regspec_t * bus_assigned_addr 85011245SZhijun.Fu@Sun.COM * int bus_assigned_entries 85111245SZhijun.Fu@Sun.COM * pf_data_t * bus_pfd 85211596SJason.Beloro@Sun.COM * pcie_domain_t * <bus_dom> 85311245SZhijun.Fu@Sun.COM * int bus_mps 85411245SZhijun.Fu@Sun.COM * uint64_t bus_cfgacc_base 85511245SZhijun.Fu@Sun.COM * void * bus_plat_private 85611245SZhijun.Fu@Sun.COM */ 85710187SKrishna.Elango@Sun.COM void 85810187SKrishna.Elango@Sun.COM pcie_rc_init_bus(dev_info_t *dip) 85910187SKrishna.Elango@Sun.COM { 86010187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 86110187SKrishna.Elango@Sun.COM 86210187SKrishna.Elango@Sun.COM bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP); 86310187SKrishna.Elango@Sun.COM bus_p->bus_dip = dip; 86410187SKrishna.Elango@Sun.COM bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO; 86510187SKrishna.Elango@Sun.COM bus_p->bus_hdr_type = PCI_HEADER_ONE; 86610187SKrishna.Elango@Sun.COM 86710187SKrishna.Elango@Sun.COM /* Fake that there are AER logs */ 86810187SKrishna.Elango@Sun.COM bus_p->bus_aer_off = (uint16_t)-1; 86910187SKrishna.Elango@Sun.COM 87010187SKrishna.Elango@Sun.COM /* Needed only for handle lookup */ 87110187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags |= PF_FM_READY; 87210187SKrishna.Elango@Sun.COM 87310187SKrishna.Elango@Sun.COM ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p); 87411596SJason.Beloro@Sun.COM 87511596SJason.Beloro@Sun.COM PCIE_BUS2DOM(bus_p) = PCIE_ZALLOC(pcie_domain_t); 87610187SKrishna.Elango@Sun.COM } 87710187SKrishna.Elango@Sun.COM 87810187SKrishna.Elango@Sun.COM void 87910187SKrishna.Elango@Sun.COM pcie_rc_fini_bus(dev_info_t *dip) 88010187SKrishna.Elango@Sun.COM { 88111245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2DOWNBUS(dip); 88210187SKrishna.Elango@Sun.COM ndi_set_bus_private(dip, B_FALSE, NULL, NULL); 88311596SJason.Beloro@Sun.COM kmem_free(PCIE_BUS2DOM(bus_p), sizeof (pcie_domain_t)); 88410187SKrishna.Elango@Sun.COM kmem_free(bus_p, sizeof (pcie_bus_t)); 88510187SKrishna.Elango@Sun.COM } 88610187SKrishna.Elango@Sun.COM 88710187SKrishna.Elango@Sun.COM /* 88811245SZhijun.Fu@Sun.COM * partially init pcie_bus_t for device (dip,bdf) for accessing pci 88911245SZhijun.Fu@Sun.COM * config space 89011245SZhijun.Fu@Sun.COM * 89111245SZhijun.Fu@Sun.COM * This routine is invoked during boot, either after creating a devinfo node 89211245SZhijun.Fu@Sun.COM * (x86 case) or during px driver attach (sparc case); it is also invoked 89311245SZhijun.Fu@Sun.COM * in hotplug context after a devinfo node is created. 89411245SZhijun.Fu@Sun.COM * 89511245SZhijun.Fu@Sun.COM * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL 89611245SZhijun.Fu@Sun.COM * is set: 89710187SKrishna.Elango@Sun.COM * 89811245SZhijun.Fu@Sun.COM * dev_info_t * <bus_dip> 89911245SZhijun.Fu@Sun.COM * dev_info_t * <bus_rp_dip> 90011245SZhijun.Fu@Sun.COM * ddi_acc_handle_t bus_cfg_hdl 90111245SZhijun.Fu@Sun.COM * uint_t bus_fm_flags 90211245SZhijun.Fu@Sun.COM * pcie_req_id_t <bus_bdf> 90311245SZhijun.Fu@Sun.COM * pcie_req_id_t <bus_rp_bdf> 90411245SZhijun.Fu@Sun.COM * uint32_t <bus_dev_ven_id> 90511245SZhijun.Fu@Sun.COM * uint8_t <bus_rev_id> 90611245SZhijun.Fu@Sun.COM * uint8_t <bus_hdr_type> 90711245SZhijun.Fu@Sun.COM * uint16_t <bus_dev_type> 90811245SZhijun.Fu@Sun.COM * uint8_t <bus_bdg_secbus 90911245SZhijun.Fu@Sun.COM * uint16_t <bus_pcie_off> 91011245SZhijun.Fu@Sun.COM * uint16_t <bus_aer_off> 91111245SZhijun.Fu@Sun.COM * uint16_t <bus_pcix_off> 91211245SZhijun.Fu@Sun.COM * uint16_t <bus_ecc_ver> 91311245SZhijun.Fu@Sun.COM * pci_bus_range_t bus_bus_range 91411245SZhijun.Fu@Sun.COM * ppb_ranges_t * bus_addr_ranges 91511245SZhijun.Fu@Sun.COM * int bus_addr_entries 91611245SZhijun.Fu@Sun.COM * pci_regspec_t * bus_assigned_addr 91711245SZhijun.Fu@Sun.COM * int bus_assigned_entries 91811245SZhijun.Fu@Sun.COM * pf_data_t * bus_pfd 91911596SJason.Beloro@Sun.COM * pcie_domain_t * bus_dom 92011245SZhijun.Fu@Sun.COM * int bus_mps 92111245SZhijun.Fu@Sun.COM * uint64_t bus_cfgacc_base 92211245SZhijun.Fu@Sun.COM * void * bus_plat_private 92311245SZhijun.Fu@Sun.COM * 92411245SZhijun.Fu@Sun.COM * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL 92511245SZhijun.Fu@Sun.COM * is set: 92611245SZhijun.Fu@Sun.COM * 92711245SZhijun.Fu@Sun.COM * dev_info_t * bus_dip 92811245SZhijun.Fu@Sun.COM * dev_info_t * bus_rp_dip 92911245SZhijun.Fu@Sun.COM * ddi_acc_handle_t bus_cfg_hdl 93011245SZhijun.Fu@Sun.COM * uint_t bus_fm_flags 93111245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_bdf 93211245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_rp_bdf 93311245SZhijun.Fu@Sun.COM * uint32_t bus_dev_ven_id 93411245SZhijun.Fu@Sun.COM * uint8_t bus_rev_id 93511245SZhijun.Fu@Sun.COM * uint8_t bus_hdr_type 93611245SZhijun.Fu@Sun.COM * uint16_t bus_dev_type 93711245SZhijun.Fu@Sun.COM * uint8_t <bus_bdg_secbus> 93811245SZhijun.Fu@Sun.COM * uint16_t bus_pcie_off 93911245SZhijun.Fu@Sun.COM * uint16_t bus_aer_off 94011245SZhijun.Fu@Sun.COM * uint16_t bus_pcix_off 94111245SZhijun.Fu@Sun.COM * uint16_t bus_ecc_ver 94211245SZhijun.Fu@Sun.COM * pci_bus_range_t <bus_bus_range> 94311245SZhijun.Fu@Sun.COM * ppb_ranges_t * <bus_addr_ranges> 94411245SZhijun.Fu@Sun.COM * int <bus_addr_entries> 94511245SZhijun.Fu@Sun.COM * pci_regspec_t * <bus_assigned_addr> 94611245SZhijun.Fu@Sun.COM * int <bus_assigned_entries> 94711245SZhijun.Fu@Sun.COM * pf_data_t * <bus_pfd> 94811596SJason.Beloro@Sun.COM * pcie_domain_t * bus_dom 94911245SZhijun.Fu@Sun.COM * int bus_mps 95011245SZhijun.Fu@Sun.COM * uint64_t bus_cfgacc_base 95111245SZhijun.Fu@Sun.COM * void * <bus_plat_private> 95210187SKrishna.Elango@Sun.COM */ 95311245SZhijun.Fu@Sun.COM 95410187SKrishna.Elango@Sun.COM pcie_bus_t * 95511245SZhijun.Fu@Sun.COM pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf, uint8_t flags) 95610187SKrishna.Elango@Sun.COM { 95711245SZhijun.Fu@Sun.COM uint16_t status, base, baseptr, num_cap; 95811245SZhijun.Fu@Sun.COM uint32_t capid; 95911245SZhijun.Fu@Sun.COM int range_size; 96011245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p; 96111245SZhijun.Fu@Sun.COM dev_info_t *rcdip; 96211245SZhijun.Fu@Sun.COM dev_info_t *pdip; 96311245SZhijun.Fu@Sun.COM const char *errstr = NULL; 96410187SKrishna.Elango@Sun.COM 96511245SZhijun.Fu@Sun.COM if (!(flags & PCIE_BUS_INITIAL)) 96611245SZhijun.Fu@Sun.COM goto initial_done; 96710187SKrishna.Elango@Sun.COM 96810187SKrishna.Elango@Sun.COM bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP); 96910187SKrishna.Elango@Sun.COM 97011245SZhijun.Fu@Sun.COM bus_p->bus_dip = dip; 97111245SZhijun.Fu@Sun.COM bus_p->bus_bdf = bdf; 97210187SKrishna.Elango@Sun.COM 97311245SZhijun.Fu@Sun.COM rcdip = pcie_get_rc_dip(dip); 97411245SZhijun.Fu@Sun.COM ASSERT(rcdip != NULL); 97510187SKrishna.Elango@Sun.COM 97611245SZhijun.Fu@Sun.COM /* Save the Vendor ID, Device ID and revision ID */ 97711245SZhijun.Fu@Sun.COM bus_p->bus_dev_ven_id = pci_cfgacc_get32(rcdip, bdf, PCI_CONF_VENID); 97811245SZhijun.Fu@Sun.COM bus_p->bus_rev_id = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID); 97910187SKrishna.Elango@Sun.COM /* Save the Header Type */ 98011245SZhijun.Fu@Sun.COM bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER); 98110187SKrishna.Elango@Sun.COM bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M; 98210187SKrishna.Elango@Sun.COM 98311245SZhijun.Fu@Sun.COM /* 98411245SZhijun.Fu@Sun.COM * Figure out the device type and all the relavant capability offsets 98511245SZhijun.Fu@Sun.COM */ 98611245SZhijun.Fu@Sun.COM /* set default value */ 98711245SZhijun.Fu@Sun.COM bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO; 98810187SKrishna.Elango@Sun.COM 98911245SZhijun.Fu@Sun.COM status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT); 99011245SZhijun.Fu@Sun.COM if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP)) 99111245SZhijun.Fu@Sun.COM goto caps_done; /* capability not supported */ 99211245SZhijun.Fu@Sun.COM 99311245SZhijun.Fu@Sun.COM /* Relevant conventional capabilities first */ 99411245SZhijun.Fu@Sun.COM 99511245SZhijun.Fu@Sun.COM /* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */ 99611245SZhijun.Fu@Sun.COM num_cap = 2; 99710923SEvan.Yan@Sun.COM 99811245SZhijun.Fu@Sun.COM switch (bus_p->bus_hdr_type) { 99911245SZhijun.Fu@Sun.COM case PCI_HEADER_ZERO: 100011245SZhijun.Fu@Sun.COM baseptr = PCI_CONF_CAP_PTR; 100111245SZhijun.Fu@Sun.COM break; 100211245SZhijun.Fu@Sun.COM case PCI_HEADER_PPB: 100311245SZhijun.Fu@Sun.COM baseptr = PCI_BCNF_CAP_PTR; 100411245SZhijun.Fu@Sun.COM break; 100511245SZhijun.Fu@Sun.COM case PCI_HEADER_CARDBUS: 100611245SZhijun.Fu@Sun.COM baseptr = PCI_CBUS_CAP_PTR; 100711245SZhijun.Fu@Sun.COM break; 100811245SZhijun.Fu@Sun.COM default: 100911245SZhijun.Fu@Sun.COM cmn_err(CE_WARN, "%s: unexpected pci header type:%x", 101011245SZhijun.Fu@Sun.COM __func__, bus_p->bus_hdr_type); 101111245SZhijun.Fu@Sun.COM goto caps_done; 101210187SKrishna.Elango@Sun.COM } 101310187SKrishna.Elango@Sun.COM 101411245SZhijun.Fu@Sun.COM base = baseptr; 101511245SZhijun.Fu@Sun.COM for (base = pci_cfgacc_get8(rcdip, bdf, base); base && num_cap; 101611245SZhijun.Fu@Sun.COM base = pci_cfgacc_get8(rcdip, bdf, base + PCI_CAP_NEXT_PTR)) { 101711245SZhijun.Fu@Sun.COM capid = pci_cfgacc_get8(rcdip, bdf, base); 101811245SZhijun.Fu@Sun.COM switch (capid) { 101911245SZhijun.Fu@Sun.COM case PCI_CAP_ID_PCI_E: 102011245SZhijun.Fu@Sun.COM bus_p->bus_pcie_off = base; 102111245SZhijun.Fu@Sun.COM bus_p->bus_dev_type = pci_cfgacc_get16(rcdip, bdf, 102211245SZhijun.Fu@Sun.COM base + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 102311245SZhijun.Fu@Sun.COM 102411245SZhijun.Fu@Sun.COM /* Check and save PCIe hotplug capability information */ 102511245SZhijun.Fu@Sun.COM if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) && 102611245SZhijun.Fu@Sun.COM (pci_cfgacc_get16(rcdip, bdf, base + PCIE_PCIECAP) 102711245SZhijun.Fu@Sun.COM & PCIE_PCIECAP_SLOT_IMPL) && 102811245SZhijun.Fu@Sun.COM (pci_cfgacc_get32(rcdip, bdf, base + PCIE_SLOTCAP) 102911245SZhijun.Fu@Sun.COM & PCIE_SLOTCAP_HP_CAPABLE)) 103011245SZhijun.Fu@Sun.COM bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE; 103110923SEvan.Yan@Sun.COM 103211245SZhijun.Fu@Sun.COM num_cap--; 103311245SZhijun.Fu@Sun.COM break; 103411245SZhijun.Fu@Sun.COM case PCI_CAP_ID_PCIX: 103511245SZhijun.Fu@Sun.COM bus_p->bus_pcix_off = base; 103611245SZhijun.Fu@Sun.COM if (PCIE_IS_BDG(bus_p)) 103711245SZhijun.Fu@Sun.COM bus_p->bus_ecc_ver = 103811245SZhijun.Fu@Sun.COM pci_cfgacc_get16(rcdip, bdf, base + 103911245SZhijun.Fu@Sun.COM PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 104011245SZhijun.Fu@Sun.COM else 104111245SZhijun.Fu@Sun.COM bus_p->bus_ecc_ver = 104211245SZhijun.Fu@Sun.COM pci_cfgacc_get16(rcdip, bdf, base + 104311245SZhijun.Fu@Sun.COM PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK; 104411245SZhijun.Fu@Sun.COM num_cap--; 104511245SZhijun.Fu@Sun.COM break; 104611245SZhijun.Fu@Sun.COM default: 104711245SZhijun.Fu@Sun.COM break; 104810187SKrishna.Elango@Sun.COM } 104910187SKrishna.Elango@Sun.COM } 105010187SKrishna.Elango@Sun.COM 105111245SZhijun.Fu@Sun.COM /* Check and save PCI hotplug (SHPC) capability information */ 105211245SZhijun.Fu@Sun.COM if (PCIE_IS_BDG(bus_p)) { 105311245SZhijun.Fu@Sun.COM base = baseptr; 105411245SZhijun.Fu@Sun.COM for (base = pci_cfgacc_get8(rcdip, bdf, base); 105511245SZhijun.Fu@Sun.COM base; base = pci_cfgacc_get8(rcdip, bdf, 105611245SZhijun.Fu@Sun.COM base + PCI_CAP_NEXT_PTR)) { 105711245SZhijun.Fu@Sun.COM capid = pci_cfgacc_get8(rcdip, bdf, base); 105811245SZhijun.Fu@Sun.COM if (capid == PCI_CAP_ID_PCI_HOTPLUG) { 105911245SZhijun.Fu@Sun.COM bus_p->bus_pci_hp_off = base; 106011245SZhijun.Fu@Sun.COM bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE; 106111245SZhijun.Fu@Sun.COM break; 106211245SZhijun.Fu@Sun.COM } 106311245SZhijun.Fu@Sun.COM } 106411245SZhijun.Fu@Sun.COM } 106511245SZhijun.Fu@Sun.COM 106611245SZhijun.Fu@Sun.COM /* Then, relevant extended capabilities */ 106710187SKrishna.Elango@Sun.COM 106811245SZhijun.Fu@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 106911245SZhijun.Fu@Sun.COM goto caps_done; 107011245SZhijun.Fu@Sun.COM 107111245SZhijun.Fu@Sun.COM /* Extended caps: PCIE_EXT_CAP_ID_AER */ 107211245SZhijun.Fu@Sun.COM for (base = PCIE_EXT_CAP; base; base = (capid >> 107311245SZhijun.Fu@Sun.COM PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) { 107411245SZhijun.Fu@Sun.COM capid = pci_cfgacc_get32(rcdip, bdf, base); 107511245SZhijun.Fu@Sun.COM if (capid == PCI_CAP_EINVAL32) 107611245SZhijun.Fu@Sun.COM break; 107711245SZhijun.Fu@Sun.COM if (((capid >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK) 107811245SZhijun.Fu@Sun.COM == PCIE_EXT_CAP_ID_AER) { 107911245SZhijun.Fu@Sun.COM bus_p->bus_aer_off = base; 108011245SZhijun.Fu@Sun.COM break; 108111245SZhijun.Fu@Sun.COM } 108211245SZhijun.Fu@Sun.COM } 108311245SZhijun.Fu@Sun.COM 108411245SZhijun.Fu@Sun.COM caps_done: 108510187SKrishna.Elango@Sun.COM /* save RP dip and RP bdf */ 108610187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) { 108711245SZhijun.Fu@Sun.COM bus_p->bus_rp_dip = dip; 108810187SKrishna.Elango@Sun.COM bus_p->bus_rp_bdf = bus_p->bus_bdf; 108910187SKrishna.Elango@Sun.COM } else { 109011245SZhijun.Fu@Sun.COM for (pdip = ddi_get_parent(dip); pdip; 109110187SKrishna.Elango@Sun.COM pdip = ddi_get_parent(pdip)) { 109210187SKrishna.Elango@Sun.COM pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip); 109310187SKrishna.Elango@Sun.COM 109410187SKrishna.Elango@Sun.COM /* 109511245SZhijun.Fu@Sun.COM * If RP dip and RP bdf in parent's bus_t have 109611245SZhijun.Fu@Sun.COM * been initialized, simply use these instead of 109711245SZhijun.Fu@Sun.COM * continuing up to the RC. 109811245SZhijun.Fu@Sun.COM */ 109911245SZhijun.Fu@Sun.COM if (parent_bus_p->bus_rp_dip != NULL) { 110011245SZhijun.Fu@Sun.COM bus_p->bus_rp_dip = parent_bus_p->bus_rp_dip; 110111245SZhijun.Fu@Sun.COM bus_p->bus_rp_bdf = parent_bus_p->bus_rp_bdf; 110211245SZhijun.Fu@Sun.COM break; 110311245SZhijun.Fu@Sun.COM } 110411245SZhijun.Fu@Sun.COM 110511245SZhijun.Fu@Sun.COM /* 110610187SKrishna.Elango@Sun.COM * When debugging be aware that some NVIDIA x86 110710187SKrishna.Elango@Sun.COM * architectures have 2 nodes for each RP, One at Bus 110810187SKrishna.Elango@Sun.COM * 0x0 and one at Bus 0x80. The requester is from Bus 110910187SKrishna.Elango@Sun.COM * 0x80 111010187SKrishna.Elango@Sun.COM */ 111110187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(parent_bus_p)) { 111210187SKrishna.Elango@Sun.COM bus_p->bus_rp_dip = pdip; 111310187SKrishna.Elango@Sun.COM bus_p->bus_rp_bdf = parent_bus_p->bus_bdf; 111410187SKrishna.Elango@Sun.COM break; 111510187SKrishna.Elango@Sun.COM } 111610187SKrishna.Elango@Sun.COM } 111710187SKrishna.Elango@Sun.COM } 111810187SKrishna.Elango@Sun.COM 111911245SZhijun.Fu@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED; 112011245SZhijun.Fu@Sun.COM bus_p->bus_fm_flags = 0; 112111245SZhijun.Fu@Sun.COM bus_p->bus_mps = 0; 112210187SKrishna.Elango@Sun.COM 112311245SZhijun.Fu@Sun.COM ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p); 112411245SZhijun.Fu@Sun.COM 112511245SZhijun.Fu@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip)) 112611245SZhijun.Fu@Sun.COM (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip, 112710923SEvan.Yan@Sun.COM "hotplug-capable"); 112810923SEvan.Yan@Sun.COM 112911245SZhijun.Fu@Sun.COM initial_done: 113011245SZhijun.Fu@Sun.COM if (!(flags & PCIE_BUS_FINAL)) 113111245SZhijun.Fu@Sun.COM goto final_done; 113211245SZhijun.Fu@Sun.COM 113311245SZhijun.Fu@Sun.COM /* already initialized? */ 113411245SZhijun.Fu@Sun.COM bus_p = PCIE_DIP2BUS(dip); 113511245SZhijun.Fu@Sun.COM 113611245SZhijun.Fu@Sun.COM /* Save the Range information if device is a switch/bridge */ 113711245SZhijun.Fu@Sun.COM if (PCIE_IS_BDG(bus_p)) { 113811245SZhijun.Fu@Sun.COM /* get "bus_range" property */ 113911245SZhijun.Fu@Sun.COM range_size = sizeof (pci_bus_range_t); 114011245SZhijun.Fu@Sun.COM if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 114111245SZhijun.Fu@Sun.COM "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size) 114211245SZhijun.Fu@Sun.COM != DDI_PROP_SUCCESS) { 114311245SZhijun.Fu@Sun.COM errstr = "Cannot find \"bus-range\" property"; 114411245SZhijun.Fu@Sun.COM cmn_err(CE_WARN, 114511245SZhijun.Fu@Sun.COM "PCIE init err info failed BDF 0x%x:%s\n", 114611245SZhijun.Fu@Sun.COM bus_p->bus_bdf, errstr); 114711245SZhijun.Fu@Sun.COM } 114811245SZhijun.Fu@Sun.COM 114911245SZhijun.Fu@Sun.COM /* get secondary bus number */ 115011245SZhijun.Fu@Sun.COM rcdip = pcie_get_rc_dip(dip); 115111245SZhijun.Fu@Sun.COM ASSERT(rcdip != NULL); 115210187SKrishna.Elango@Sun.COM 115311245SZhijun.Fu@Sun.COM bus_p->bus_bdg_secbus = pci_cfgacc_get8(rcdip, 115411245SZhijun.Fu@Sun.COM bus_p->bus_bdf, PCI_BCNF_SECBUS); 115511245SZhijun.Fu@Sun.COM 115611245SZhijun.Fu@Sun.COM /* Get "ranges" property */ 115711245SZhijun.Fu@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 115811245SZhijun.Fu@Sun.COM "ranges", (caddr_t)&bus_p->bus_addr_ranges, 115911245SZhijun.Fu@Sun.COM &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS) 116011245SZhijun.Fu@Sun.COM bus_p->bus_addr_entries = 0; 116111245SZhijun.Fu@Sun.COM bus_p->bus_addr_entries /= sizeof (ppb_ranges_t); 116211245SZhijun.Fu@Sun.COM } 116310187SKrishna.Elango@Sun.COM 116411245SZhijun.Fu@Sun.COM /* save "assigned-addresses" property array, ignore failues */ 116511245SZhijun.Fu@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 116611245SZhijun.Fu@Sun.COM "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr, 116711245SZhijun.Fu@Sun.COM &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS) 116811245SZhijun.Fu@Sun.COM bus_p->bus_assigned_entries /= sizeof (pci_regspec_t); 116911245SZhijun.Fu@Sun.COM else 117011245SZhijun.Fu@Sun.COM bus_p->bus_assigned_entries = 0; 117111245SZhijun.Fu@Sun.COM 117211245SZhijun.Fu@Sun.COM pcie_init_pfd(dip); 117311245SZhijun.Fu@Sun.COM 117411245SZhijun.Fu@Sun.COM pcie_init_plat(dip); 117511245SZhijun.Fu@Sun.COM 117611245SZhijun.Fu@Sun.COM final_done: 117710187SKrishna.Elango@Sun.COM 117810187SKrishna.Elango@Sun.COM PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n", 117911245SZhijun.Fu@Sun.COM ddi_driver_name(dip), (void *)dip, bus_p->bus_bdf, 118010187SKrishna.Elango@Sun.COM bus_p->bus_bdg_secbus); 118110187SKrishna.Elango@Sun.COM #ifdef DEBUG 118210187SKrishna.Elango@Sun.COM pcie_print_bus(bus_p); 118310187SKrishna.Elango@Sun.COM #endif 118410187SKrishna.Elango@Sun.COM 118510187SKrishna.Elango@Sun.COM return (bus_p); 118611245SZhijun.Fu@Sun.COM } 118711245SZhijun.Fu@Sun.COM 118811245SZhijun.Fu@Sun.COM /* 118911245SZhijun.Fu@Sun.COM * Invoked before destroying devinfo node, mostly during hotplug 119011245SZhijun.Fu@Sun.COM * operation to free pcie_bus_t data structure 119111245SZhijun.Fu@Sun.COM */ 119211245SZhijun.Fu@Sun.COM /* ARGSUSED */ 119311245SZhijun.Fu@Sun.COM void 119411245SZhijun.Fu@Sun.COM pcie_fini_bus(dev_info_t *dip, uint8_t flags) 119511245SZhijun.Fu@Sun.COM { 119611245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 119711245SZhijun.Fu@Sun.COM ASSERT(bus_p); 119811245SZhijun.Fu@Sun.COM 119911245SZhijun.Fu@Sun.COM if (flags & PCIE_BUS_INITIAL) { 120011245SZhijun.Fu@Sun.COM pcie_fini_plat(dip); 120111245SZhijun.Fu@Sun.COM pcie_fini_pfd(dip); 120211245SZhijun.Fu@Sun.COM 120311245SZhijun.Fu@Sun.COM kmem_free(bus_p->bus_assigned_addr, 120411245SZhijun.Fu@Sun.COM (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries)); 120511245SZhijun.Fu@Sun.COM kmem_free(bus_p->bus_addr_ranges, 120611245SZhijun.Fu@Sun.COM (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries)); 120711245SZhijun.Fu@Sun.COM /* zero out the fields that have been destroyed */ 120811245SZhijun.Fu@Sun.COM bus_p->bus_assigned_addr = NULL; 120911245SZhijun.Fu@Sun.COM bus_p->bus_addr_ranges = NULL; 121011245SZhijun.Fu@Sun.COM bus_p->bus_assigned_entries = 0; 121111245SZhijun.Fu@Sun.COM bus_p->bus_addr_entries = 0; 121211245SZhijun.Fu@Sun.COM } 121311245SZhijun.Fu@Sun.COM 121411245SZhijun.Fu@Sun.COM if (flags & PCIE_BUS_FINAL) { 121511245SZhijun.Fu@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip)) { 121611245SZhijun.Fu@Sun.COM (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, 121711245SZhijun.Fu@Sun.COM "hotplug-capable"); 121811245SZhijun.Fu@Sun.COM } 121911245SZhijun.Fu@Sun.COM 122011245SZhijun.Fu@Sun.COM ndi_set_bus_private(dip, B_TRUE, NULL, NULL); 122111245SZhijun.Fu@Sun.COM kmem_free(bus_p, sizeof (pcie_bus_t)); 122211245SZhijun.Fu@Sun.COM } 122310187SKrishna.Elango@Sun.COM } 122410187SKrishna.Elango@Sun.COM 122510187SKrishna.Elango@Sun.COM int 122610187SKrishna.Elango@Sun.COM pcie_postattach_child(dev_info_t *cdip) 122710187SKrishna.Elango@Sun.COM { 122810187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip); 122910187SKrishna.Elango@Sun.COM 123010187SKrishna.Elango@Sun.COM if (!bus_p) 123110187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 123210187SKrishna.Elango@Sun.COM 123310187SKrishna.Elango@Sun.COM return (pcie_enable_ce(cdip)); 123410187SKrishna.Elango@Sun.COM } 123510187SKrishna.Elango@Sun.COM 123610187SKrishna.Elango@Sun.COM /* 123710187SKrishna.Elango@Sun.COM * PCI-Express child device de-initialization. 123810187SKrishna.Elango@Sun.COM * This function disables generic pci-express interrupts and error 123910187SKrishna.Elango@Sun.COM * handling. 124010187SKrishna.Elango@Sun.COM */ 124110187SKrishna.Elango@Sun.COM void 124210187SKrishna.Elango@Sun.COM pcie_uninitchild(dev_info_t *cdip) 124310187SKrishna.Elango@Sun.COM { 124410187SKrishna.Elango@Sun.COM pcie_disable_errors(cdip); 124511245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(cdip); 124611596SJason.Beloro@Sun.COM pcie_fini_dom(cdip); 124711245SZhijun.Fu@Sun.COM } 124811245SZhijun.Fu@Sun.COM 124911245SZhijun.Fu@Sun.COM /* 125011245SZhijun.Fu@Sun.COM * find the root complex dip 125111245SZhijun.Fu@Sun.COM */ 125211245SZhijun.Fu@Sun.COM dev_info_t * 125311245SZhijun.Fu@Sun.COM pcie_get_rc_dip(dev_info_t *dip) 125411245SZhijun.Fu@Sun.COM { 125511245SZhijun.Fu@Sun.COM dev_info_t *rcdip; 125611245SZhijun.Fu@Sun.COM pcie_bus_t *rc_bus_p; 125711245SZhijun.Fu@Sun.COM 125811245SZhijun.Fu@Sun.COM for (rcdip = ddi_get_parent(dip); rcdip; 125911245SZhijun.Fu@Sun.COM rcdip = ddi_get_parent(rcdip)) { 126011245SZhijun.Fu@Sun.COM rc_bus_p = PCIE_DIP2BUS(rcdip); 126111245SZhijun.Fu@Sun.COM if (rc_bus_p && PCIE_IS_RC(rc_bus_p)) 126211245SZhijun.Fu@Sun.COM break; 126311245SZhijun.Fu@Sun.COM } 126411245SZhijun.Fu@Sun.COM 126511245SZhijun.Fu@Sun.COM return (rcdip); 126611245SZhijun.Fu@Sun.COM } 126711245SZhijun.Fu@Sun.COM 126811245SZhijun.Fu@Sun.COM static boolean_t 126911245SZhijun.Fu@Sun.COM pcie_is_pci_device(dev_info_t *dip) 127011245SZhijun.Fu@Sun.COM { 127111245SZhijun.Fu@Sun.COM dev_info_t *pdip; 127211245SZhijun.Fu@Sun.COM char *device_type; 127311245SZhijun.Fu@Sun.COM 127411245SZhijun.Fu@Sun.COM pdip = ddi_get_parent(dip); 127511245SZhijun.Fu@Sun.COM ASSERT(pdip); 127611245SZhijun.Fu@Sun.COM 127711245SZhijun.Fu@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 127811245SZhijun.Fu@Sun.COM "device_type", &device_type) != DDI_PROP_SUCCESS) 127911245SZhijun.Fu@Sun.COM return (B_FALSE); 128011245SZhijun.Fu@Sun.COM 128111245SZhijun.Fu@Sun.COM if (strcmp(device_type, "pciex") != 0 && 128211245SZhijun.Fu@Sun.COM strcmp(device_type, "pci") != 0) { 128311245SZhijun.Fu@Sun.COM ddi_prop_free(device_type); 128411245SZhijun.Fu@Sun.COM return (B_FALSE); 128511245SZhijun.Fu@Sun.COM } 128611245SZhijun.Fu@Sun.COM 128711245SZhijun.Fu@Sun.COM ddi_prop_free(device_type); 128811245SZhijun.Fu@Sun.COM return (B_TRUE); 128911245SZhijun.Fu@Sun.COM } 129011245SZhijun.Fu@Sun.COM 129111245SZhijun.Fu@Sun.COM typedef struct { 129211245SZhijun.Fu@Sun.COM boolean_t init; 129311245SZhijun.Fu@Sun.COM uint8_t flags; 129411245SZhijun.Fu@Sun.COM } pcie_bus_arg_t; 129511245SZhijun.Fu@Sun.COM 129611245SZhijun.Fu@Sun.COM /*ARGSUSED*/ 129711245SZhijun.Fu@Sun.COM static int 129811245SZhijun.Fu@Sun.COM pcie_fab_do_init_fini(dev_info_t *dip, void *arg) 129911245SZhijun.Fu@Sun.COM { 130011245SZhijun.Fu@Sun.COM pcie_req_id_t bdf; 130111245SZhijun.Fu@Sun.COM pcie_bus_arg_t *bus_arg = (pcie_bus_arg_t *)arg; 130211245SZhijun.Fu@Sun.COM 130311245SZhijun.Fu@Sun.COM if (!pcie_is_pci_device(dip)) 130411245SZhijun.Fu@Sun.COM goto out; 130511245SZhijun.Fu@Sun.COM 130611245SZhijun.Fu@Sun.COM if (bus_arg->init) { 130711245SZhijun.Fu@Sun.COM if (pcie_get_bdf_from_dip(dip, &bdf) != DDI_SUCCESS) 130811245SZhijun.Fu@Sun.COM goto out; 130911245SZhijun.Fu@Sun.COM 131011245SZhijun.Fu@Sun.COM (void) pcie_init_bus(dip, bdf, bus_arg->flags); 131111245SZhijun.Fu@Sun.COM } else { 131211245SZhijun.Fu@Sun.COM (void) pcie_fini_bus(dip, bus_arg->flags); 131311245SZhijun.Fu@Sun.COM } 131411245SZhijun.Fu@Sun.COM 131511245SZhijun.Fu@Sun.COM return (DDI_WALK_CONTINUE); 131611245SZhijun.Fu@Sun.COM 131711245SZhijun.Fu@Sun.COM out: 131811245SZhijun.Fu@Sun.COM return (DDI_WALK_PRUNECHILD); 131910187SKrishna.Elango@Sun.COM } 132010187SKrishna.Elango@Sun.COM 132110187SKrishna.Elango@Sun.COM void 132211245SZhijun.Fu@Sun.COM pcie_fab_init_bus(dev_info_t *rcdip, uint8_t flags) 132310187SKrishna.Elango@Sun.COM { 132411245SZhijun.Fu@Sun.COM int circular_count; 132511245SZhijun.Fu@Sun.COM dev_info_t *dip = ddi_get_child(rcdip); 132611245SZhijun.Fu@Sun.COM pcie_bus_arg_t arg; 132710187SKrishna.Elango@Sun.COM 132811245SZhijun.Fu@Sun.COM arg.init = B_TRUE; 132911245SZhijun.Fu@Sun.COM arg.flags = flags; 133010187SKrishna.Elango@Sun.COM 133111245SZhijun.Fu@Sun.COM ndi_devi_enter(rcdip, &circular_count); 133211245SZhijun.Fu@Sun.COM ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg); 133311245SZhijun.Fu@Sun.COM ndi_devi_exit(rcdip, circular_count); 133411245SZhijun.Fu@Sun.COM } 133510923SEvan.Yan@Sun.COM 133611245SZhijun.Fu@Sun.COM void 133711245SZhijun.Fu@Sun.COM pcie_fab_fini_bus(dev_info_t *rcdip, uint8_t flags) 133811245SZhijun.Fu@Sun.COM { 133911245SZhijun.Fu@Sun.COM int circular_count; 134011245SZhijun.Fu@Sun.COM dev_info_t *dip = ddi_get_child(rcdip); 134111245SZhijun.Fu@Sun.COM pcie_bus_arg_t arg; 134210923SEvan.Yan@Sun.COM 134311245SZhijun.Fu@Sun.COM arg.init = B_FALSE; 134411245SZhijun.Fu@Sun.COM arg.flags = flags; 134510187SKrishna.Elango@Sun.COM 134611245SZhijun.Fu@Sun.COM ndi_devi_enter(rcdip, &circular_count); 134711245SZhijun.Fu@Sun.COM ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg); 134811245SZhijun.Fu@Sun.COM ndi_devi_exit(rcdip, circular_count); 134910187SKrishna.Elango@Sun.COM } 135010187SKrishna.Elango@Sun.COM 135110187SKrishna.Elango@Sun.COM void 135210187SKrishna.Elango@Sun.COM pcie_enable_errors(dev_info_t *dip) 135310187SKrishna.Elango@Sun.COM { 135410187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 135510187SKrishna.Elango@Sun.COM uint16_t reg16, tmp16; 135610187SKrishna.Elango@Sun.COM uint32_t reg32, tmp32; 135710187SKrishna.Elango@Sun.COM 135810187SKrishna.Elango@Sun.COM ASSERT(bus_p); 135910187SKrishna.Elango@Sun.COM 136010187SKrishna.Elango@Sun.COM /* 136110187SKrishna.Elango@Sun.COM * Clear any pending errors 136210187SKrishna.Elango@Sun.COM */ 136310187SKrishna.Elango@Sun.COM pcie_clear_errors(dip); 136410187SKrishna.Elango@Sun.COM 136510187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 136610187SKrishna.Elango@Sun.COM return; 136710187SKrishna.Elango@Sun.COM 136810187SKrishna.Elango@Sun.COM /* 136910187SKrishna.Elango@Sun.COM * Enable Baseline Error Handling but leave CE reporting off (poweron 137010187SKrishna.Elango@Sun.COM * default). 137110187SKrishna.Elango@Sun.COM */ 137210187SKrishna.Elango@Sun.COM if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) != 137310187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 137410187SKrishna.Elango@Sun.COM tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK | 137510187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 137610187SKrishna.Elango@Sun.COM (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 137710187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 137810187SKrishna.Elango@Sun.COM (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN)); 137910187SKrishna.Elango@Sun.COM 138010187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16); 138110187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16); 138210187SKrishna.Elango@Sun.COM } 138310187SKrishna.Elango@Sun.COM 138410187SKrishna.Elango@Sun.COM /* Enable Root Port Baseline Error Receiving */ 138510187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p) && 138610187SKrishna.Elango@Sun.COM (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) != 138710187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 138810187SKrishna.Elango@Sun.COM 138910187SKrishna.Elango@Sun.COM tmp16 = pcie_serr_disable_flag ? 139010187SKrishna.Elango@Sun.COM (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) : 139110187SKrishna.Elango@Sun.COM pcie_root_ctrl_default; 139210187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16); 139310187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL, 139410187SKrishna.Elango@Sun.COM reg16); 139510187SKrishna.Elango@Sun.COM } 139610187SKrishna.Elango@Sun.COM 139710187SKrishna.Elango@Sun.COM /* 139810187SKrishna.Elango@Sun.COM * Enable PCI-Express Advanced Error Handling if Exists 139910187SKrishna.Elango@Sun.COM */ 140010187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 140110187SKrishna.Elango@Sun.COM return; 140210187SKrishna.Elango@Sun.COM 140310187SKrishna.Elango@Sun.COM /* Set Uncorrectable Severity */ 140410187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) != 140510187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 140610187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_uce_severity; 140710187SKrishna.Elango@Sun.COM 140810187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32); 140910187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV, 141010187SKrishna.Elango@Sun.COM reg32); 141110187SKrishna.Elango@Sun.COM } 141210187SKrishna.Elango@Sun.COM 141310187SKrishna.Elango@Sun.COM /* Enable Uncorrectable errors */ 141410187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) != 141510187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 141610187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_uce_mask; 141710187SKrishna.Elango@Sun.COM 141810187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32); 141910187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK, 142010187SKrishna.Elango@Sun.COM reg32); 142110187SKrishna.Elango@Sun.COM } 142210187SKrishna.Elango@Sun.COM 142310187SKrishna.Elango@Sun.COM /* Enable ECRC generation and checking */ 142410187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) != 142510187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 142610187SKrishna.Elango@Sun.COM tmp32 = reg32 | pcie_ecrc_value; 142710187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32); 142810187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32); 142910187SKrishna.Elango@Sun.COM } 143010187SKrishna.Elango@Sun.COM 143110187SKrishna.Elango@Sun.COM /* Enable Secondary Uncorrectable errors if this is a bridge */ 143210187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) 143310187SKrishna.Elango@Sun.COM goto root; 143410187SKrishna.Elango@Sun.COM 143510187SKrishna.Elango@Sun.COM /* Set Uncorrectable Severity */ 143610187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) != 143710187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 143810187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_suce_severity; 143910187SKrishna.Elango@Sun.COM 144010187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32); 144110187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV, 144210187SKrishna.Elango@Sun.COM reg32); 144310187SKrishna.Elango@Sun.COM } 144410187SKrishna.Elango@Sun.COM 144510187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) != 144610187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 144710187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask); 144810187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32, 144910187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MASK, reg32); 145010187SKrishna.Elango@Sun.COM } 145110187SKrishna.Elango@Sun.COM 145210187SKrishna.Elango@Sun.COM root: 145310187SKrishna.Elango@Sun.COM /* 145410187SKrishna.Elango@Sun.COM * Enable Root Control this is a Root device 145510187SKrishna.Elango@Sun.COM */ 145610187SKrishna.Elango@Sun.COM if (!PCIE_IS_ROOT(bus_p)) 145710187SKrishna.Elango@Sun.COM return; 145810187SKrishna.Elango@Sun.COM 145910187SKrishna.Elango@Sun.COM if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) != 146010187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 146110187SKrishna.Elango@Sun.COM PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD, 146210187SKrishna.Elango@Sun.COM pcie_root_error_cmd_default); 146310187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16, 146410187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD, reg16); 146510187SKrishna.Elango@Sun.COM } 146610187SKrishna.Elango@Sun.COM } 146710187SKrishna.Elango@Sun.COM 146810187SKrishna.Elango@Sun.COM /* 146910187SKrishna.Elango@Sun.COM * This function is used for enabling CE reporting and setting the AER CE mask. 147010187SKrishna.Elango@Sun.COM * When called from outside the pcie module it should always be preceded by 147110187SKrishna.Elango@Sun.COM * a call to pcie_enable_errors. 147210187SKrishna.Elango@Sun.COM */ 147310187SKrishna.Elango@Sun.COM int 147410187SKrishna.Elango@Sun.COM pcie_enable_ce(dev_info_t *dip) 147510187SKrishna.Elango@Sun.COM { 147610187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 147710187SKrishna.Elango@Sun.COM uint16_t device_sts, device_ctl; 147810187SKrishna.Elango@Sun.COM uint32_t tmp_pcie_aer_ce_mask; 147910187SKrishna.Elango@Sun.COM 148010187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 148110187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 148210187SKrishna.Elango@Sun.COM 148310187SKrishna.Elango@Sun.COM /* 148410187SKrishna.Elango@Sun.COM * The "pcie_ce_mask" property is used to control both the CE reporting 148510187SKrishna.Elango@Sun.COM * enable field in the device control register and the AER CE mask. We 148610187SKrishna.Elango@Sun.COM * leave CE reporting disabled if pcie_ce_mask is set to -1. 148710187SKrishna.Elango@Sun.COM */ 148810187SKrishna.Elango@Sun.COM 148910187SKrishna.Elango@Sun.COM tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 149010187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask); 149110187SKrishna.Elango@Sun.COM 149210187SKrishna.Elango@Sun.COM if (tmp_pcie_aer_ce_mask == (uint32_t)-1) { 149310187SKrishna.Elango@Sun.COM /* 149410187SKrishna.Elango@Sun.COM * Nothing to do since CE reporting has already been disabled. 149510187SKrishna.Elango@Sun.COM */ 149610187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 149710187SKrishna.Elango@Sun.COM } 149810187SKrishna.Elango@Sun.COM 149910187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(bus_p)) { 150010187SKrishna.Elango@Sun.COM /* Enable AER CE */ 150110187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask); 150210187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK, 150310187SKrishna.Elango@Sun.COM 0); 150410187SKrishna.Elango@Sun.COM 150510187SKrishna.Elango@Sun.COM /* Clear any pending AER CE errors */ 150610187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1); 150710187SKrishna.Elango@Sun.COM } 150810187SKrishna.Elango@Sun.COM 150910187SKrishna.Elango@Sun.COM /* clear any pending CE errors */ 151010187SKrishna.Elango@Sun.COM if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) != 151110187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) 151210187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS, 151310187SKrishna.Elango@Sun.COM device_sts & (~PCIE_DEVSTS_CE_DETECTED)); 151410187SKrishna.Elango@Sun.COM 151510187SKrishna.Elango@Sun.COM /* Enable CE reporting */ 151610187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 151710187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, 151810187SKrishna.Elango@Sun.COM (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default); 151910187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl); 152010187SKrishna.Elango@Sun.COM 152110187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 152210187SKrishna.Elango@Sun.COM } 152310187SKrishna.Elango@Sun.COM 152410187SKrishna.Elango@Sun.COM /* ARGSUSED */ 152510187SKrishna.Elango@Sun.COM void 152610187SKrishna.Elango@Sun.COM pcie_disable_errors(dev_info_t *dip) 152710187SKrishna.Elango@Sun.COM { 152810187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 152910187SKrishna.Elango@Sun.COM uint16_t device_ctl; 153010187SKrishna.Elango@Sun.COM uint32_t aer_reg; 153110187SKrishna.Elango@Sun.COM 153210187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p)) 153310187SKrishna.Elango@Sun.COM return; 153410187SKrishna.Elango@Sun.COM 153510187SKrishna.Elango@Sun.COM /* 153610187SKrishna.Elango@Sun.COM * Disable PCI-Express Baseline Error Handling 153710187SKrishna.Elango@Sun.COM */ 153810187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 153910187SKrishna.Elango@Sun.COM device_ctl &= ~PCIE_DEVCTL_ERR_MASK; 154010187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl); 154110187SKrishna.Elango@Sun.COM 154210187SKrishna.Elango@Sun.COM /* 154310187SKrishna.Elango@Sun.COM * Disable PCI-Express Advanced Error Handling if Exists 154410187SKrishna.Elango@Sun.COM */ 154510187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 154610187SKrishna.Elango@Sun.COM goto root; 154710187SKrishna.Elango@Sun.COM 154810187SKrishna.Elango@Sun.COM /* Disable Uncorrectable errors */ 154910187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS); 155010187SKrishna.Elango@Sun.COM 155110187SKrishna.Elango@Sun.COM /* Disable Correctable errors */ 155210187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS); 155310187SKrishna.Elango@Sun.COM 155410187SKrishna.Elango@Sun.COM /* Disable ECRC generation and checking */ 155510187SKrishna.Elango@Sun.COM if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) != 155610187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) { 155710187SKrishna.Elango@Sun.COM aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA | 155810187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_CHECK_ENA); 155910187SKrishna.Elango@Sun.COM 156010187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg); 156110187SKrishna.Elango@Sun.COM } 156210187SKrishna.Elango@Sun.COM /* 156310187SKrishna.Elango@Sun.COM * Disable Secondary Uncorrectable errors if this is a bridge 156410187SKrishna.Elango@Sun.COM */ 156510187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p)) 156610187SKrishna.Elango@Sun.COM goto root; 156710187SKrishna.Elango@Sun.COM 156810187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS); 156910187SKrishna.Elango@Sun.COM 157010187SKrishna.Elango@Sun.COM root: 157110187SKrishna.Elango@Sun.COM /* 157210187SKrishna.Elango@Sun.COM * disable Root Control this is a Root device 157310187SKrishna.Elango@Sun.COM */ 157410187SKrishna.Elango@Sun.COM if (!PCIE_IS_ROOT(bus_p)) 157510187SKrishna.Elango@Sun.COM return; 157610187SKrishna.Elango@Sun.COM 157710187SKrishna.Elango@Sun.COM if (!pcie_serr_disable_flag) { 157810187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL); 157910187SKrishna.Elango@Sun.COM device_ctl &= ~PCIE_ROOT_SYS_ERR; 158010187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl); 158110187SKrishna.Elango@Sun.COM } 158210187SKrishna.Elango@Sun.COM 158310187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p)) 158410187SKrishna.Elango@Sun.COM return; 158510187SKrishna.Elango@Sun.COM 158610187SKrishna.Elango@Sun.COM if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) != 158710187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) { 158810187SKrishna.Elango@Sun.COM device_ctl &= ~pcie_root_error_cmd_default; 158910187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl); 159010187SKrishna.Elango@Sun.COM } 159110187SKrishna.Elango@Sun.COM } 159210187SKrishna.Elango@Sun.COM 159310187SKrishna.Elango@Sun.COM /* 159410187SKrishna.Elango@Sun.COM * Extract bdf from "reg" property. 159510187SKrishna.Elango@Sun.COM */ 159610187SKrishna.Elango@Sun.COM int 159710187SKrishna.Elango@Sun.COM pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf) 159810187SKrishna.Elango@Sun.COM { 159910187SKrishna.Elango@Sun.COM pci_regspec_t *regspec; 160010187SKrishna.Elango@Sun.COM int reglen; 160110187SKrishna.Elango@Sun.COM 160210187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 160310187SKrishna.Elango@Sun.COM "reg", (int **)®spec, (uint_t *)®len) != DDI_SUCCESS) 160410187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 160510187SKrishna.Elango@Sun.COM 160610187SKrishna.Elango@Sun.COM if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) { 160710187SKrishna.Elango@Sun.COM ddi_prop_free(regspec); 160810187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 160910187SKrishna.Elango@Sun.COM } 161010187SKrishna.Elango@Sun.COM 161110187SKrishna.Elango@Sun.COM /* Get phys_hi from first element. All have same bdf. */ 161210187SKrishna.Elango@Sun.COM *bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8; 161310187SKrishna.Elango@Sun.COM 161410187SKrishna.Elango@Sun.COM ddi_prop_free(regspec); 161510187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 161610187SKrishna.Elango@Sun.COM } 161710187SKrishna.Elango@Sun.COM 161810187SKrishna.Elango@Sun.COM dev_info_t * 161910187SKrishna.Elango@Sun.COM pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 162010187SKrishna.Elango@Sun.COM { 162110187SKrishna.Elango@Sun.COM dev_info_t *cdip = rdip; 162210187SKrishna.Elango@Sun.COM 162310187SKrishna.Elango@Sun.COM for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 162410187SKrishna.Elango@Sun.COM ; 162510187SKrishna.Elango@Sun.COM 162610187SKrishna.Elango@Sun.COM return (cdip); 162710187SKrishna.Elango@Sun.COM } 162810187SKrishna.Elango@Sun.COM 162910187SKrishna.Elango@Sun.COM uint32_t 163010187SKrishna.Elango@Sun.COM pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip) 163110187SKrishna.Elango@Sun.COM { 163210187SKrishna.Elango@Sun.COM dev_info_t *cdip; 163310187SKrishna.Elango@Sun.COM 163410187SKrishna.Elango@Sun.COM /* 163510187SKrishna.Elango@Sun.COM * As part of the probing, the PCI fcode interpreter may setup a DMA 163610187SKrishna.Elango@Sun.COM * request if a given card has a fcode on it using dip and rdip of the 163710923SEvan.Yan@Sun.COM * hotplug connector i.e, dip and rdip of px/pcieb driver. In this 163810187SKrishna.Elango@Sun.COM * case, return a invalid value for the bdf since we cannot get to the 163910187SKrishna.Elango@Sun.COM * bdf value of the actual device which will be initiating this DMA. 164010187SKrishna.Elango@Sun.COM */ 164110187SKrishna.Elango@Sun.COM if (rdip == dip) 164210187SKrishna.Elango@Sun.COM return (PCIE_INVALID_BDF); 164310187SKrishna.Elango@Sun.COM 164410187SKrishna.Elango@Sun.COM cdip = pcie_get_my_childs_dip(dip, rdip); 164510187SKrishna.Elango@Sun.COM 164610187SKrishna.Elango@Sun.COM /* 164710187SKrishna.Elango@Sun.COM * For a given rdip, return the bdf value of dip's (px or pcieb) 164810187SKrishna.Elango@Sun.COM * immediate child or secondary bus-id if dip is a PCIe2PCI bridge. 164910187SKrishna.Elango@Sun.COM * 165010187SKrishna.Elango@Sun.COM * XXX - For now, return a invalid bdf value for all PCI and PCI-X 165110187SKrishna.Elango@Sun.COM * devices since this needs more work. 165210187SKrishna.Elango@Sun.COM */ 165310187SKrishna.Elango@Sun.COM return (PCI_GET_PCIE2PCI_SECBUS(cdip) ? 165410187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF : PCI_GET_BDF(cdip)); 165510187SKrishna.Elango@Sun.COM } 165610187SKrishna.Elango@Sun.COM 165710187SKrishna.Elango@Sun.COM uint32_t 165810187SKrishna.Elango@Sun.COM pcie_get_aer_uce_mask() { 165910187SKrishna.Elango@Sun.COM return (pcie_aer_uce_mask); 166010187SKrishna.Elango@Sun.COM } 166110187SKrishna.Elango@Sun.COM uint32_t 166210187SKrishna.Elango@Sun.COM pcie_get_aer_ce_mask() { 166310187SKrishna.Elango@Sun.COM return (pcie_aer_ce_mask); 166410187SKrishna.Elango@Sun.COM } 166510187SKrishna.Elango@Sun.COM uint32_t 166610187SKrishna.Elango@Sun.COM pcie_get_aer_suce_mask() { 166710187SKrishna.Elango@Sun.COM return (pcie_aer_suce_mask); 166810187SKrishna.Elango@Sun.COM } 166910187SKrishna.Elango@Sun.COM uint32_t 167010187SKrishna.Elango@Sun.COM pcie_get_serr_mask() { 167110187SKrishna.Elango@Sun.COM return (pcie_serr_disable_flag); 167210187SKrishna.Elango@Sun.COM } 167310187SKrishna.Elango@Sun.COM 167410187SKrishna.Elango@Sun.COM void 167510187SKrishna.Elango@Sun.COM pcie_set_aer_uce_mask(uint32_t mask) { 167610187SKrishna.Elango@Sun.COM pcie_aer_uce_mask = mask; 167710187SKrishna.Elango@Sun.COM if (mask & PCIE_AER_UCE_UR) 167810187SKrishna.Elango@Sun.COM pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN; 167910187SKrishna.Elango@Sun.COM else 168010187SKrishna.Elango@Sun.COM pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN; 168110187SKrishna.Elango@Sun.COM 168210187SKrishna.Elango@Sun.COM if (mask & PCIE_AER_UCE_ECRC) 168310187SKrishna.Elango@Sun.COM pcie_ecrc_value = 0; 168410187SKrishna.Elango@Sun.COM } 168510187SKrishna.Elango@Sun.COM 168610187SKrishna.Elango@Sun.COM void 168710187SKrishna.Elango@Sun.COM pcie_set_aer_ce_mask(uint32_t mask) { 168810187SKrishna.Elango@Sun.COM pcie_aer_ce_mask = mask; 168910187SKrishna.Elango@Sun.COM } 169010187SKrishna.Elango@Sun.COM void 169110187SKrishna.Elango@Sun.COM pcie_set_aer_suce_mask(uint32_t mask) { 169210187SKrishna.Elango@Sun.COM pcie_aer_suce_mask = mask; 169310187SKrishna.Elango@Sun.COM } 169410187SKrishna.Elango@Sun.COM void 169510187SKrishna.Elango@Sun.COM pcie_set_serr_mask(uint32_t mask) { 169610187SKrishna.Elango@Sun.COM pcie_serr_disable_flag = mask; 169710187SKrishna.Elango@Sun.COM } 169810187SKrishna.Elango@Sun.COM 169910187SKrishna.Elango@Sun.COM /* 170010187SKrishna.Elango@Sun.COM * Is the rdip a child of dip. Used for checking certain CTLOPS from bubbling 170110187SKrishna.Elango@Sun.COM * up erronously. Ex. ISA ctlops to a PCI-PCI Bridge. 170210187SKrishna.Elango@Sun.COM */ 170310187SKrishna.Elango@Sun.COM boolean_t 170410187SKrishna.Elango@Sun.COM pcie_is_child(dev_info_t *dip, dev_info_t *rdip) 170510187SKrishna.Elango@Sun.COM { 170610187SKrishna.Elango@Sun.COM dev_info_t *cdip = ddi_get_child(dip); 170710187SKrishna.Elango@Sun.COM for (; cdip; cdip = ddi_get_next_sibling(cdip)) 170810187SKrishna.Elango@Sun.COM if (cdip == rdip) 170910187SKrishna.Elango@Sun.COM break; 171010187SKrishna.Elango@Sun.COM return (cdip != NULL); 171110187SKrishna.Elango@Sun.COM } 171210187SKrishna.Elango@Sun.COM 171310187SKrishna.Elango@Sun.COM boolean_t 171410187SKrishna.Elango@Sun.COM pcie_is_link_disabled(dev_info_t *dip) 171510187SKrishna.Elango@Sun.COM { 171610187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 171710187SKrishna.Elango@Sun.COM 171810187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 171910187SKrishna.Elango@Sun.COM if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) & 172010187SKrishna.Elango@Sun.COM PCIE_LINKCTL_LINK_DISABLE) 172110187SKrishna.Elango@Sun.COM return (B_TRUE); 172210187SKrishna.Elango@Sun.COM } 172310187SKrishna.Elango@Sun.COM return (B_FALSE); 172410187SKrishna.Elango@Sun.COM } 172510187SKrishna.Elango@Sun.COM 172610187SKrishna.Elango@Sun.COM /* 172710187SKrishna.Elango@Sun.COM * Initialize the MPS for a root port. 172810187SKrishna.Elango@Sun.COM * 172910187SKrishna.Elango@Sun.COM * dip - dip of root port device. 173010187SKrishna.Elango@Sun.COM */ 173110187SKrishna.Elango@Sun.COM void 173210187SKrishna.Elango@Sun.COM pcie_init_root_port_mps(dev_info_t *dip) 173310187SKrishna.Elango@Sun.COM { 173410187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 173510187SKrishna.Elango@Sun.COM int rp_cap, max_supported = pcie_max_mps; 173610187SKrishna.Elango@Sun.COM 173710187SKrishna.Elango@Sun.COM (void) pcie_get_fabric_mps(ddi_get_parent(dip), 173810187SKrishna.Elango@Sun.COM ddi_get_child(dip), &max_supported); 173910187SKrishna.Elango@Sun.COM 174010187SKrishna.Elango@Sun.COM rp_cap = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL, 174110187SKrishna.Elango@Sun.COM bus_p->bus_pcie_off, PCIE_DEVCAP) & 174210187SKrishna.Elango@Sun.COM PCIE_DEVCAP_MAX_PAYLOAD_MASK; 174310187SKrishna.Elango@Sun.COM 174410187SKrishna.Elango@Sun.COM if (rp_cap < max_supported) 174510187SKrishna.Elango@Sun.COM max_supported = rp_cap; 174610187SKrishna.Elango@Sun.COM 174710187SKrishna.Elango@Sun.COM bus_p->bus_mps = max_supported; 174810187SKrishna.Elango@Sun.COM (void) pcie_initchild_mps(dip); 174910187SKrishna.Elango@Sun.COM } 175010187SKrishna.Elango@Sun.COM 175110187SKrishna.Elango@Sun.COM /* 175210187SKrishna.Elango@Sun.COM * Initialize the Maximum Payload Size of a device. 175310187SKrishna.Elango@Sun.COM * 175410187SKrishna.Elango@Sun.COM * cdip - dip of device. 175510187SKrishna.Elango@Sun.COM * 175610187SKrishna.Elango@Sun.COM * returns - DDI_SUCCESS or DDI_FAILURE 175710187SKrishna.Elango@Sun.COM */ 175810187SKrishna.Elango@Sun.COM int 175910187SKrishna.Elango@Sun.COM pcie_initchild_mps(dev_info_t *cdip) 176010187SKrishna.Elango@Sun.COM { 176110187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p; 176210187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(cdip); 176310923SEvan.Yan@Sun.COM uint8_t dev_type; 176410187SKrishna.Elango@Sun.COM 176510187SKrishna.Elango@Sun.COM bus_p = PCIE_DIP2BUS(cdip); 176610187SKrishna.Elango@Sun.COM if (bus_p == NULL) { 176710187SKrishna.Elango@Sun.COM PCIE_DBG("%s: BUS not found.\n", 176810187SKrishna.Elango@Sun.COM ddi_driver_name(cdip)); 176910187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 177010187SKrishna.Elango@Sun.COM } 177110187SKrishna.Elango@Sun.COM 177210923SEvan.Yan@Sun.COM dev_type = bus_p->bus_dev_type; 177310923SEvan.Yan@Sun.COM 177410923SEvan.Yan@Sun.COM /* 177510923SEvan.Yan@Sun.COM * For ARI Devices, only function zero's MPS needs to be set. 177610923SEvan.Yan@Sun.COM */ 177710923SEvan.Yan@Sun.COM if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) && 177810923SEvan.Yan@Sun.COM (pcie_ari_is_enabled(pdip) == PCIE_ARI_FORW_ENABLED)) { 177910923SEvan.Yan@Sun.COM pcie_req_id_t child_bdf; 178010923SEvan.Yan@Sun.COM 178110923SEvan.Yan@Sun.COM if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE) 178210923SEvan.Yan@Sun.COM return (DDI_FAILURE); 178310923SEvan.Yan@Sun.COM if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) != 0) 178410923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 178510923SEvan.Yan@Sun.COM } 178610923SEvan.Yan@Sun.COM 178712059SAlan.Adamson@Sun.COM if (PCIE_IS_PCIE(bus_p)) { 178812059SAlan.Adamson@Sun.COM int suggested_mrrs, fabric_mps; 178912059SAlan.Adamson@Sun.COM uint16_t device_mps, device_mps_cap, device_mrrs, dev_ctrl; 179010187SKrishna.Elango@Sun.COM 1791*12330SDaniel.Ice@Sun.COM dev_ctrl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 179212059SAlan.Adamson@Sun.COM if ((fabric_mps = (PCIE_IS_RP(bus_p) ? bus_p : 1793*12330SDaniel.Ice@Sun.COM PCIE_DIP2BUS(pdip))->bus_mps) < 0) { 1794*12330SDaniel.Ice@Sun.COM dev_ctrl = (dev_ctrl & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 1795*12330SDaniel.Ice@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 1796*12330SDaniel.Ice@Sun.COM (pcie_devctl_default & 1797*12330SDaniel.Ice@Sun.COM (PCIE_DEVCTL_MAX_READ_REQ_MASK | 1798*12330SDaniel.Ice@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)); 1799*12330SDaniel.Ice@Sun.COM 1800*12330SDaniel.Ice@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl); 180112059SAlan.Adamson@Sun.COM return (DDI_SUCCESS); 1802*12330SDaniel.Ice@Sun.COM } 180312059SAlan.Adamson@Sun.COM 180412059SAlan.Adamson@Sun.COM device_mps_cap = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) & 180510187SKrishna.Elango@Sun.COM PCIE_DEVCAP_MAX_PAYLOAD_MASK; 180610187SKrishna.Elango@Sun.COM 180712059SAlan.Adamson@Sun.COM device_mrrs = (dev_ctrl & PCIE_DEVCTL_MAX_READ_REQ_MASK) >> 180812059SAlan.Adamson@Sun.COM PCIE_DEVCTL_MAX_READ_REQ_SHIFT; 180912059SAlan.Adamson@Sun.COM 181012059SAlan.Adamson@Sun.COM if (device_mps_cap < fabric_mps) 181112059SAlan.Adamson@Sun.COM device_mrrs = device_mps = device_mps_cap; 181212059SAlan.Adamson@Sun.COM else 181312059SAlan.Adamson@Sun.COM device_mps = (uint16_t)fabric_mps; 181412059SAlan.Adamson@Sun.COM 181512059SAlan.Adamson@Sun.COM suggested_mrrs = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, 181612059SAlan.Adamson@Sun.COM cdip, DDI_PROP_DONTPASS, "suggested-mrrs", device_mrrs); 181712059SAlan.Adamson@Sun.COM 181812059SAlan.Adamson@Sun.COM if ((device_mps == fabric_mps) || 181912059SAlan.Adamson@Sun.COM (suggested_mrrs < device_mrrs)) 182012059SAlan.Adamson@Sun.COM device_mrrs = (uint16_t)suggested_mrrs; 182110187SKrishna.Elango@Sun.COM 182210187SKrishna.Elango@Sun.COM /* 182312059SAlan.Adamson@Sun.COM * Replace MPS and MRRS settings. 182410187SKrishna.Elango@Sun.COM */ 182512059SAlan.Adamson@Sun.COM dev_ctrl &= ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 182612059SAlan.Adamson@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK); 182710187SKrishna.Elango@Sun.COM 182812059SAlan.Adamson@Sun.COM dev_ctrl |= ((device_mrrs << PCIE_DEVCTL_MAX_READ_REQ_SHIFT) | 182912059SAlan.Adamson@Sun.COM device_mps << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT); 183010187SKrishna.Elango@Sun.COM 183110187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl); 183210187SKrishna.Elango@Sun.COM 183312059SAlan.Adamson@Sun.COM bus_p->bus_mps = device_mps; 183410187SKrishna.Elango@Sun.COM } 183510923SEvan.Yan@Sun.COM 183610187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 183710187SKrishna.Elango@Sun.COM } 183810187SKrishna.Elango@Sun.COM 183910187SKrishna.Elango@Sun.COM /* 184010187SKrishna.Elango@Sun.COM * Scans a device tree/branch for a maximum payload size capabilities. 184110187SKrishna.Elango@Sun.COM * 184210187SKrishna.Elango@Sun.COM * rc_dip - dip of Root Complex. 184310187SKrishna.Elango@Sun.COM * dip - dip of device where scan will begin. 184410187SKrishna.Elango@Sun.COM * max_supported (IN) - maximum allowable MPS. 184510187SKrishna.Elango@Sun.COM * max_supported (OUT) - maximum payload size capability of fabric. 184610187SKrishna.Elango@Sun.COM */ 184710187SKrishna.Elango@Sun.COM void 184810187SKrishna.Elango@Sun.COM pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported) 184910187SKrishna.Elango@Sun.COM { 185010187SKrishna.Elango@Sun.COM if (dip == NULL) 185110187SKrishna.Elango@Sun.COM return; 185210187SKrishna.Elango@Sun.COM 185310187SKrishna.Elango@Sun.COM /* 185410187SKrishna.Elango@Sun.COM * Perform a fabric scan to obtain Maximum Payload Capabilities 185510187SKrishna.Elango@Sun.COM */ 185610187SKrishna.Elango@Sun.COM (void) pcie_scan_mps(rc_dip, dip, max_supported); 185710187SKrishna.Elango@Sun.COM 185810187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: Highest Common MPS= %x\n", max_supported); 185910187SKrishna.Elango@Sun.COM } 186010187SKrishna.Elango@Sun.COM 186110187SKrishna.Elango@Sun.COM /* 186210187SKrishna.Elango@Sun.COM * Scans fabric and determines Maximum Payload Size based on 186310187SKrishna.Elango@Sun.COM * highest common denominator alogorithm 186410187SKrishna.Elango@Sun.COM */ 186510187SKrishna.Elango@Sun.COM static void 186610187SKrishna.Elango@Sun.COM pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported) 186710187SKrishna.Elango@Sun.COM { 186810187SKrishna.Elango@Sun.COM int circular_count; 186910187SKrishna.Elango@Sun.COM pcie_max_supported_t max_pay_load_supported; 187010187SKrishna.Elango@Sun.COM 187110187SKrishna.Elango@Sun.COM max_pay_load_supported.dip = rc_dip; 187210187SKrishna.Elango@Sun.COM max_pay_load_supported.highest_common_mps = *max_supported; 187310187SKrishna.Elango@Sun.COM 187410187SKrishna.Elango@Sun.COM ndi_devi_enter(ddi_get_parent(dip), &circular_count); 187510187SKrishna.Elango@Sun.COM ddi_walk_devs(dip, pcie_get_max_supported, 187610187SKrishna.Elango@Sun.COM (void *)&max_pay_load_supported); 187710187SKrishna.Elango@Sun.COM ndi_devi_exit(ddi_get_parent(dip), circular_count); 187810923SEvan.Yan@Sun.COM 187910187SKrishna.Elango@Sun.COM *max_supported = max_pay_load_supported.highest_common_mps; 188010187SKrishna.Elango@Sun.COM } 188110187SKrishna.Elango@Sun.COM 188210187SKrishna.Elango@Sun.COM /* 188310187SKrishna.Elango@Sun.COM * Called as part of the Maximum Payload Size scan. 188410187SKrishna.Elango@Sun.COM */ 188510187SKrishna.Elango@Sun.COM static int 188610187SKrishna.Elango@Sun.COM pcie_get_max_supported(dev_info_t *dip, void *arg) 188710187SKrishna.Elango@Sun.COM { 188810187SKrishna.Elango@Sun.COM uint32_t max_supported; 188910187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 189010187SKrishna.Elango@Sun.COM pcie_max_supported_t *current = (pcie_max_supported_t *)arg; 189110187SKrishna.Elango@Sun.COM pci_regspec_t *reg; 189210187SKrishna.Elango@Sun.COM int rlen; 189310187SKrishna.Elango@Sun.COM caddr_t virt; 189410187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle; 189510187SKrishna.Elango@Sun.COM 189610187SKrishna.Elango@Sun.COM if (ddi_get_child(current->dip) == NULL) { 189710187SKrishna.Elango@Sun.COM goto fail1; 189810187SKrishna.Elango@Sun.COM } 189910187SKrishna.Elango@Sun.COM 190010187SKrishna.Elango@Sun.COM if (pcie_dev(dip) == DDI_FAILURE) { 190110187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: " 190210187SKrishna.Elango@Sun.COM "Not a PCIe dev\n", ddi_driver_name(dip)); 190310187SKrishna.Elango@Sun.COM goto fail1; 190410187SKrishna.Elango@Sun.COM } 190510187SKrishna.Elango@Sun.COM 190612059SAlan.Adamson@Sun.COM /* 190712059SAlan.Adamson@Sun.COM * If the suggested-mrrs property exists, then don't include this 190812059SAlan.Adamson@Sun.COM * device in the MPS capabilities scan. 190912059SAlan.Adamson@Sun.COM */ 191012059SAlan.Adamson@Sun.COM if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 191112059SAlan.Adamson@Sun.COM "suggested-mrrs") != 0) 191212059SAlan.Adamson@Sun.COM goto fail1; 191312059SAlan.Adamson@Sun.COM 191410187SKrishna.Elango@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 191510187SKrishna.Elango@Sun.COM (caddr_t)®, &rlen) != DDI_PROP_SUCCESS) { 191610187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: " 191710187SKrishna.Elango@Sun.COM "Can not read reg\n", ddi_driver_name(dip)); 191810187SKrishna.Elango@Sun.COM goto fail1; 191910187SKrishna.Elango@Sun.COM } 192010187SKrishna.Elango@Sun.COM 192110187SKrishna.Elango@Sun.COM if (pcie_map_phys(ddi_get_child(current->dip), reg, &virt, 192210187SKrishna.Elango@Sun.COM &config_handle) != DDI_SUCCESS) { 192310187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: pcie_map_phys " 192410187SKrishna.Elango@Sun.COM "failed\n", ddi_driver_name(dip)); 192510187SKrishna.Elango@Sun.COM goto fail2; 192610187SKrishna.Elango@Sun.COM } 192710187SKrishna.Elango@Sun.COM 192810187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) == 192910187SKrishna.Elango@Sun.COM DDI_FAILURE) { 193010187SKrishna.Elango@Sun.COM goto fail3; 193110187SKrishna.Elango@Sun.COM } 193210187SKrishna.Elango@Sun.COM 193310187SKrishna.Elango@Sun.COM max_supported = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 193410187SKrishna.Elango@Sun.COM PCIE_DEVCAP) & PCIE_DEVCAP_MAX_PAYLOAD_MASK; 193510187SKrishna.Elango@Sun.COM 193610187SKrishna.Elango@Sun.COM PCIE_DBG("PCIE MPS: %s: MPS Capabilities %x\n", ddi_driver_name(dip), 193710187SKrishna.Elango@Sun.COM max_supported); 193810187SKrishna.Elango@Sun.COM 193910187SKrishna.Elango@Sun.COM if (max_supported < current->highest_common_mps) 194010187SKrishna.Elango@Sun.COM current->highest_common_mps = max_supported; 194110187SKrishna.Elango@Sun.COM 194210187SKrishna.Elango@Sun.COM fail3: 194310187SKrishna.Elango@Sun.COM pcie_unmap_phys(&config_handle, reg); 194410187SKrishna.Elango@Sun.COM fail2: 194510187SKrishna.Elango@Sun.COM kmem_free(reg, rlen); 194610187SKrishna.Elango@Sun.COM fail1: 194710187SKrishna.Elango@Sun.COM return (DDI_WALK_CONTINUE); 194810187SKrishna.Elango@Sun.COM } 194910187SKrishna.Elango@Sun.COM 195010187SKrishna.Elango@Sun.COM /* 195110187SKrishna.Elango@Sun.COM * Determines if there are any root ports attached to a root complex. 195210187SKrishna.Elango@Sun.COM * 195310187SKrishna.Elango@Sun.COM * dip - dip of root complex 195410187SKrishna.Elango@Sun.COM * 195510187SKrishna.Elango@Sun.COM * Returns - DDI_SUCCESS if there is at least one root port otherwise 195610923SEvan.Yan@Sun.COM * DDI_FAILURE. 195710187SKrishna.Elango@Sun.COM */ 195810187SKrishna.Elango@Sun.COM int 195910187SKrishna.Elango@Sun.COM pcie_root_port(dev_info_t *dip) 196010187SKrishna.Elango@Sun.COM { 196110187SKrishna.Elango@Sun.COM int port_type; 196210187SKrishna.Elango@Sun.COM uint16_t cap_ptr; 196310187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle; 196410187SKrishna.Elango@Sun.COM dev_info_t *cdip = ddi_get_child(dip); 196510187SKrishna.Elango@Sun.COM 196610187SKrishna.Elango@Sun.COM /* 196710187SKrishna.Elango@Sun.COM * Determine if any of the children of the passed in dip 196810187SKrishna.Elango@Sun.COM * are root ports. 196910187SKrishna.Elango@Sun.COM */ 197010187SKrishna.Elango@Sun.COM for (; cdip; cdip = ddi_get_next_sibling(cdip)) { 197110187SKrishna.Elango@Sun.COM 197210187SKrishna.Elango@Sun.COM if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS) 197310187SKrishna.Elango@Sun.COM continue; 197410187SKrishna.Elango@Sun.COM 197510187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, 197610187SKrishna.Elango@Sun.COM &cap_ptr)) == DDI_FAILURE) { 197710187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle); 197810187SKrishna.Elango@Sun.COM continue; 197910187SKrishna.Elango@Sun.COM } 198010187SKrishna.Elango@Sun.COM 198110187SKrishna.Elango@Sun.COM port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 198210187SKrishna.Elango@Sun.COM PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 198310187SKrishna.Elango@Sun.COM 198410187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle); 198510187SKrishna.Elango@Sun.COM 198610187SKrishna.Elango@Sun.COM if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) 198710187SKrishna.Elango@Sun.COM return (DDI_SUCCESS); 198810187SKrishna.Elango@Sun.COM } 198910187SKrishna.Elango@Sun.COM 199010187SKrishna.Elango@Sun.COM /* No root ports were found */ 199110187SKrishna.Elango@Sun.COM 199210187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 199310187SKrishna.Elango@Sun.COM } 199410187SKrishna.Elango@Sun.COM 199510187SKrishna.Elango@Sun.COM /* 199610187SKrishna.Elango@Sun.COM * Function that determines if a device a PCIe device. 199710187SKrishna.Elango@Sun.COM * 199810187SKrishna.Elango@Sun.COM * dip - dip of device. 199910187SKrishna.Elango@Sun.COM * 200010187SKrishna.Elango@Sun.COM * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE. 200110187SKrishna.Elango@Sun.COM */ 200210187SKrishna.Elango@Sun.COM int 200310187SKrishna.Elango@Sun.COM pcie_dev(dev_info_t *dip) 200410187SKrishna.Elango@Sun.COM { 200510187SKrishna.Elango@Sun.COM /* get parent device's device_type property */ 200610187SKrishna.Elango@Sun.COM char *device_type; 200710187SKrishna.Elango@Sun.COM int rc = DDI_FAILURE; 200810187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(dip); 200910187SKrishna.Elango@Sun.COM 201010187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 201110187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "device_type", &device_type) 201210187SKrishna.Elango@Sun.COM != DDI_PROP_SUCCESS) { 201310187SKrishna.Elango@Sun.COM return (DDI_FAILURE); 201410187SKrishna.Elango@Sun.COM } 201510187SKrishna.Elango@Sun.COM 201610187SKrishna.Elango@Sun.COM if (strcmp(device_type, "pciex") == 0) 201710187SKrishna.Elango@Sun.COM rc = DDI_SUCCESS; 201810187SKrishna.Elango@Sun.COM else 201910187SKrishna.Elango@Sun.COM rc = DDI_FAILURE; 202010187SKrishna.Elango@Sun.COM 202110187SKrishna.Elango@Sun.COM ddi_prop_free(device_type); 202210187SKrishna.Elango@Sun.COM return (rc); 202310187SKrishna.Elango@Sun.COM } 202410187SKrishna.Elango@Sun.COM 202510187SKrishna.Elango@Sun.COM /* 202610187SKrishna.Elango@Sun.COM * Function to map in a device's memory space. 202710187SKrishna.Elango@Sun.COM */ 202810187SKrishna.Elango@Sun.COM static int 202910187SKrishna.Elango@Sun.COM pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 203010187SKrishna.Elango@Sun.COM caddr_t *addrp, ddi_acc_handle_t *handlep) 203110187SKrishna.Elango@Sun.COM { 203210187SKrishna.Elango@Sun.COM ddi_map_req_t mr; 203310187SKrishna.Elango@Sun.COM ddi_acc_hdl_t *hp; 203410187SKrishna.Elango@Sun.COM int result; 203510187SKrishna.Elango@Sun.COM ddi_device_acc_attr_t attr; 203610187SKrishna.Elango@Sun.COM 203710187SKrishna.Elango@Sun.COM attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 203810187SKrishna.Elango@Sun.COM attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 203910187SKrishna.Elango@Sun.COM attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 204010187SKrishna.Elango@Sun.COM attr.devacc_attr_access = DDI_CAUTIOUS_ACC; 204110187SKrishna.Elango@Sun.COM 204210187SKrishna.Elango@Sun.COM *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 204310187SKrishna.Elango@Sun.COM hp = impl_acc_hdl_get(*handlep); 204410187SKrishna.Elango@Sun.COM hp->ah_vers = VERS_ACCHDL; 204510187SKrishna.Elango@Sun.COM hp->ah_dip = dip; 204610187SKrishna.Elango@Sun.COM hp->ah_rnumber = 0; 204710187SKrishna.Elango@Sun.COM hp->ah_offset = 0; 204810187SKrishna.Elango@Sun.COM hp->ah_len = 0; 204910187SKrishna.Elango@Sun.COM hp->ah_acc = attr; 205010187SKrishna.Elango@Sun.COM 205110187SKrishna.Elango@Sun.COM mr.map_op = DDI_MO_MAP_LOCKED; 205210187SKrishna.Elango@Sun.COM mr.map_type = DDI_MT_REGSPEC; 205310187SKrishna.Elango@Sun.COM mr.map_obj.rp = (struct regspec *)phys_spec; 205410187SKrishna.Elango@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE; 205510187SKrishna.Elango@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING; 205610187SKrishna.Elango@Sun.COM mr.map_handlep = hp; 205710187SKrishna.Elango@Sun.COM mr.map_vers = DDI_MAP_VERSION; 205810187SKrishna.Elango@Sun.COM 205910187SKrishna.Elango@Sun.COM result = ddi_map(dip, &mr, 0, 0, addrp); 206010187SKrishna.Elango@Sun.COM 206110187SKrishna.Elango@Sun.COM if (result != DDI_SUCCESS) { 206210187SKrishna.Elango@Sun.COM impl_acc_hdl_free(*handlep); 206310187SKrishna.Elango@Sun.COM *handlep = (ddi_acc_handle_t)NULL; 206410187SKrishna.Elango@Sun.COM } else { 206510187SKrishna.Elango@Sun.COM hp->ah_addr = *addrp; 206610187SKrishna.Elango@Sun.COM } 206710187SKrishna.Elango@Sun.COM 206810187SKrishna.Elango@Sun.COM return (result); 206910187SKrishna.Elango@Sun.COM } 207010187SKrishna.Elango@Sun.COM 207110187SKrishna.Elango@Sun.COM /* 207210187SKrishna.Elango@Sun.COM * Map out memory that was mapped in with pcie_map_phys(); 207310187SKrishna.Elango@Sun.COM */ 207410187SKrishna.Elango@Sun.COM static void 207510187SKrishna.Elango@Sun.COM pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph) 207610187SKrishna.Elango@Sun.COM { 207710187SKrishna.Elango@Sun.COM ddi_map_req_t mr; 207810187SKrishna.Elango@Sun.COM ddi_acc_hdl_t *hp; 207910187SKrishna.Elango@Sun.COM 208010187SKrishna.Elango@Sun.COM hp = impl_acc_hdl_get(*handlep); 208110187SKrishna.Elango@Sun.COM ASSERT(hp); 208210187SKrishna.Elango@Sun.COM 208310187SKrishna.Elango@Sun.COM mr.map_op = DDI_MO_UNMAP; 208410187SKrishna.Elango@Sun.COM mr.map_type = DDI_MT_REGSPEC; 208510187SKrishna.Elango@Sun.COM mr.map_obj.rp = (struct regspec *)ph; 208610187SKrishna.Elango@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE; 208710187SKrishna.Elango@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING; 208810187SKrishna.Elango@Sun.COM mr.map_handlep = hp; 208910187SKrishna.Elango@Sun.COM mr.map_vers = DDI_MAP_VERSION; 209010187SKrishna.Elango@Sun.COM 209110187SKrishna.Elango@Sun.COM (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 209210187SKrishna.Elango@Sun.COM hp->ah_len, &hp->ah_addr); 209310187SKrishna.Elango@Sun.COM 209410187SKrishna.Elango@Sun.COM impl_acc_hdl_free(*handlep); 209510187SKrishna.Elango@Sun.COM *handlep = (ddi_acc_handle_t)NULL; 209610187SKrishna.Elango@Sun.COM } 209710187SKrishna.Elango@Sun.COM 209810187SKrishna.Elango@Sun.COM void 209910187SKrishna.Elango@Sun.COM pcie_set_rber_fatal(dev_info_t *dip, boolean_t val) 210010187SKrishna.Elango@Sun.COM { 210110187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 210210187SKrishna.Elango@Sun.COM bus_p->bus_pfd->pe_rber_fatal = val; 210310187SKrishna.Elango@Sun.COM } 210410187SKrishna.Elango@Sun.COM 210510187SKrishna.Elango@Sun.COM /* 210610187SKrishna.Elango@Sun.COM * Return parent Root Port's pe_rber_fatal value. 210710187SKrishna.Elango@Sun.COM */ 210810187SKrishna.Elango@Sun.COM boolean_t 210910187SKrishna.Elango@Sun.COM pcie_get_rber_fatal(dev_info_t *dip) 211010187SKrishna.Elango@Sun.COM { 211110187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 211210187SKrishna.Elango@Sun.COM pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip); 211310187SKrishna.Elango@Sun.COM return (rp_bus_p->bus_pfd->pe_rber_fatal); 211410187SKrishna.Elango@Sun.COM } 211510187SKrishna.Elango@Sun.COM 211610923SEvan.Yan@Sun.COM int 211710923SEvan.Yan@Sun.COM pcie_ari_supported(dev_info_t *dip) 211810923SEvan.Yan@Sun.COM { 211910923SEvan.Yan@Sun.COM uint32_t devcap2; 212010923SEvan.Yan@Sun.COM uint16_t pciecap; 212110923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 212210923SEvan.Yan@Sun.COM uint8_t dev_type; 212310923SEvan.Yan@Sun.COM 212410923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p\n", dip); 212510923SEvan.Yan@Sun.COM 212610923SEvan.Yan@Sun.COM if (bus_p == NULL) 212710923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 212810923SEvan.Yan@Sun.COM 212910923SEvan.Yan@Sun.COM dev_type = bus_p->bus_dev_type; 213010923SEvan.Yan@Sun.COM 213110923SEvan.Yan@Sun.COM if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) && 213210923SEvan.Yan@Sun.COM (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT)) 213310923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 213410923SEvan.Yan@Sun.COM 213510923SEvan.Yan@Sun.COM if (pcie_disable_ari) { 213610923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip); 213710923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 213810923SEvan.Yan@Sun.COM } 213910923SEvan.Yan@Sun.COM 214010923SEvan.Yan@Sun.COM pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP); 214110923SEvan.Yan@Sun.COM 214210923SEvan.Yan@Sun.COM if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) { 214310923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip); 214410923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 214510923SEvan.Yan@Sun.COM } 214610923SEvan.Yan@Sun.COM 214710923SEvan.Yan@Sun.COM devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2); 214810923SEvan.Yan@Sun.COM 214910923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n", 215010923SEvan.Yan@Sun.COM dip, devcap2); 215110923SEvan.Yan@Sun.COM 215210923SEvan.Yan@Sun.COM if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) { 215310923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: " 215410923SEvan.Yan@Sun.COM "dip=%p: ARI Forwarding is supported\n", dip); 215510923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_SUPPORTED); 215610923SEvan.Yan@Sun.COM } 215710923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED); 215810923SEvan.Yan@Sun.COM } 215910923SEvan.Yan@Sun.COM 216010923SEvan.Yan@Sun.COM int 216110923SEvan.Yan@Sun.COM pcie_ari_enable(dev_info_t *dip) 216210923SEvan.Yan@Sun.COM { 216310923SEvan.Yan@Sun.COM uint16_t devctl2; 216410923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 216510923SEvan.Yan@Sun.COM 216610923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_enable: dip=%p\n", dip); 216710923SEvan.Yan@Sun.COM 216810923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 216910923SEvan.Yan@Sun.COM return (DDI_FAILURE); 217010923SEvan.Yan@Sun.COM 217110923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2); 217210923SEvan.Yan@Sun.COM devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN; 217310923SEvan.Yan@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2); 217410923SEvan.Yan@Sun.COM 217510923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n", 217610923SEvan.Yan@Sun.COM dip, devctl2); 217710923SEvan.Yan@Sun.COM 217810923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 217910923SEvan.Yan@Sun.COM } 218010923SEvan.Yan@Sun.COM 218110923SEvan.Yan@Sun.COM int 218210923SEvan.Yan@Sun.COM pcie_ari_disable(dev_info_t *dip) 218310923SEvan.Yan@Sun.COM { 218410923SEvan.Yan@Sun.COM uint16_t devctl2; 218510923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 218610923SEvan.Yan@Sun.COM 218710923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_disable: dip=%p\n", dip); 218810923SEvan.Yan@Sun.COM 218910923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 219010923SEvan.Yan@Sun.COM return (DDI_FAILURE); 219110923SEvan.Yan@Sun.COM 219210923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2); 219310923SEvan.Yan@Sun.COM devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN; 219410923SEvan.Yan@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2); 219510923SEvan.Yan@Sun.COM 219610923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n", 219710923SEvan.Yan@Sun.COM dip, devctl2); 219810923SEvan.Yan@Sun.COM 219910923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 220010923SEvan.Yan@Sun.COM } 220110923SEvan.Yan@Sun.COM 220210923SEvan.Yan@Sun.COM int 220310923SEvan.Yan@Sun.COM pcie_ari_is_enabled(dev_info_t *dip) 220410923SEvan.Yan@Sun.COM { 220510923SEvan.Yan@Sun.COM uint16_t devctl2; 220610923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 220710923SEvan.Yan@Sun.COM 220810923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip); 220910923SEvan.Yan@Sun.COM 221010923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 221110923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_DISABLED); 221210923SEvan.Yan@Sun.COM 221310923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2); 221410923SEvan.Yan@Sun.COM 221510923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n", 221610923SEvan.Yan@Sun.COM dip, devctl2); 221710923SEvan.Yan@Sun.COM 221810923SEvan.Yan@Sun.COM if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) { 221910923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: " 222010923SEvan.Yan@Sun.COM "dip=%p: ARI Forwarding is enabled\n", dip); 222110923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_ENABLED); 222210923SEvan.Yan@Sun.COM } 222310923SEvan.Yan@Sun.COM 222410923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_DISABLED); 222510923SEvan.Yan@Sun.COM } 222610923SEvan.Yan@Sun.COM 222710923SEvan.Yan@Sun.COM int 222810923SEvan.Yan@Sun.COM pcie_ari_device(dev_info_t *dip) 222910923SEvan.Yan@Sun.COM { 223010923SEvan.Yan@Sun.COM ddi_acc_handle_t handle; 223110923SEvan.Yan@Sun.COM uint16_t cap_ptr; 223210923SEvan.Yan@Sun.COM 223310923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_device: dip=%p\n", dip); 223410923SEvan.Yan@Sun.COM 223510923SEvan.Yan@Sun.COM /* 223610923SEvan.Yan@Sun.COM * XXX - This function may be called before the bus_p structure 223710923SEvan.Yan@Sun.COM * has been populated. This code can be changed to remove 223810923SEvan.Yan@Sun.COM * pci_config_setup()/pci_config_teardown() when the RFE 223910923SEvan.Yan@Sun.COM * to populate the bus_p structures early in boot is putback. 224010923SEvan.Yan@Sun.COM */ 224110923SEvan.Yan@Sun.COM 224210923SEvan.Yan@Sun.COM /* First make sure it is a PCIe device */ 224310923SEvan.Yan@Sun.COM 224410923SEvan.Yan@Sun.COM if (pci_config_setup(dip, &handle) != DDI_SUCCESS) 224510923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE); 224610923SEvan.Yan@Sun.COM 224710923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) 224810923SEvan.Yan@Sun.COM != DDI_SUCCESS) { 224910923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 225010923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE); 225110923SEvan.Yan@Sun.COM } 225210923SEvan.Yan@Sun.COM 225310923SEvan.Yan@Sun.COM /* Locate the ARI Capability */ 225410923SEvan.Yan@Sun.COM 225510923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), 225610923SEvan.Yan@Sun.COM &cap_ptr)) == DDI_FAILURE) { 225710923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 225810923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE); 225910923SEvan.Yan@Sun.COM } 226010923SEvan.Yan@Sun.COM 226110923SEvan.Yan@Sun.COM /* ARI Capability was found so it must be a ARI device */ 226210923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip); 226310923SEvan.Yan@Sun.COM 226410923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 226510923SEvan.Yan@Sun.COM return (PCIE_ARI_DEVICE); 226610923SEvan.Yan@Sun.COM } 226710923SEvan.Yan@Sun.COM 226810923SEvan.Yan@Sun.COM int 226910923SEvan.Yan@Sun.COM pcie_ari_get_next_function(dev_info_t *dip, int *func) 227010923SEvan.Yan@Sun.COM { 227110923SEvan.Yan@Sun.COM uint32_t val; 227210923SEvan.Yan@Sun.COM uint16_t cap_ptr, next_function; 227310923SEvan.Yan@Sun.COM ddi_acc_handle_t handle; 227410923SEvan.Yan@Sun.COM 227510923SEvan.Yan@Sun.COM /* 227610923SEvan.Yan@Sun.COM * XXX - This function may be called before the bus_p structure 227710923SEvan.Yan@Sun.COM * has been populated. This code can be changed to remove 227810923SEvan.Yan@Sun.COM * pci_config_setup()/pci_config_teardown() when the RFE 227910923SEvan.Yan@Sun.COM * to populate the bus_p structures early in boot is putback. 228010923SEvan.Yan@Sun.COM */ 228110923SEvan.Yan@Sun.COM 228210923SEvan.Yan@Sun.COM if (pci_config_setup(dip, &handle) != DDI_SUCCESS) 228310923SEvan.Yan@Sun.COM return (DDI_FAILURE); 228410923SEvan.Yan@Sun.COM 228510923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, 228610923SEvan.Yan@Sun.COM PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) { 228710923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 228810923SEvan.Yan@Sun.COM return (DDI_FAILURE); 228910923SEvan.Yan@Sun.COM } 229010923SEvan.Yan@Sun.COM 229110923SEvan.Yan@Sun.COM val = PCI_CAP_GET32(handle, NULL, cap_ptr, PCIE_ARI_CAP); 229210923SEvan.Yan@Sun.COM 229310923SEvan.Yan@Sun.COM next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) & 229410923SEvan.Yan@Sun.COM PCIE_ARI_CAP_NEXT_FUNC_MASK; 229510923SEvan.Yan@Sun.COM 229610923SEvan.Yan@Sun.COM pci_config_teardown(&handle); 229710923SEvan.Yan@Sun.COM 229810923SEvan.Yan@Sun.COM *func = next_function; 229910923SEvan.Yan@Sun.COM 230010923SEvan.Yan@Sun.COM return (DDI_SUCCESS); 230110923SEvan.Yan@Sun.COM } 230210923SEvan.Yan@Sun.COM 230310923SEvan.Yan@Sun.COM dev_info_t * 230410923SEvan.Yan@Sun.COM pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function) 230510923SEvan.Yan@Sun.COM { 230610923SEvan.Yan@Sun.COM pcie_req_id_t child_bdf; 230710923SEvan.Yan@Sun.COM dev_info_t *cdip; 230810923SEvan.Yan@Sun.COM 230910923SEvan.Yan@Sun.COM for (cdip = ddi_get_child(dip); cdip; 231010923SEvan.Yan@Sun.COM cdip = ddi_get_next_sibling(cdip)) { 231110923SEvan.Yan@Sun.COM 231210923SEvan.Yan@Sun.COM if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE) 231310923SEvan.Yan@Sun.COM return (NULL); 231410923SEvan.Yan@Sun.COM 231510923SEvan.Yan@Sun.COM if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function) 231610923SEvan.Yan@Sun.COM return (cdip); 231710923SEvan.Yan@Sun.COM } 231810923SEvan.Yan@Sun.COM return (NULL); 231910923SEvan.Yan@Sun.COM } 232010923SEvan.Yan@Sun.COM 232110187SKrishna.Elango@Sun.COM #ifdef DEBUG 232210187SKrishna.Elango@Sun.COM 232310187SKrishna.Elango@Sun.COM static void 232410187SKrishna.Elango@Sun.COM pcie_print_bus(pcie_bus_t *bus_p) 232510187SKrishna.Elango@Sun.COM { 232610187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip); 232710187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags); 232810187SKrishna.Elango@Sun.COM 232910187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf); 233010187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id); 233110187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id); 233210187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type); 233310187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type); 233410187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus); 233510187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off); 233610187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off); 233710187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off); 233810187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver); 233910187SKrishna.Elango@Sun.COM } 234010187SKrishna.Elango@Sun.COM 234110187SKrishna.Elango@Sun.COM /* 234210187SKrishna.Elango@Sun.COM * For debugging purposes set pcie_dbg_print != 0 to see printf messages 234310187SKrishna.Elango@Sun.COM * during interrupt. 234410187SKrishna.Elango@Sun.COM * 234510187SKrishna.Elango@Sun.COM * When a proper solution is in place this code will disappear. 234610187SKrishna.Elango@Sun.COM * Potential solutions are: 234710187SKrishna.Elango@Sun.COM * o circular buffers 234810187SKrishna.Elango@Sun.COM * o taskq to print at lower pil 234910187SKrishna.Elango@Sun.COM */ 235010187SKrishna.Elango@Sun.COM int pcie_dbg_print = 0; 235110187SKrishna.Elango@Sun.COM void 235210187SKrishna.Elango@Sun.COM pcie_dbg(char *fmt, ...) 235310187SKrishna.Elango@Sun.COM { 235410187SKrishna.Elango@Sun.COM va_list ap; 235510187SKrishna.Elango@Sun.COM 235610187SKrishna.Elango@Sun.COM if (!pcie_debug_flags) { 235710187SKrishna.Elango@Sun.COM return; 235810187SKrishna.Elango@Sun.COM } 235910187SKrishna.Elango@Sun.COM va_start(ap, fmt); 236010187SKrishna.Elango@Sun.COM if (servicing_interrupt()) { 236110187SKrishna.Elango@Sun.COM if (pcie_dbg_print) { 236210187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap); 236310187SKrishna.Elango@Sun.COM } 236410187SKrishna.Elango@Sun.COM } else { 236510187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap); 236610187SKrishna.Elango@Sun.COM } 236710187SKrishna.Elango@Sun.COM va_end(ap); 236810187SKrishna.Elango@Sun.COM } 236910187SKrishna.Elango@Sun.COM #endif /* DEBUG */ 237010187SKrishna.Elango@Sun.COM 237110187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64) 237210187SKrishna.Elango@Sun.COM static void 237310187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl, boolean_t *empty_io_range, 237410187SKrishna.Elango@Sun.COM boolean_t *empty_mem_range) 237510187SKrishna.Elango@Sun.COM { 237610187SKrishna.Elango@Sun.COM uint8_t class, subclass; 237710187SKrishna.Elango@Sun.COM uint_t val; 237810187SKrishna.Elango@Sun.COM 237910187SKrishna.Elango@Sun.COM class = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS); 238010187SKrishna.Elango@Sun.COM subclass = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS); 238110187SKrishna.Elango@Sun.COM 238210187SKrishna.Elango@Sun.COM if ((class == PCI_CLASS_BRIDGE) && (subclass == PCI_BRIDGE_PCI)) { 238310187SKrishna.Elango@Sun.COM val = (((uint_t)pci_config_get8(cfg_hdl, PCI_BCNF_IO_BASE_LOW) & 238410187SKrishna.Elango@Sun.COM PCI_BCNF_IO_MASK) << 8); 238510187SKrishna.Elango@Sun.COM /* 238610187SKrishna.Elango@Sun.COM * Assuming that a zero based io_range[0] implies an 238710187SKrishna.Elango@Sun.COM * invalid I/O range. Likewise for mem_range[0]. 238810187SKrishna.Elango@Sun.COM */ 238910187SKrishna.Elango@Sun.COM if (val == 0) 239010187SKrishna.Elango@Sun.COM *empty_io_range = B_TRUE; 239110187SKrishna.Elango@Sun.COM val = (((uint_t)pci_config_get16(cfg_hdl, PCI_BCNF_MEM_BASE) & 239210187SKrishna.Elango@Sun.COM PCI_BCNF_MEM_MASK) << 16); 239310187SKrishna.Elango@Sun.COM if (val == 0) 239410187SKrishna.Elango@Sun.COM *empty_mem_range = B_TRUE; 239510187SKrishna.Elango@Sun.COM } 239610187SKrishna.Elango@Sun.COM } 239711245SZhijun.Fu@Sun.COM 239810187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */ 2399