1d4bc0535SKrishna Elango /* 2d4bc0535SKrishna Elango * CDDL HEADER START 3d4bc0535SKrishna Elango * 4d4bc0535SKrishna Elango * The contents of this file are subject to the terms of the 5d4bc0535SKrishna Elango * Common Development and Distribution License (the "License"). 6d4bc0535SKrishna Elango * You may not use this file except in compliance with the License. 7d4bc0535SKrishna Elango * 8d4bc0535SKrishna Elango * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d4bc0535SKrishna Elango * or http://www.opensolaris.org/os/licensing. 10d4bc0535SKrishna Elango * See the License for the specific language governing permissions 11d4bc0535SKrishna Elango * and limitations under the License. 12d4bc0535SKrishna Elango * 13d4bc0535SKrishna Elango * When distributing Covered Code, include this CDDL HEADER in each 14d4bc0535SKrishna Elango * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d4bc0535SKrishna Elango * If applicable, add the following below this CDDL HEADER, with the 16d4bc0535SKrishna Elango * fields enclosed by brackets "[]" replaced with your own identifying 17d4bc0535SKrishna Elango * information: Portions Copyright [yyyy] [name of copyright owner] 18d4bc0535SKrishna Elango * 19d4bc0535SKrishna Elango * CDDL HEADER END 20d4bc0535SKrishna Elango */ 219187c210SAlan Adamson, SD OSSD 22d4bc0535SKrishna Elango /* 2383e6495bSDaniel Ice * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24d4bc0535SKrishna Elango */ 25d4bc0535SKrishna Elango 26d4bc0535SKrishna Elango #include <sys/sysmacros.h> 27d4bc0535SKrishna Elango #include <sys/types.h> 28d4bc0535SKrishna Elango #include <sys/kmem.h> 29d4bc0535SKrishna Elango #include <sys/modctl.h> 30d4bc0535SKrishna Elango #include <sys/ddi.h> 31d4bc0535SKrishna Elango #include <sys/sunddi.h> 32d4bc0535SKrishna Elango #include <sys/sunndi.h> 33d4bc0535SKrishna Elango #include <sys/fm/protocol.h> 34d4bc0535SKrishna Elango #include <sys/fm/util.h> 35d4bc0535SKrishna Elango #include <sys/promif.h> 36d4bc0535SKrishna Elango #include <sys/disp.h> 3726947304SEvan Yan #include <sys/stat.h> 3826947304SEvan Yan #include <sys/file.h> 39d4bc0535SKrishna Elango #include <sys/pci_cap.h> 4026947304SEvan Yan #include <sys/pci_impl.h> 41d4bc0535SKrishna Elango #include <sys/pcie_impl.h> 4226947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h> 4370f83219SEvan Yan #include <sys/hotplug/pci/pciehpc.h> 4470f83219SEvan Yan #include <sys/hotplug/pci/pcishpc.h> 4526947304SEvan Yan #include <sys/hotplug/pci/pcicfg.h> 46c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h> 47d4bc0535SKrishna Elango 4826947304SEvan Yan /* Local functions prototypes */ 49d4bc0535SKrishna Elango static void pcie_init_pfd(dev_info_t *); 50d4bc0535SKrishna Elango static void pcie_fini_pfd(dev_info_t *); 51d4bc0535SKrishna Elango 52d4bc0535SKrishna Elango #if defined(__i386) || defined(__amd64) 53d4bc0535SKrishna Elango static void pcie_check_io_mem_range(ddi_acc_handle_t, boolean_t *, boolean_t *); 54d4bc0535SKrishna Elango #endif /* defined(__i386) || defined(__amd64) */ 55d4bc0535SKrishna Elango 56d4bc0535SKrishna Elango #ifdef DEBUG 57d4bc0535SKrishna Elango uint_t pcie_debug_flags = 0; 58d4bc0535SKrishna Elango static void pcie_print_bus(pcie_bus_t *bus_p); 5926947304SEvan Yan void pcie_dbg(char *fmt, ...); 60d4bc0535SKrishna Elango #endif /* DEBUG */ 61d4bc0535SKrishna Elango 62d4bc0535SKrishna Elango /* Variable to control default PCI-Express config settings */ 63d4bc0535SKrishna Elango ushort_t pcie_command_default = 64d4bc0535SKrishna Elango PCI_COMM_SERR_ENABLE | 65d4bc0535SKrishna Elango PCI_COMM_WAIT_CYC_ENAB | 66d4bc0535SKrishna Elango PCI_COMM_PARITY_DETECT | 67d4bc0535SKrishna Elango PCI_COMM_ME | 68d4bc0535SKrishna Elango PCI_COMM_MAE | 69d4bc0535SKrishna Elango PCI_COMM_IO; 70d4bc0535SKrishna Elango 71d4bc0535SKrishna Elango /* xxx_fw are bits that are controlled by FW and should not be modified */ 72d4bc0535SKrishna Elango ushort_t pcie_command_default_fw = 73d4bc0535SKrishna Elango PCI_COMM_SPEC_CYC | 74d4bc0535SKrishna Elango PCI_COMM_MEMWR_INVAL | 75d4bc0535SKrishna Elango PCI_COMM_PALETTE_SNOOP | 76d4bc0535SKrishna Elango PCI_COMM_WAIT_CYC_ENAB | 77d4bc0535SKrishna Elango 0xF800; /* Reserved Bits */ 78d4bc0535SKrishna Elango 79d4bc0535SKrishna Elango ushort_t pcie_bdg_command_default_fw = 80d4bc0535SKrishna Elango PCI_BCNF_BCNTRL_ISA_ENABLE | 81d4bc0535SKrishna Elango PCI_BCNF_BCNTRL_VGA_ENABLE | 82d4bc0535SKrishna Elango 0xF000; /* Reserved Bits */ 83d4bc0535SKrishna Elango 84d4bc0535SKrishna Elango /* PCI-Express Base error defaults */ 85d4bc0535SKrishna Elango ushort_t pcie_base_err_default = 86d4bc0535SKrishna Elango PCIE_DEVCTL_CE_REPORTING_EN | 87d4bc0535SKrishna Elango PCIE_DEVCTL_NFE_REPORTING_EN | 88d4bc0535SKrishna Elango PCIE_DEVCTL_FE_REPORTING_EN | 89d4bc0535SKrishna Elango PCIE_DEVCTL_UR_REPORTING_EN; 90d4bc0535SKrishna Elango 91d4bc0535SKrishna Elango /* PCI-Express Device Control Register */ 92d4bc0535SKrishna Elango uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN | 93d4bc0535SKrishna Elango PCIE_DEVCTL_MAX_READ_REQ_512; 94d4bc0535SKrishna Elango 95d4bc0535SKrishna Elango /* PCI-Express AER Root Control Register */ 96d4bc0535SKrishna Elango #define PCIE_ROOT_SYS_ERR (PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \ 97d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \ 98d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_FE_EN) 99d4bc0535SKrishna Elango 100d4bc0535SKrishna Elango ushort_t pcie_root_ctrl_default = 101d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | 102d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | 103d4bc0535SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_FE_EN; 104d4bc0535SKrishna Elango 105d4bc0535SKrishna Elango /* PCI-Express Root Error Command Register */ 106d4bc0535SKrishna Elango ushort_t pcie_root_error_cmd_default = 107d4bc0535SKrishna Elango PCIE_AER_RE_CMD_CE_REP_EN | 108d4bc0535SKrishna Elango PCIE_AER_RE_CMD_NFE_REP_EN | 109d4bc0535SKrishna Elango PCIE_AER_RE_CMD_FE_REP_EN; 110d4bc0535SKrishna Elango 111d4bc0535SKrishna Elango /* ECRC settings in the PCIe AER Control Register */ 112d4bc0535SKrishna Elango uint32_t pcie_ecrc_value = 113d4bc0535SKrishna Elango PCIE_AER_CTL_ECRC_GEN_ENA | 114d4bc0535SKrishna Elango PCIE_AER_CTL_ECRC_CHECK_ENA; 115d4bc0535SKrishna Elango 116d4bc0535SKrishna Elango /* 117d4bc0535SKrishna Elango * If a particular platform wants to disable certain errors such as UR/MA, 118d4bc0535SKrishna Elango * instead of using #defines have the platform's PCIe Root Complex driver set 119d4bc0535SKrishna Elango * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions. For 120d4bc0535SKrishna Elango * x86 the closest thing to a PCIe root complex driver is NPE. For SPARC the 121d4bc0535SKrishna Elango * closest PCIe root complex driver is PX. 122d4bc0535SKrishna Elango * 123d4bc0535SKrishna Elango * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86 124d4bc0535SKrishna Elango * systems may want to disable SERR in general. For root ports, enabling SERR 125d4bc0535SKrishna Elango * causes NMIs which are not handled and results in a watchdog timeout error. 126d4bc0535SKrishna Elango */ 127d4bc0535SKrishna Elango uint32_t pcie_aer_uce_mask = 0; /* AER UE Mask */ 128d4bc0535SKrishna Elango uint32_t pcie_aer_ce_mask = 0; /* AER CE Mask */ 129d4bc0535SKrishna Elango uint32_t pcie_aer_suce_mask = 0; /* AER Secondary UE Mask */ 130d4bc0535SKrishna Elango uint32_t pcie_serr_disable_flag = 0; /* Disable SERR */ 131d4bc0535SKrishna Elango 132d4bc0535SKrishna Elango /* Default severities needed for eversholt. Error handling doesn't care */ 133d4bc0535SKrishna Elango uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \ 134d4bc0535SKrishna Elango PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \ 135d4bc0535SKrishna Elango PCIE_AER_UCE_TRAINING; 136d4bc0535SKrishna Elango uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \ 137d4bc0535SKrishna Elango PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \ 138d4bc0535SKrishna Elango PCIE_AER_SUCE_USC_MSG_DATA_ERR; 139d4bc0535SKrishna Elango 140d4bc0535SKrishna Elango int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5; 14126947304SEvan Yan int pcie_disable_ari = 0; 142d4bc0535SKrishna Elango 143d4bc0535SKrishna Elango static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, 144d4bc0535SKrishna Elango int *max_supported); 145d4bc0535SKrishna Elango static int pcie_get_max_supported(dev_info_t *dip, void *arg); 146d4bc0535SKrishna Elango static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 147d4bc0535SKrishna Elango caddr_t *addrp, ddi_acc_handle_t *handlep); 148d4bc0535SKrishna Elango static void pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph); 149d4bc0535SKrishna Elango 150c0da6274SZhi-Jun Robin Fu dev_info_t *pcie_get_rc_dip(dev_info_t *dip); 151c0da6274SZhi-Jun Robin Fu 152d4bc0535SKrishna Elango /* 153d4bc0535SKrishna Elango * modload support 154d4bc0535SKrishna Elango */ 155d4bc0535SKrishna Elango 156d4bc0535SKrishna Elango static struct modlmisc modlmisc = { 157d4bc0535SKrishna Elango &mod_miscops, /* Type of module */ 15826947304SEvan Yan "PCI Express Framework Module" 159d4bc0535SKrishna Elango }; 160d4bc0535SKrishna Elango 161d4bc0535SKrishna Elango static struct modlinkage modlinkage = { 162d4bc0535SKrishna Elango MODREV_1, 163d4bc0535SKrishna Elango (void *)&modlmisc, 164d4bc0535SKrishna Elango NULL 165d4bc0535SKrishna Elango }; 166d4bc0535SKrishna Elango 167d4bc0535SKrishna Elango /* 168d4bc0535SKrishna Elango * Global Variables needed for a non-atomic version of ddi_fm_ereport_post. 169d4bc0535SKrishna Elango * Currently used to send the pci.fabric ereports whose payload depends on the 170d4bc0535SKrishna Elango * type of PCI device it is being sent for. 171d4bc0535SKrishna Elango */ 172d4bc0535SKrishna Elango char *pcie_nv_buf; 173d4bc0535SKrishna Elango nv_alloc_t *pcie_nvap; 174d4bc0535SKrishna Elango nvlist_t *pcie_nvl; 175d4bc0535SKrishna Elango 176d4bc0535SKrishna Elango int 177d4bc0535SKrishna Elango _init(void) 178d4bc0535SKrishna Elango { 179d4bc0535SKrishna Elango int rval; 180d4bc0535SKrishna Elango 181d4bc0535SKrishna Elango pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP); 182d4bc0535SKrishna Elango pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ); 183d4bc0535SKrishna Elango pcie_nvl = fm_nvlist_create(pcie_nvap); 184d4bc0535SKrishna Elango 185*c92295a9SAn Bui if ((rval = mod_install(&modlinkage)) != 0) { 186*c92295a9SAn Bui fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN); 187*c92295a9SAn Bui fm_nva_xdestroy(pcie_nvap); 188*c92295a9SAn Bui kmem_free(pcie_nv_buf, ERPT_DATA_SZ); 189*c92295a9SAn Bui } 190d4bc0535SKrishna Elango return (rval); 191d4bc0535SKrishna Elango } 192d4bc0535SKrishna Elango 193d4bc0535SKrishna Elango int 194d4bc0535SKrishna Elango _fini() 195d4bc0535SKrishna Elango { 196d4bc0535SKrishna Elango int rval; 197d4bc0535SKrishna Elango 198*c92295a9SAn Bui if ((rval = mod_remove(&modlinkage)) == 0) { 199d4bc0535SKrishna Elango fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN); 200d4bc0535SKrishna Elango fm_nva_xdestroy(pcie_nvap); 201d4bc0535SKrishna Elango kmem_free(pcie_nv_buf, ERPT_DATA_SZ); 202*c92295a9SAn Bui } 203d4bc0535SKrishna Elango return (rval); 204d4bc0535SKrishna Elango } 205d4bc0535SKrishna Elango 206d4bc0535SKrishna Elango int 207d4bc0535SKrishna Elango _info(struct modinfo *modinfop) 208d4bc0535SKrishna Elango { 209d4bc0535SKrishna Elango return (mod_info(&modlinkage, modinfop)); 210d4bc0535SKrishna Elango } 211d4bc0535SKrishna Elango 21226947304SEvan Yan /* ARGSUSED */ 21326947304SEvan Yan int 21426947304SEvan Yan pcie_init(dev_info_t *dip, caddr_t arg) 21526947304SEvan Yan { 21626947304SEvan Yan int ret = DDI_SUCCESS; 21726947304SEvan Yan 21826947304SEvan Yan /* 21926947304SEvan Yan * Create a "devctl" minor node to support DEVCTL_DEVICE_* 22026947304SEvan Yan * and DEVCTL_BUS_* ioctls to this bus. 22126947304SEvan Yan */ 22226947304SEvan Yan if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR, 22326947304SEvan Yan PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR), 22426947304SEvan Yan DDI_NT_NEXUS, 0)) != DDI_SUCCESS) { 22526947304SEvan Yan PCIE_DBG("Failed to create devctl minor node for %s%d\n", 22626947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip)); 22726947304SEvan Yan 22826947304SEvan Yan return (ret); 22926947304SEvan Yan } 23026947304SEvan Yan 23126947304SEvan Yan if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) { 23226947304SEvan Yan /* 233ed11b501SColin Zou - Sun Microsystems - Beijing China * On some x86 platforms, we observed unexpected hotplug 234ed11b501SColin Zou - Sun Microsystems - Beijing China * initialization failures in recent years. The known cause 235ed11b501SColin Zou - Sun Microsystems - Beijing China * is a hardware issue: while the problem PCI bridges have 236ed11b501SColin Zou - Sun Microsystems - Beijing China * the Hotplug Capable registers set, the machine actually 237ed11b501SColin Zou - Sun Microsystems - Beijing China * does not implement the expected ACPI object. 238ed11b501SColin Zou - Sun Microsystems - Beijing China * 239ed11b501SColin Zou - Sun Microsystems - Beijing China * We don't want to stop PCI driver attach and system boot 240ed11b501SColin Zou - Sun Microsystems - Beijing China * just because of this hotplug initialization failure. 241ed11b501SColin Zou - Sun Microsystems - Beijing China * Continue with a debug message printed. 24226947304SEvan Yan */ 243ed11b501SColin Zou - Sun Microsystems - Beijing China PCIE_DBG("%s%d: Failed setting hotplug framework\n", 24426947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip)); 24526947304SEvan Yan 24626947304SEvan Yan #if defined(__sparc) 24726947304SEvan Yan ddi_remove_minor_node(dip, "devctl"); 24826947304SEvan Yan 24926947304SEvan Yan return (ret); 25026947304SEvan Yan #endif /* defined(__sparc) */ 25126947304SEvan Yan } 25226947304SEvan Yan 25326947304SEvan Yan return (DDI_SUCCESS); 25426947304SEvan Yan } 25526947304SEvan Yan 25626947304SEvan Yan /* ARGSUSED */ 25726947304SEvan Yan int 25826947304SEvan Yan pcie_uninit(dev_info_t *dip) 25926947304SEvan Yan { 26026947304SEvan Yan int ret = DDI_SUCCESS; 26126947304SEvan Yan 26226947304SEvan Yan if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED) 26326947304SEvan Yan (void) pcie_ari_disable(dip); 26426947304SEvan Yan 26526947304SEvan Yan if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) { 26626947304SEvan Yan PCIE_DBG("Failed to uninitialize hotplug for %s%d\n", 26726947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip)); 26826947304SEvan Yan 26926947304SEvan Yan return (ret); 27026947304SEvan Yan } 27126947304SEvan Yan 27226947304SEvan Yan ddi_remove_minor_node(dip, "devctl"); 27326947304SEvan Yan 27426947304SEvan Yan return (ret); 27526947304SEvan Yan } 27626947304SEvan Yan 27770f83219SEvan Yan /* 27870f83219SEvan Yan * PCIe module interface for enabling hotplug interrupt. 27970f83219SEvan Yan * 28070f83219SEvan Yan * It should be called after pcie_init() is done and bus driver's 28170f83219SEvan Yan * interrupt handlers have being attached. 28270f83219SEvan Yan */ 28370f83219SEvan Yan int 28470f83219SEvan Yan pcie_hpintr_enable(dev_info_t *dip) 28570f83219SEvan Yan { 28670f83219SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 28770f83219SEvan Yan pcie_hp_ctrl_t *ctrl_p = PCIE_GET_HP_CTRL(dip); 28870f83219SEvan Yan 28970f83219SEvan Yan if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) { 29070f83219SEvan Yan (void) (ctrl_p->hc_ops.enable_hpc_intr)(ctrl_p); 29170f83219SEvan Yan } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) { 29270f83219SEvan Yan (void) pcishpc_enable_irqs(ctrl_p); 29370f83219SEvan Yan } 29470f83219SEvan Yan return (DDI_SUCCESS); 29570f83219SEvan Yan } 29670f83219SEvan Yan 29770f83219SEvan Yan /* 29870f83219SEvan Yan * PCIe module interface for disabling hotplug interrupt. 29970f83219SEvan Yan * 30070f83219SEvan Yan * It should be called before pcie_uninit() is called and bus driver's 30170f83219SEvan Yan * interrupt handlers is dettached. 30270f83219SEvan Yan */ 30370f83219SEvan Yan int 30470f83219SEvan Yan pcie_hpintr_disable(dev_info_t *dip) 30570f83219SEvan Yan { 30670f83219SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 30770f83219SEvan Yan pcie_hp_ctrl_t *ctrl_p = PCIE_GET_HP_CTRL(dip); 30870f83219SEvan Yan 30970f83219SEvan Yan if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) { 31070f83219SEvan Yan (void) (ctrl_p->hc_ops.disable_hpc_intr)(ctrl_p); 31170f83219SEvan Yan } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) { 31270f83219SEvan Yan (void) pcishpc_disable_irqs(ctrl_p); 31370f83219SEvan Yan } 31470f83219SEvan Yan return (DDI_SUCCESS); 31570f83219SEvan Yan } 31670f83219SEvan Yan 31726947304SEvan Yan /* ARGSUSED */ 31826947304SEvan Yan int 31926947304SEvan Yan pcie_intr(dev_info_t *dip) 32026947304SEvan Yan { 32126947304SEvan Yan return (pcie_hp_intr(dip)); 32226947304SEvan Yan } 32326947304SEvan Yan 32426947304SEvan Yan /* ARGSUSED */ 32526947304SEvan Yan int 32626947304SEvan Yan pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp) 32726947304SEvan Yan { 32826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 32926947304SEvan Yan 33026947304SEvan Yan /* 33126947304SEvan Yan * Make sure the open is for the right file type. 33226947304SEvan Yan */ 33326947304SEvan Yan if (otyp != OTYP_CHR) 33426947304SEvan Yan return (EINVAL); 33526947304SEvan Yan 33626947304SEvan Yan /* 33726947304SEvan Yan * Handle the open by tracking the device state. 33826947304SEvan Yan */ 33926947304SEvan Yan if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) || 34026947304SEvan Yan ((flags & FEXCL) && 34126947304SEvan Yan (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) { 34226947304SEvan Yan return (EBUSY); 34326947304SEvan Yan } 34426947304SEvan Yan 34526947304SEvan Yan if (flags & FEXCL) 34626947304SEvan Yan bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL; 34726947304SEvan Yan else 34826947304SEvan Yan bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN; 34926947304SEvan Yan 35026947304SEvan Yan return (0); 35126947304SEvan Yan } 35226947304SEvan Yan 35326947304SEvan Yan /* ARGSUSED */ 35426947304SEvan Yan int 35526947304SEvan Yan pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp) 35626947304SEvan Yan { 35726947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 35826947304SEvan Yan 35926947304SEvan Yan if (otyp != OTYP_CHR) 36026947304SEvan Yan return (EINVAL); 36126947304SEvan Yan 36226947304SEvan Yan bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED; 36326947304SEvan Yan 36426947304SEvan Yan return (0); 36526947304SEvan Yan } 36626947304SEvan Yan 36726947304SEvan Yan /* ARGSUSED */ 36826947304SEvan Yan int 36926947304SEvan Yan pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode, 37026947304SEvan Yan cred_t *credp, int *rvalp) 37126947304SEvan Yan { 37226947304SEvan Yan struct devctl_iocdata *dcp; 37326947304SEvan Yan uint_t bus_state; 37426947304SEvan Yan int rv = DDI_SUCCESS; 37526947304SEvan Yan 37626947304SEvan Yan /* 37726947304SEvan Yan * We can use the generic implementation for devctl ioctl 37826947304SEvan Yan */ 37926947304SEvan Yan switch (cmd) { 38026947304SEvan Yan case DEVCTL_DEVICE_GETSTATE: 38126947304SEvan Yan case DEVCTL_DEVICE_ONLINE: 38226947304SEvan Yan case DEVCTL_DEVICE_OFFLINE: 38326947304SEvan Yan case DEVCTL_BUS_GETSTATE: 38426947304SEvan Yan return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0)); 38526947304SEvan Yan default: 38626947304SEvan Yan break; 38726947304SEvan Yan } 38826947304SEvan Yan 38926947304SEvan Yan /* 39026947304SEvan Yan * read devctl ioctl data 39126947304SEvan Yan */ 39226947304SEvan Yan if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 39326947304SEvan Yan return (EFAULT); 39426947304SEvan Yan 39526947304SEvan Yan switch (cmd) { 39626947304SEvan Yan case DEVCTL_BUS_QUIESCE: 39726947304SEvan Yan if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) 39826947304SEvan Yan if (bus_state == BUS_QUIESCED) 39926947304SEvan Yan break; 40026947304SEvan Yan (void) ndi_set_bus_state(dip, BUS_QUIESCED); 40126947304SEvan Yan break; 40226947304SEvan Yan case DEVCTL_BUS_UNQUIESCE: 40326947304SEvan Yan if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) 40426947304SEvan Yan if (bus_state == BUS_ACTIVE) 40526947304SEvan Yan break; 40626947304SEvan Yan (void) ndi_set_bus_state(dip, BUS_ACTIVE); 40726947304SEvan Yan break; 40826947304SEvan Yan case DEVCTL_BUS_RESET: 40926947304SEvan Yan case DEVCTL_BUS_RESETALL: 41026947304SEvan Yan case DEVCTL_DEVICE_RESET: 41126947304SEvan Yan rv = ENOTSUP; 41226947304SEvan Yan break; 41326947304SEvan Yan default: 41426947304SEvan Yan rv = ENOTTY; 41526947304SEvan Yan } 41626947304SEvan Yan 41726947304SEvan Yan ndi_dc_freehdl(dcp); 41826947304SEvan Yan return (rv); 41926947304SEvan Yan } 42026947304SEvan Yan 42126947304SEvan Yan /* ARGSUSED */ 42226947304SEvan Yan int 42326947304SEvan Yan pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 42426947304SEvan Yan int flags, char *name, caddr_t valuep, int *lengthp) 42526947304SEvan Yan { 42626947304SEvan Yan if (dev == DDI_DEV_T_ANY) 42726947304SEvan Yan goto skip; 42826947304SEvan Yan 42926947304SEvan Yan if (PCIE_IS_HOTPLUG_CAPABLE(dip) && 43026947304SEvan Yan strcmp(name, "pci-occupant") == 0) { 43126947304SEvan Yan int pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev)); 43226947304SEvan Yan 43326947304SEvan Yan pcie_hp_create_occupant_props(dip, dev, pci_dev); 43426947304SEvan Yan } 43526947304SEvan Yan 43626947304SEvan Yan skip: 43726947304SEvan Yan return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); 43826947304SEvan Yan } 43926947304SEvan Yan 440c0da6274SZhi-Jun Robin Fu int 441c0da6274SZhi-Jun Robin Fu pcie_init_cfghdl(dev_info_t *cdip) 442c0da6274SZhi-Jun Robin Fu { 443c0da6274SZhi-Jun Robin Fu pcie_bus_t *bus_p; 444c0da6274SZhi-Jun Robin Fu ddi_acc_handle_t eh = NULL; 445c0da6274SZhi-Jun Robin Fu 446c0da6274SZhi-Jun Robin Fu bus_p = PCIE_DIP2BUS(cdip); 447c0da6274SZhi-Jun Robin Fu if (bus_p == NULL) 448c0da6274SZhi-Jun Robin Fu return (DDI_FAILURE); 449c0da6274SZhi-Jun Robin Fu 450c0da6274SZhi-Jun Robin Fu /* Create an config access special to error handling */ 451c0da6274SZhi-Jun Robin Fu if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) { 452c0da6274SZhi-Jun Robin Fu cmn_err(CE_WARN, "Cannot setup config access" 453c0da6274SZhi-Jun Robin Fu " for BDF 0x%x\n", bus_p->bus_bdf); 454c0da6274SZhi-Jun Robin Fu return (DDI_FAILURE); 455c0da6274SZhi-Jun Robin Fu } 456c0da6274SZhi-Jun Robin Fu 457c0da6274SZhi-Jun Robin Fu bus_p->bus_cfg_hdl = eh; 458c0da6274SZhi-Jun Robin Fu return (DDI_SUCCESS); 459c0da6274SZhi-Jun Robin Fu } 460c0da6274SZhi-Jun Robin Fu 461c0da6274SZhi-Jun Robin Fu void 462c0da6274SZhi-Jun Robin Fu pcie_fini_cfghdl(dev_info_t *cdip) 463c0da6274SZhi-Jun Robin Fu { 464c0da6274SZhi-Jun Robin Fu pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip); 465c0da6274SZhi-Jun Robin Fu 466c0da6274SZhi-Jun Robin Fu pci_config_teardown(&bus_p->bus_cfg_hdl); 467c0da6274SZhi-Jun Robin Fu } 468c0da6274SZhi-Jun Robin Fu 469d4bc0535SKrishna Elango /* 470d4bc0535SKrishna Elango * PCI-Express child device initialization. 471d4bc0535SKrishna Elango * This function enables generic pci-express interrupts and error 472d4bc0535SKrishna Elango * handling. 473d4bc0535SKrishna Elango * 474d4bc0535SKrishna Elango * @param pdip root dip (root nexus's dip) 475d4bc0535SKrishna Elango * @param cdip child's dip (device's dip) 476d4bc0535SKrishna Elango * @return DDI_SUCCESS or DDI_FAILURE 477d4bc0535SKrishna Elango */ 478d4bc0535SKrishna Elango /* ARGSUSED */ 479d4bc0535SKrishna Elango int 480d4bc0535SKrishna Elango pcie_initchild(dev_info_t *cdip) 481d4bc0535SKrishna Elango { 482d4bc0535SKrishna Elango uint16_t tmp16, reg16; 483d4bc0535SKrishna Elango pcie_bus_t *bus_p; 484fc256490SJason Beloro uint32_t devid, venid; 485d4bc0535SKrishna Elango 486d4bc0535SKrishna Elango bus_p = PCIE_DIP2BUS(cdip); 487d4bc0535SKrishna Elango if (bus_p == NULL) { 488d4bc0535SKrishna Elango PCIE_DBG("%s: BUS not found.\n", 489d4bc0535SKrishna Elango ddi_driver_name(cdip)); 490d4bc0535SKrishna Elango 491d4bc0535SKrishna Elango return (DDI_FAILURE); 492d4bc0535SKrishna Elango } 493d4bc0535SKrishna Elango 494c0da6274SZhi-Jun Robin Fu if (pcie_init_cfghdl(cdip) != DDI_SUCCESS) 495c0da6274SZhi-Jun Robin Fu return (DDI_FAILURE); 496c0da6274SZhi-Jun Robin Fu 497fc256490SJason Beloro /* 498fc256490SJason Beloro * Update pcie_bus_t with real Vendor Id Device Id. 499fc256490SJason Beloro * 500fc256490SJason Beloro * For assigned devices in IOV environment, the OBP will return 501fc256490SJason Beloro * faked device id/vendor id on configration read and for both 502fc256490SJason Beloro * properties in root domain. translate_devid() function will 503fc256490SJason Beloro * update the properties with real device-id/vendor-id on such 504fc256490SJason Beloro * platforms, so that we can utilize the properties here to get 505fc256490SJason Beloro * real device-id/vendor-id and overwrite the faked ids. 506fc256490SJason Beloro * 507fc256490SJason Beloro * For unassigned devices or devices in non-IOV environment, the 508fc256490SJason Beloro * operation below won't make a difference. 509fc256490SJason Beloro * 510fc256490SJason Beloro * The IOV implementation only supports assignment of PCIE 511fc256490SJason Beloro * endpoint devices. Devices under pci-pci bridges don't need 512fc256490SJason Beloro * operation like this. 513fc256490SJason Beloro */ 514fc256490SJason Beloro devid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 515fc256490SJason Beloro "device-id", -1); 516fc256490SJason Beloro venid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 517fc256490SJason Beloro "vendor-id", -1); 518fc256490SJason Beloro bus_p->bus_dev_ven_id = (devid << 16) | (venid & 0xffff); 519fc256490SJason Beloro 520d4bc0535SKrishna Elango /* Clear the device's status register */ 521d4bc0535SKrishna Elango reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT); 522d4bc0535SKrishna Elango PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16); 523d4bc0535SKrishna Elango 524d4bc0535SKrishna Elango /* Setup the device's command register */ 525d4bc0535SKrishna Elango reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM); 526d4bc0535SKrishna Elango tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default; 527d4bc0535SKrishna Elango 528d4bc0535SKrishna Elango #if defined(__i386) || defined(__amd64) 529d4bc0535SKrishna Elango boolean_t empty_io_range = B_FALSE; 530d4bc0535SKrishna Elango boolean_t empty_mem_range = B_FALSE; 531d4bc0535SKrishna Elango /* 532d4bc0535SKrishna Elango * Check for empty IO and Mem ranges on bridges. If so disable IO/Mem 533d4bc0535SKrishna Elango * access as it can cause a hang if enabled. 534d4bc0535SKrishna Elango */ 535d4bc0535SKrishna Elango pcie_check_io_mem_range(bus_p->bus_cfg_hdl, &empty_io_range, 536d4bc0535SKrishna Elango &empty_mem_range); 537d4bc0535SKrishna Elango if ((empty_io_range == B_TRUE) && 538d4bc0535SKrishna Elango (pcie_command_default & PCI_COMM_IO)) { 539d4bc0535SKrishna Elango tmp16 &= ~PCI_COMM_IO; 540d4bc0535SKrishna Elango PCIE_DBG("No I/O range found for %s, bdf 0x%x\n", 541d4bc0535SKrishna Elango ddi_driver_name(cdip), bus_p->bus_bdf); 542d4bc0535SKrishna Elango } 543d4bc0535SKrishna Elango if ((empty_mem_range == B_TRUE) && 544d4bc0535SKrishna Elango (pcie_command_default & PCI_COMM_MAE)) { 545d4bc0535SKrishna Elango tmp16 &= ~PCI_COMM_MAE; 546d4bc0535SKrishna Elango PCIE_DBG("No Mem range found for %s, bdf 0x%x\n", 547d4bc0535SKrishna Elango ddi_driver_name(cdip), bus_p->bus_bdf); 548d4bc0535SKrishna Elango } 549d4bc0535SKrishna Elango #endif /* defined(__i386) || defined(__amd64) */ 550d4bc0535SKrishna Elango 551d4bc0535SKrishna Elango if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p)) 552d4bc0535SKrishna Elango tmp16 &= ~PCI_COMM_SERR_ENABLE; 553d4bc0535SKrishna Elango 554d4bc0535SKrishna Elango PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16); 555d4bc0535SKrishna Elango PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16); 556d4bc0535SKrishna Elango 557d4bc0535SKrishna Elango /* 558d4bc0535SKrishna Elango * If the device has a bus control register then program it 559d4bc0535SKrishna Elango * based on the settings in the command register. 560d4bc0535SKrishna Elango */ 561d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p)) { 562d4bc0535SKrishna Elango /* Clear the device's secondary status register */ 563d4bc0535SKrishna Elango reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS); 564d4bc0535SKrishna Elango PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16); 565d4bc0535SKrishna Elango 566d4bc0535SKrishna Elango /* Setup the device's secondary command register */ 567d4bc0535SKrishna Elango reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL); 568d4bc0535SKrishna Elango tmp16 = (reg16 & pcie_bdg_command_default_fw); 569d4bc0535SKrishna Elango 570d4bc0535SKrishna Elango tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE; 571d4bc0535SKrishna Elango /* 572d4bc0535SKrishna Elango * Workaround for this Nvidia bridge. Don't enable the SERR 573d4bc0535SKrishna Elango * enable bit in the bridge control register as it could lead to 574d4bc0535SKrishna Elango * bogus NMIs. 575d4bc0535SKrishna Elango */ 576d4bc0535SKrishna Elango if (bus_p->bus_dev_ven_id == 0x037010DE) 577d4bc0535SKrishna Elango tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE; 578d4bc0535SKrishna Elango 579d4bc0535SKrishna Elango if (pcie_command_default & PCI_COMM_PARITY_DETECT) 580d4bc0535SKrishna Elango tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE; 581d4bc0535SKrishna Elango 582d4bc0535SKrishna Elango /* 583d4bc0535SKrishna Elango * Enable Master Abort Mode only if URs have not been masked. 584d4bc0535SKrishna Elango * For PCI and PCIe-PCI bridges, enabling this bit causes a 585d4bc0535SKrishna Elango * Master Aborts/UR to be forwarded as a UR/TA or SERR. If this 586d4bc0535SKrishna Elango * bit is masked, posted requests are dropped and non-posted 587d4bc0535SKrishna Elango * requests are returned with -1. 588d4bc0535SKrishna Elango */ 589d4bc0535SKrishna Elango if (pcie_aer_uce_mask & PCIE_AER_UCE_UR) 590d4bc0535SKrishna Elango tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE; 591d4bc0535SKrishna Elango else 592d4bc0535SKrishna Elango tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE; 593d4bc0535SKrishna Elango PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16); 594d4bc0535SKrishna Elango PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL, 595d4bc0535SKrishna Elango reg16); 596d4bc0535SKrishna Elango } 597d4bc0535SKrishna Elango 598d4bc0535SKrishna Elango if (PCIE_IS_PCIE(bus_p)) { 599d4bc0535SKrishna Elango /* Setup PCIe device control register */ 600d4bc0535SKrishna Elango reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 60183e6495bSDaniel Ice /* note: MPS/MRRS are initialized in pcie_initchild_mps() */ 60283e6495bSDaniel Ice tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK | 60383e6495bSDaniel Ice PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 60483e6495bSDaniel Ice (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 60583e6495bSDaniel Ice PCIE_DEVCTL_MAX_PAYLOAD_MASK)); 606d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16); 607d4bc0535SKrishna Elango PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16); 608d4bc0535SKrishna Elango 609d4bc0535SKrishna Elango /* Enable PCIe errors */ 610d4bc0535SKrishna Elango pcie_enable_errors(cdip); 611d4bc0535SKrishna Elango } 612d4bc0535SKrishna Elango 61326947304SEvan Yan bus_p->bus_ari = B_FALSE; 61426947304SEvan Yan if ((pcie_ari_is_enabled(ddi_get_parent(cdip)) 61526947304SEvan Yan == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip) 61626947304SEvan Yan == PCIE_ARI_DEVICE)) { 61726947304SEvan Yan bus_p->bus_ari = B_TRUE; 61826947304SEvan Yan } 61926947304SEvan Yan 620c0da6274SZhi-Jun Robin Fu if (pcie_initchild_mps(cdip) == DDI_FAILURE) { 621c0da6274SZhi-Jun Robin Fu pcie_fini_cfghdl(cdip); 622d4bc0535SKrishna Elango return (DDI_FAILURE); 623c0da6274SZhi-Jun Robin Fu } 624d4bc0535SKrishna Elango 625d4bc0535SKrishna Elango return (DDI_SUCCESS); 626d4bc0535SKrishna Elango } 627d4bc0535SKrishna Elango 628d4bc0535SKrishna Elango static void 629d4bc0535SKrishna Elango pcie_init_pfd(dev_info_t *dip) 630d4bc0535SKrishna Elango { 631d4bc0535SKrishna Elango pf_data_t *pfd_p = PCIE_ZALLOC(pf_data_t); 632d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 633d4bc0535SKrishna Elango 634d4bc0535SKrishna Elango PCIE_DIP2PFD(dip) = pfd_p; 635d4bc0535SKrishna Elango 636d4bc0535SKrishna Elango pfd_p->pe_bus_p = bus_p; 637d4bc0535SKrishna Elango pfd_p->pe_severity_flags = 0; 638fc256490SJason Beloro pfd_p->pe_orig_severity_flags = 0; 639d4bc0535SKrishna Elango pfd_p->pe_lock = B_FALSE; 640d4bc0535SKrishna Elango pfd_p->pe_valid = B_FALSE; 641d4bc0535SKrishna Elango 642d4bc0535SKrishna Elango /* Allocate the root fault struct for both RC and RP */ 643d4bc0535SKrishna Elango if (PCIE_IS_ROOT(bus_p)) { 644d4bc0535SKrishna Elango PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t); 645d4bc0535SKrishna Elango PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF; 646fc256490SJason Beloro PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t); 647d4bc0535SKrishna Elango } 648d4bc0535SKrishna Elango 649d4bc0535SKrishna Elango PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t); 650fc256490SJason Beloro PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t); 651fc256490SJason Beloro PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF; 652d4bc0535SKrishna Elango 653d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p)) 654d4bc0535SKrishna Elango PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t); 655d4bc0535SKrishna Elango 656d4bc0535SKrishna Elango if (PCIE_IS_PCIE(bus_p)) { 657d4bc0535SKrishna Elango PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t); 658d4bc0535SKrishna Elango 659d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p)) 660d4bc0535SKrishna Elango PCIE_RP_REG(pfd_p) = 661d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcie_rp_err_regs_t); 662d4bc0535SKrishna Elango 663d4bc0535SKrishna Elango PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t); 664d4bc0535SKrishna Elango PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF; 665d4bc0535SKrishna Elango 666d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p)) { 667d4bc0535SKrishna Elango PCIE_ADV_RP_REG(pfd_p) = 668d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t); 669d4bc0535SKrishna Elango PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = 670d4bc0535SKrishna Elango PCIE_INVALID_BDF; 671d4bc0535SKrishna Elango PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = 672d4bc0535SKrishna Elango PCIE_INVALID_BDF; 673d4bc0535SKrishna Elango } else if (PCIE_IS_PCIE_BDG(bus_p)) { 674d4bc0535SKrishna Elango PCIE_ADV_BDG_REG(pfd_p) = 675d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t); 676d4bc0535SKrishna Elango PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf = 677d4bc0535SKrishna Elango PCIE_INVALID_BDF; 678d4bc0535SKrishna Elango } 679d4bc0535SKrishna Elango 680d4bc0535SKrishna Elango if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) { 681d4bc0535SKrishna Elango PCIX_BDG_ERR_REG(pfd_p) = 682d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_bdg_err_regs_t); 683d4bc0535SKrishna Elango 684d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) { 685d4bc0535SKrishna Elango PCIX_BDG_ECC_REG(pfd_p, 0) = 686d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t); 687d4bc0535SKrishna Elango PCIX_BDG_ECC_REG(pfd_p, 1) = 688d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t); 689d4bc0535SKrishna Elango } 690d4bc0535SKrishna Elango } 691d4bc0535SKrishna Elango } else if (PCIE_IS_PCIX(bus_p)) { 692d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p)) { 693d4bc0535SKrishna Elango PCIX_BDG_ERR_REG(pfd_p) = 694d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_bdg_err_regs_t); 695d4bc0535SKrishna Elango 696d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) { 697d4bc0535SKrishna Elango PCIX_BDG_ECC_REG(pfd_p, 0) = 698d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t); 699d4bc0535SKrishna Elango PCIX_BDG_ECC_REG(pfd_p, 1) = 700d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t); 701d4bc0535SKrishna Elango } 702d4bc0535SKrishna Elango } else { 703d4bc0535SKrishna Elango PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t); 704d4bc0535SKrishna Elango 705d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) 706d4bc0535SKrishna Elango PCIX_ECC_REG(pfd_p) = 707d4bc0535SKrishna Elango PCIE_ZALLOC(pf_pcix_ecc_regs_t); 708d4bc0535SKrishna Elango } 709d4bc0535SKrishna Elango } 710d4bc0535SKrishna Elango } 711d4bc0535SKrishna Elango 712d4bc0535SKrishna Elango static void 713d4bc0535SKrishna Elango pcie_fini_pfd(dev_info_t *dip) 714d4bc0535SKrishna Elango { 715d4bc0535SKrishna Elango pf_data_t *pfd_p = PCIE_DIP2PFD(dip); 716d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 717d4bc0535SKrishna Elango 718d4bc0535SKrishna Elango if (PCIE_IS_PCIE(bus_p)) { 719d4bc0535SKrishna Elango if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) { 720d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) { 721d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0), 722d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t)); 723d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1), 724d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t)); 725d4bc0535SKrishna Elango } 726d4bc0535SKrishna Elango 727d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ERR_REG(pfd_p), 728d4bc0535SKrishna Elango sizeof (pf_pcix_bdg_err_regs_t)); 729d4bc0535SKrishna Elango } 730d4bc0535SKrishna Elango 731d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p)) 732d4bc0535SKrishna Elango kmem_free(PCIE_ADV_RP_REG(pfd_p), 733d4bc0535SKrishna Elango sizeof (pf_pcie_adv_rp_err_regs_t)); 734d4bc0535SKrishna Elango else if (PCIE_IS_PCIE_BDG(bus_p)) 735d4bc0535SKrishna Elango kmem_free(PCIE_ADV_BDG_REG(pfd_p), 736d4bc0535SKrishna Elango sizeof (pf_pcie_adv_bdg_err_regs_t)); 737d4bc0535SKrishna Elango 738d4bc0535SKrishna Elango kmem_free(PCIE_ADV_REG(pfd_p), 739d4bc0535SKrishna Elango sizeof (pf_pcie_adv_err_regs_t)); 740d4bc0535SKrishna Elango 741d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p)) 742d4bc0535SKrishna Elango kmem_free(PCIE_RP_REG(pfd_p), 743d4bc0535SKrishna Elango sizeof (pf_pcie_rp_err_regs_t)); 744d4bc0535SKrishna Elango 745d4bc0535SKrishna Elango kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t)); 746d4bc0535SKrishna Elango } else if (PCIE_IS_PCIX(bus_p)) { 747d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p)) { 748d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) { 749d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0), 750d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t)); 751d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1), 752d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t)); 753d4bc0535SKrishna Elango } 754d4bc0535SKrishna Elango 755d4bc0535SKrishna Elango kmem_free(PCIX_BDG_ERR_REG(pfd_p), 756d4bc0535SKrishna Elango sizeof (pf_pcix_bdg_err_regs_t)); 757d4bc0535SKrishna Elango } else { 758d4bc0535SKrishna Elango if (PCIX_ECC_VERSION_CHECK(bus_p)) 759d4bc0535SKrishna Elango kmem_free(PCIX_ECC_REG(pfd_p), 760d4bc0535SKrishna Elango sizeof (pf_pcix_ecc_regs_t)); 761d4bc0535SKrishna Elango 762d4bc0535SKrishna Elango kmem_free(PCIX_ERR_REG(pfd_p), 763d4bc0535SKrishna Elango sizeof (pf_pcix_err_regs_t)); 764d4bc0535SKrishna Elango } 765d4bc0535SKrishna Elango } 766d4bc0535SKrishna Elango 767d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p)) 768d4bc0535SKrishna Elango kmem_free(PCI_BDG_ERR_REG(pfd_p), 769d4bc0535SKrishna Elango sizeof (pf_pci_bdg_err_regs_t)); 770d4bc0535SKrishna Elango 771fc256490SJason Beloro kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t)); 772d4bc0535SKrishna Elango kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t)); 773d4bc0535SKrishna Elango 774fc256490SJason Beloro if (PCIE_IS_ROOT(bus_p)) { 775d4bc0535SKrishna Elango kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t)); 776fc256490SJason Beloro kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t)); 777fc256490SJason Beloro } 778d4bc0535SKrishna Elango 779d4bc0535SKrishna Elango kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t)); 780d4bc0535SKrishna Elango 781d4bc0535SKrishna Elango PCIE_DIP2PFD(dip) = NULL; 782d4bc0535SKrishna Elango } 783d4bc0535SKrishna Elango 784d4bc0535SKrishna Elango 785d4bc0535SKrishna Elango /* 786d4bc0535SKrishna Elango * Special functions to allocate pf_data_t's for PCIe root complexes. 787d4bc0535SKrishna Elango * Note: Root Complex not Root Port 788d4bc0535SKrishna Elango */ 789d4bc0535SKrishna Elango void 790d4bc0535SKrishna Elango pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p) 791d4bc0535SKrishna Elango { 792d4bc0535SKrishna Elango pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip); 793d4bc0535SKrishna Elango pfd_p->pe_severity_flags = 0; 794fc256490SJason Beloro pfd_p->pe_orig_severity_flags = 0; 795d4bc0535SKrishna Elango pfd_p->pe_lock = B_FALSE; 796d4bc0535SKrishna Elango pfd_p->pe_valid = B_FALSE; 797d4bc0535SKrishna Elango 798d4bc0535SKrishna Elango PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t); 799d4bc0535SKrishna Elango PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF; 800fc256490SJason Beloro PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t); 801d4bc0535SKrishna Elango PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t); 802fc256490SJason Beloro PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t); 803fc256490SJason Beloro PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF; 804d4bc0535SKrishna Elango PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t); 805d4bc0535SKrishna Elango PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t); 806d4bc0535SKrishna Elango PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t); 807d4bc0535SKrishna Elango PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t); 808d4bc0535SKrishna Elango PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t); 809fc256490SJason Beloro PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = PCIE_INVALID_BDF; 810fc256490SJason Beloro PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = PCIE_INVALID_BDF; 811d4bc0535SKrishna Elango 812d4bc0535SKrishna Elango PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity; 813d4bc0535SKrishna Elango } 814d4bc0535SKrishna Elango 815d4bc0535SKrishna Elango void 816d4bc0535SKrishna Elango pcie_rc_fini_pfd(pf_data_t *pfd_p) 817d4bc0535SKrishna Elango { 818d4bc0535SKrishna Elango kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t)); 819d4bc0535SKrishna Elango kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t)); 820d4bc0535SKrishna Elango kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t)); 821d4bc0535SKrishna Elango kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t)); 822d4bc0535SKrishna Elango kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t)); 823fc256490SJason Beloro kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t)); 824d4bc0535SKrishna Elango kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t)); 825d4bc0535SKrishna Elango kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t)); 826fc256490SJason Beloro kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t)); 827d4bc0535SKrishna Elango } 828d4bc0535SKrishna Elango 829c0da6274SZhi-Jun Robin Fu /* 830c0da6274SZhi-Jun Robin Fu * init pcie_bus_t for root complex 831c0da6274SZhi-Jun Robin Fu * 832c0da6274SZhi-Jun Robin Fu * Only a few of the fields in bus_t is valid for root complex. 833c0da6274SZhi-Jun Robin Fu * The fields that are bracketed are initialized in this routine: 834c0da6274SZhi-Jun Robin Fu * 835c0da6274SZhi-Jun Robin Fu * dev_info_t * <bus_dip> 836c0da6274SZhi-Jun Robin Fu * dev_info_t * bus_rp_dip 837c0da6274SZhi-Jun Robin Fu * ddi_acc_handle_t bus_cfg_hdl 838c0da6274SZhi-Jun Robin Fu * uint_t <bus_fm_flags> 839c0da6274SZhi-Jun Robin Fu * pcie_req_id_t bus_bdf 840c0da6274SZhi-Jun Robin Fu * pcie_req_id_t bus_rp_bdf 841c0da6274SZhi-Jun Robin Fu * uint32_t bus_dev_ven_id 842c0da6274SZhi-Jun Robin Fu * uint8_t bus_rev_id 843c0da6274SZhi-Jun Robin Fu * uint8_t <bus_hdr_type> 844c0da6274SZhi-Jun Robin Fu * uint16_t <bus_dev_type> 845c0da6274SZhi-Jun Robin Fu * uint8_t bus_bdg_secbus 846c0da6274SZhi-Jun Robin Fu * uint16_t bus_pcie_off 847c0da6274SZhi-Jun Robin Fu * uint16_t <bus_aer_off> 848c0da6274SZhi-Jun Robin Fu * uint16_t bus_pcix_off 849c0da6274SZhi-Jun Robin Fu * uint16_t bus_ecc_ver 850c0da6274SZhi-Jun Robin Fu * pci_bus_range_t bus_bus_range 851c0da6274SZhi-Jun Robin Fu * ppb_ranges_t * bus_addr_ranges 852c0da6274SZhi-Jun Robin Fu * int bus_addr_entries 853c0da6274SZhi-Jun Robin Fu * pci_regspec_t * bus_assigned_addr 854c0da6274SZhi-Jun Robin Fu * int bus_assigned_entries 855c0da6274SZhi-Jun Robin Fu * pf_data_t * bus_pfd 856fc256490SJason Beloro * pcie_domain_t * <bus_dom> 857c0da6274SZhi-Jun Robin Fu * int bus_mps 858c0da6274SZhi-Jun Robin Fu * uint64_t bus_cfgacc_base 859c0da6274SZhi-Jun Robin Fu * void * bus_plat_private 860c0da6274SZhi-Jun Robin Fu */ 861d4bc0535SKrishna Elango void 862d4bc0535SKrishna Elango pcie_rc_init_bus(dev_info_t *dip) 863d4bc0535SKrishna Elango { 864d4bc0535SKrishna Elango pcie_bus_t *bus_p; 865d4bc0535SKrishna Elango 866d4bc0535SKrishna Elango bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP); 867d4bc0535SKrishna Elango bus_p->bus_dip = dip; 868d4bc0535SKrishna Elango bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO; 869d4bc0535SKrishna Elango bus_p->bus_hdr_type = PCI_HEADER_ONE; 870d4bc0535SKrishna Elango 871d4bc0535SKrishna Elango /* Fake that there are AER logs */ 872d4bc0535SKrishna Elango bus_p->bus_aer_off = (uint16_t)-1; 873d4bc0535SKrishna Elango 874d4bc0535SKrishna Elango /* Needed only for handle lookup */ 875d4bc0535SKrishna Elango bus_p->bus_fm_flags |= PF_FM_READY; 876d4bc0535SKrishna Elango 877d4bc0535SKrishna Elango ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p); 878fc256490SJason Beloro 879fc256490SJason Beloro PCIE_BUS2DOM(bus_p) = PCIE_ZALLOC(pcie_domain_t); 880d4bc0535SKrishna Elango } 881d4bc0535SKrishna Elango 882d4bc0535SKrishna Elango void 883d4bc0535SKrishna Elango pcie_rc_fini_bus(dev_info_t *dip) 884d4bc0535SKrishna Elango { 885c0da6274SZhi-Jun Robin Fu pcie_bus_t *bus_p = PCIE_DIP2DOWNBUS(dip); 886d4bc0535SKrishna Elango ndi_set_bus_private(dip, B_FALSE, NULL, NULL); 887fc256490SJason Beloro kmem_free(PCIE_BUS2DOM(bus_p), sizeof (pcie_domain_t)); 888d4bc0535SKrishna Elango kmem_free(bus_p, sizeof (pcie_bus_t)); 889d4bc0535SKrishna Elango } 890d4bc0535SKrishna Elango 891d4bc0535SKrishna Elango /* 892c0da6274SZhi-Jun Robin Fu * partially init pcie_bus_t for device (dip,bdf) for accessing pci 893c0da6274SZhi-Jun Robin Fu * config space 894d4bc0535SKrishna Elango * 895c0da6274SZhi-Jun Robin Fu * This routine is invoked during boot, either after creating a devinfo node 896c0da6274SZhi-Jun Robin Fu * (x86 case) or during px driver attach (sparc case); it is also invoked 897c0da6274SZhi-Jun Robin Fu * in hotplug context after a devinfo node is created. 898c0da6274SZhi-Jun Robin Fu * 899c0da6274SZhi-Jun Robin Fu * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL 900c0da6274SZhi-Jun Robin Fu * is set: 901c0da6274SZhi-Jun Robin Fu * 902c0da6274SZhi-Jun Robin Fu * dev_info_t * <bus_dip> 903c0da6274SZhi-Jun Robin Fu * dev_info_t * <bus_rp_dip> 904c0da6274SZhi-Jun Robin Fu * ddi_acc_handle_t bus_cfg_hdl 905c0da6274SZhi-Jun Robin Fu * uint_t bus_fm_flags 906c0da6274SZhi-Jun Robin Fu * pcie_req_id_t <bus_bdf> 907c0da6274SZhi-Jun Robin Fu * pcie_req_id_t <bus_rp_bdf> 908c0da6274SZhi-Jun Robin Fu * uint32_t <bus_dev_ven_id> 909c0da6274SZhi-Jun Robin Fu * uint8_t <bus_rev_id> 910c0da6274SZhi-Jun Robin Fu * uint8_t <bus_hdr_type> 911c0da6274SZhi-Jun Robin Fu * uint16_t <bus_dev_type> 912c0da6274SZhi-Jun Robin Fu * uint8_t <bus_bdg_secbus 913c0da6274SZhi-Jun Robin Fu * uint16_t <bus_pcie_off> 914c0da6274SZhi-Jun Robin Fu * uint16_t <bus_aer_off> 915c0da6274SZhi-Jun Robin Fu * uint16_t <bus_pcix_off> 916c0da6274SZhi-Jun Robin Fu * uint16_t <bus_ecc_ver> 917c0da6274SZhi-Jun Robin Fu * pci_bus_range_t bus_bus_range 918c0da6274SZhi-Jun Robin Fu * ppb_ranges_t * bus_addr_ranges 919c0da6274SZhi-Jun Robin Fu * int bus_addr_entries 920c0da6274SZhi-Jun Robin Fu * pci_regspec_t * bus_assigned_addr 921c0da6274SZhi-Jun Robin Fu * int bus_assigned_entries 922c0da6274SZhi-Jun Robin Fu * pf_data_t * bus_pfd 923fc256490SJason Beloro * pcie_domain_t * bus_dom 924c0da6274SZhi-Jun Robin Fu * int bus_mps 925c0da6274SZhi-Jun Robin Fu * uint64_t bus_cfgacc_base 926c0da6274SZhi-Jun Robin Fu * void * bus_plat_private 927c0da6274SZhi-Jun Robin Fu * 928c0da6274SZhi-Jun Robin Fu * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL 929c0da6274SZhi-Jun Robin Fu * is set: 930c0da6274SZhi-Jun Robin Fu * 931c0da6274SZhi-Jun Robin Fu * dev_info_t * bus_dip 932c0da6274SZhi-Jun Robin Fu * dev_info_t * bus_rp_dip 933c0da6274SZhi-Jun Robin Fu * ddi_acc_handle_t bus_cfg_hdl 934c0da6274SZhi-Jun Robin Fu * uint_t bus_fm_flags 935c0da6274SZhi-Jun Robin Fu * pcie_req_id_t bus_bdf 936c0da6274SZhi-Jun Robin Fu * pcie_req_id_t bus_rp_bdf 937c0da6274SZhi-Jun Robin Fu * uint32_t bus_dev_ven_id 938c0da6274SZhi-Jun Robin Fu * uint8_t bus_rev_id 939c0da6274SZhi-Jun Robin Fu * uint8_t bus_hdr_type 940c0da6274SZhi-Jun Robin Fu * uint16_t bus_dev_type 941c0da6274SZhi-Jun Robin Fu * uint8_t <bus_bdg_secbus> 942c0da6274SZhi-Jun Robin Fu * uint16_t bus_pcie_off 943c0da6274SZhi-Jun Robin Fu * uint16_t bus_aer_off 944c0da6274SZhi-Jun Robin Fu * uint16_t bus_pcix_off 945c0da6274SZhi-Jun Robin Fu * uint16_t bus_ecc_ver 946c0da6274SZhi-Jun Robin Fu * pci_bus_range_t <bus_bus_range> 947c0da6274SZhi-Jun Robin Fu * ppb_ranges_t * <bus_addr_ranges> 948c0da6274SZhi-Jun Robin Fu * int <bus_addr_entries> 949c0da6274SZhi-Jun Robin Fu * pci_regspec_t * <bus_assigned_addr> 950c0da6274SZhi-Jun Robin Fu * int <bus_assigned_entries> 951c0da6274SZhi-Jun Robin Fu * pf_data_t * <bus_pfd> 952fc256490SJason Beloro * pcie_domain_t * bus_dom 953c0da6274SZhi-Jun Robin Fu * int bus_mps 954c0da6274SZhi-Jun Robin Fu * uint64_t bus_cfgacc_base 955c0da6274SZhi-Jun Robin Fu * void * <bus_plat_private> 956d4bc0535SKrishna Elango */ 957c0da6274SZhi-Jun Robin Fu 958d4bc0535SKrishna Elango pcie_bus_t * 959c0da6274SZhi-Jun Robin Fu pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf, uint8_t flags) 960d4bc0535SKrishna Elango { 961c0da6274SZhi-Jun Robin Fu uint16_t status, base, baseptr, num_cap; 962c0da6274SZhi-Jun Robin Fu uint32_t capid; 963d4bc0535SKrishna Elango int range_size; 964c0da6274SZhi-Jun Robin Fu pcie_bus_t *bus_p; 965c0da6274SZhi-Jun Robin Fu dev_info_t *rcdip; 966d4bc0535SKrishna Elango dev_info_t *pdip; 967d4bc0535SKrishna Elango const char *errstr = NULL; 968d4bc0535SKrishna Elango 969c0da6274SZhi-Jun Robin Fu if (!(flags & PCIE_BUS_INITIAL)) 970c0da6274SZhi-Jun Robin Fu goto initial_done; 971d4bc0535SKrishna Elango 972d4bc0535SKrishna Elango bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP); 973d4bc0535SKrishna Elango 974c0da6274SZhi-Jun Robin Fu bus_p->bus_dip = dip; 975c0da6274SZhi-Jun Robin Fu bus_p->bus_bdf = bdf; 976d4bc0535SKrishna Elango 977c0da6274SZhi-Jun Robin Fu rcdip = pcie_get_rc_dip(dip); 978c0da6274SZhi-Jun Robin Fu ASSERT(rcdip != NULL); 97926947304SEvan Yan 980c0da6274SZhi-Jun Robin Fu /* Save the Vendor ID, Device ID and revision ID */ 981c0da6274SZhi-Jun Robin Fu bus_p->bus_dev_ven_id = pci_cfgacc_get32(rcdip, bdf, PCI_CONF_VENID); 982c0da6274SZhi-Jun Robin Fu bus_p->bus_rev_id = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID); 983d4bc0535SKrishna Elango /* Save the Header Type */ 984c0da6274SZhi-Jun Robin Fu bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER); 985d4bc0535SKrishna Elango bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M; 986d4bc0535SKrishna Elango 987c0da6274SZhi-Jun Robin Fu /* 988c0da6274SZhi-Jun Robin Fu * Figure out the device type and all the relavant capability offsets 989c0da6274SZhi-Jun Robin Fu */ 990c0da6274SZhi-Jun Robin Fu /* set default value */ 991c0da6274SZhi-Jun Robin Fu bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO; 992d4bc0535SKrishna Elango 993c0da6274SZhi-Jun Robin Fu status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT); 994c0da6274SZhi-Jun Robin Fu if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP)) 995c0da6274SZhi-Jun Robin Fu goto caps_done; /* capability not supported */ 996c0da6274SZhi-Jun Robin Fu 997c0da6274SZhi-Jun Robin Fu /* Relevant conventional capabilities first */ 998c0da6274SZhi-Jun Robin Fu 999c0da6274SZhi-Jun Robin Fu /* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */ 1000c0da6274SZhi-Jun Robin Fu num_cap = 2; 1001c0da6274SZhi-Jun Robin Fu 1002c0da6274SZhi-Jun Robin Fu switch (bus_p->bus_hdr_type) { 1003c0da6274SZhi-Jun Robin Fu case PCI_HEADER_ZERO: 1004c0da6274SZhi-Jun Robin Fu baseptr = PCI_CONF_CAP_PTR; 1005c0da6274SZhi-Jun Robin Fu break; 1006c0da6274SZhi-Jun Robin Fu case PCI_HEADER_PPB: 1007c0da6274SZhi-Jun Robin Fu baseptr = PCI_BCNF_CAP_PTR; 1008c0da6274SZhi-Jun Robin Fu break; 1009c0da6274SZhi-Jun Robin Fu case PCI_HEADER_CARDBUS: 1010c0da6274SZhi-Jun Robin Fu baseptr = PCI_CBUS_CAP_PTR; 1011c0da6274SZhi-Jun Robin Fu break; 1012c0da6274SZhi-Jun Robin Fu default: 1013c0da6274SZhi-Jun Robin Fu cmn_err(CE_WARN, "%s: unexpected pci header type:%x", 1014c0da6274SZhi-Jun Robin Fu __func__, bus_p->bus_hdr_type); 1015c0da6274SZhi-Jun Robin Fu goto caps_done; 1016c0da6274SZhi-Jun Robin Fu } 1017c0da6274SZhi-Jun Robin Fu 1018c0da6274SZhi-Jun Robin Fu base = baseptr; 1019c0da6274SZhi-Jun Robin Fu for (base = pci_cfgacc_get8(rcdip, bdf, base); base && num_cap; 1020c0da6274SZhi-Jun Robin Fu base = pci_cfgacc_get8(rcdip, bdf, base + PCI_CAP_NEXT_PTR)) { 1021c0da6274SZhi-Jun Robin Fu capid = pci_cfgacc_get8(rcdip, bdf, base); 1022c0da6274SZhi-Jun Robin Fu switch (capid) { 1023c0da6274SZhi-Jun Robin Fu case PCI_CAP_ID_PCI_E: 1024c0da6274SZhi-Jun Robin Fu bus_p->bus_pcie_off = base; 1025c0da6274SZhi-Jun Robin Fu bus_p->bus_dev_type = pci_cfgacc_get16(rcdip, bdf, 1026c0da6274SZhi-Jun Robin Fu base + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 102726947304SEvan Yan 102826947304SEvan Yan /* Check and save PCIe hotplug capability information */ 102926947304SEvan Yan if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) && 1030c0da6274SZhi-Jun Robin Fu (pci_cfgacc_get16(rcdip, bdf, base + PCIE_PCIECAP) 103126947304SEvan Yan & PCIE_PCIECAP_SLOT_IMPL) && 1032c0da6274SZhi-Jun Robin Fu (pci_cfgacc_get32(rcdip, bdf, base + PCIE_SLOTCAP) 103326947304SEvan Yan & PCIE_SLOTCAP_HP_CAPABLE)) 103426947304SEvan Yan bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE; 1035d4bc0535SKrishna Elango 1036c0da6274SZhi-Jun Robin Fu num_cap--; 1037c0da6274SZhi-Jun Robin Fu break; 1038c0da6274SZhi-Jun Robin Fu case PCI_CAP_ID_PCIX: 1039c0da6274SZhi-Jun Robin Fu bus_p->bus_pcix_off = base; 1040d4bc0535SKrishna Elango if (PCIE_IS_BDG(bus_p)) 1041c0da6274SZhi-Jun Robin Fu bus_p->bus_ecc_ver = 1042c0da6274SZhi-Jun Robin Fu pci_cfgacc_get16(rcdip, bdf, base + 1043d4bc0535SKrishna Elango PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK; 1044d4bc0535SKrishna Elango else 1045c0da6274SZhi-Jun Robin Fu bus_p->bus_ecc_ver = 1046c0da6274SZhi-Jun Robin Fu pci_cfgacc_get16(rcdip, bdf, base + 1047d4bc0535SKrishna Elango PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK; 1048c0da6274SZhi-Jun Robin Fu num_cap--; 1049c0da6274SZhi-Jun Robin Fu break; 1050c0da6274SZhi-Jun Robin Fu default: 1051c0da6274SZhi-Jun Robin Fu break; 1052c0da6274SZhi-Jun Robin Fu } 1053d4bc0535SKrishna Elango } 1054d4bc0535SKrishna Elango 105526947304SEvan Yan /* Check and save PCI hotplug (SHPC) capability information */ 1056c0da6274SZhi-Jun Robin Fu if (PCIE_IS_BDG(bus_p)) { 1057c0da6274SZhi-Jun Robin Fu base = baseptr; 1058c0da6274SZhi-Jun Robin Fu for (base = pci_cfgacc_get8(rcdip, bdf, base); 1059c0da6274SZhi-Jun Robin Fu base; base = pci_cfgacc_get8(rcdip, bdf, 1060c0da6274SZhi-Jun Robin Fu base + PCI_CAP_NEXT_PTR)) { 1061c0da6274SZhi-Jun Robin Fu capid = pci_cfgacc_get8(rcdip, bdf, base); 1062c0da6274SZhi-Jun Robin Fu if (capid == PCI_CAP_ID_PCI_HOTPLUG) { 1063c0da6274SZhi-Jun Robin Fu bus_p->bus_pci_hp_off = base; 106426947304SEvan Yan bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE; 1065c0da6274SZhi-Jun Robin Fu break; 1066c0da6274SZhi-Jun Robin Fu } 1067c0da6274SZhi-Jun Robin Fu } 1068d4bc0535SKrishna Elango } 1069d4bc0535SKrishna Elango 1070c0da6274SZhi-Jun Robin Fu /* Then, relevant extended capabilities */ 1071d4bc0535SKrishna Elango 1072c0da6274SZhi-Jun Robin Fu if (!PCIE_IS_PCIE(bus_p)) 1073c0da6274SZhi-Jun Robin Fu goto caps_done; 1074c0da6274SZhi-Jun Robin Fu 1075c0da6274SZhi-Jun Robin Fu /* Extended caps: PCIE_EXT_CAP_ID_AER */ 1076c0da6274SZhi-Jun Robin Fu for (base = PCIE_EXT_CAP; base; base = (capid >> 1077c0da6274SZhi-Jun Robin Fu PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) { 1078c0da6274SZhi-Jun Robin Fu capid = pci_cfgacc_get32(rcdip, bdf, base); 1079c0da6274SZhi-Jun Robin Fu if (capid == PCI_CAP_EINVAL32) 1080c0da6274SZhi-Jun Robin Fu break; 1081c0da6274SZhi-Jun Robin Fu if (((capid >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK) 1082c0da6274SZhi-Jun Robin Fu == PCIE_EXT_CAP_ID_AER) { 1083c0da6274SZhi-Jun Robin Fu bus_p->bus_aer_off = base; 1084c0da6274SZhi-Jun Robin Fu break; 1085c0da6274SZhi-Jun Robin Fu } 1086d4bc0535SKrishna Elango } 1087d4bc0535SKrishna Elango 1088c0da6274SZhi-Jun Robin Fu caps_done: 1089d4bc0535SKrishna Elango /* save RP dip and RP bdf */ 1090d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p)) { 1091c0da6274SZhi-Jun Robin Fu bus_p->bus_rp_dip = dip; 1092d4bc0535SKrishna Elango bus_p->bus_rp_bdf = bus_p->bus_bdf; 1093d4bc0535SKrishna Elango } else { 1094c0da6274SZhi-Jun Robin Fu for (pdip = ddi_get_parent(dip); pdip; 1095d4bc0535SKrishna Elango pdip = ddi_get_parent(pdip)) { 1096d4bc0535SKrishna Elango pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip); 1097d4bc0535SKrishna Elango 1098d4bc0535SKrishna Elango /* 1099c0da6274SZhi-Jun Robin Fu * If RP dip and RP bdf in parent's bus_t have 1100c0da6274SZhi-Jun Robin Fu * been initialized, simply use these instead of 1101c0da6274SZhi-Jun Robin Fu * continuing up to the RC. 1102c0da6274SZhi-Jun Robin Fu */ 1103c0da6274SZhi-Jun Robin Fu if (parent_bus_p->bus_rp_dip != NULL) { 1104c0da6274SZhi-Jun Robin Fu bus_p->bus_rp_dip = parent_bus_p->bus_rp_dip; 1105c0da6274SZhi-Jun Robin Fu bus_p->bus_rp_bdf = parent_bus_p->bus_rp_bdf; 1106c0da6274SZhi-Jun Robin Fu break; 1107c0da6274SZhi-Jun Robin Fu } 1108c0da6274SZhi-Jun Robin Fu 1109c0da6274SZhi-Jun Robin Fu /* 1110d4bc0535SKrishna Elango * When debugging be aware that some NVIDIA x86 1111d4bc0535SKrishna Elango * architectures have 2 nodes for each RP, One at Bus 1112d4bc0535SKrishna Elango * 0x0 and one at Bus 0x80. The requester is from Bus 1113d4bc0535SKrishna Elango * 0x80 1114d4bc0535SKrishna Elango */ 1115d4bc0535SKrishna Elango if (PCIE_IS_ROOT(parent_bus_p)) { 1116d4bc0535SKrishna Elango bus_p->bus_rp_dip = pdip; 1117d4bc0535SKrishna Elango bus_p->bus_rp_bdf = parent_bus_p->bus_bdf; 1118d4bc0535SKrishna Elango break; 1119d4bc0535SKrishna Elango } 1120d4bc0535SKrishna Elango } 1121d4bc0535SKrishna Elango } 1122d4bc0535SKrishna Elango 1123c0da6274SZhi-Jun Robin Fu bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED; 1124c0da6274SZhi-Jun Robin Fu bus_p->bus_fm_flags = 0; 1125d4bc0535SKrishna Elango bus_p->bus_mps = 0; 1126d4bc0535SKrishna Elango 1127c0da6274SZhi-Jun Robin Fu ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p); 1128c0da6274SZhi-Jun Robin Fu 1129c0da6274SZhi-Jun Robin Fu if (PCIE_IS_HOTPLUG_CAPABLE(dip)) 1130c0da6274SZhi-Jun Robin Fu (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip, 1131c0da6274SZhi-Jun Robin Fu "hotplug-capable"); 1132c0da6274SZhi-Jun Robin Fu 1133c0da6274SZhi-Jun Robin Fu initial_done: 1134c0da6274SZhi-Jun Robin Fu if (!(flags & PCIE_BUS_FINAL)) 1135c0da6274SZhi-Jun Robin Fu goto final_done; 1136c0da6274SZhi-Jun Robin Fu 1137c0da6274SZhi-Jun Robin Fu /* already initialized? */ 1138c0da6274SZhi-Jun Robin Fu bus_p = PCIE_DIP2BUS(dip); 1139c0da6274SZhi-Jun Robin Fu 1140c0da6274SZhi-Jun Robin Fu /* Save the Range information if device is a switch/bridge */ 1141c0da6274SZhi-Jun Robin Fu if (PCIE_IS_BDG(bus_p)) { 1142c0da6274SZhi-Jun Robin Fu /* get "bus_range" property */ 1143c0da6274SZhi-Jun Robin Fu range_size = sizeof (pci_bus_range_t); 1144c0da6274SZhi-Jun Robin Fu if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1145c0da6274SZhi-Jun Robin Fu "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size) 1146c0da6274SZhi-Jun Robin Fu != DDI_PROP_SUCCESS) { 1147c0da6274SZhi-Jun Robin Fu errstr = "Cannot find \"bus-range\" property"; 1148c0da6274SZhi-Jun Robin Fu cmn_err(CE_WARN, 1149c0da6274SZhi-Jun Robin Fu "PCIE init err info failed BDF 0x%x:%s\n", 1150c0da6274SZhi-Jun Robin Fu bus_p->bus_bdf, errstr); 1151c0da6274SZhi-Jun Robin Fu } 1152c0da6274SZhi-Jun Robin Fu 1153c0da6274SZhi-Jun Robin Fu /* get secondary bus number */ 1154c0da6274SZhi-Jun Robin Fu rcdip = pcie_get_rc_dip(dip); 1155c0da6274SZhi-Jun Robin Fu ASSERT(rcdip != NULL); 1156c0da6274SZhi-Jun Robin Fu 1157c0da6274SZhi-Jun Robin Fu bus_p->bus_bdg_secbus = pci_cfgacc_get8(rcdip, 1158c0da6274SZhi-Jun Robin Fu bus_p->bus_bdf, PCI_BCNF_SECBUS); 1159c0da6274SZhi-Jun Robin Fu 1160c0da6274SZhi-Jun Robin Fu /* Get "ranges" property */ 1161c0da6274SZhi-Jun Robin Fu if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1162c0da6274SZhi-Jun Robin Fu "ranges", (caddr_t)&bus_p->bus_addr_ranges, 1163c0da6274SZhi-Jun Robin Fu &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS) 1164c0da6274SZhi-Jun Robin Fu bus_p->bus_addr_entries = 0; 1165c0da6274SZhi-Jun Robin Fu bus_p->bus_addr_entries /= sizeof (ppb_ranges_t); 1166c0da6274SZhi-Jun Robin Fu } 1167c0da6274SZhi-Jun Robin Fu 1168c0da6274SZhi-Jun Robin Fu /* save "assigned-addresses" property array, ignore failues */ 1169c0da6274SZhi-Jun Robin Fu if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1170c0da6274SZhi-Jun Robin Fu "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr, 1171c0da6274SZhi-Jun Robin Fu &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS) 1172c0da6274SZhi-Jun Robin Fu bus_p->bus_assigned_entries /= sizeof (pci_regspec_t); 1173c0da6274SZhi-Jun Robin Fu else 1174c0da6274SZhi-Jun Robin Fu bus_p->bus_assigned_entries = 0; 1175c0da6274SZhi-Jun Robin Fu 1176c0da6274SZhi-Jun Robin Fu pcie_init_pfd(dip); 1177c0da6274SZhi-Jun Robin Fu 1178c0da6274SZhi-Jun Robin Fu pcie_init_plat(dip); 1179c0da6274SZhi-Jun Robin Fu 1180c0da6274SZhi-Jun Robin Fu final_done: 1181d4bc0535SKrishna Elango 1182d4bc0535SKrishna Elango PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n", 1183c0da6274SZhi-Jun Robin Fu ddi_driver_name(dip), (void *)dip, bus_p->bus_bdf, 1184d4bc0535SKrishna Elango bus_p->bus_bdg_secbus); 1185d4bc0535SKrishna Elango #ifdef DEBUG 1186d4bc0535SKrishna Elango pcie_print_bus(bus_p); 1187d4bc0535SKrishna Elango #endif 1188d4bc0535SKrishna Elango 1189d4bc0535SKrishna Elango return (bus_p); 1190c0da6274SZhi-Jun Robin Fu } 1191c0da6274SZhi-Jun Robin Fu 1192c0da6274SZhi-Jun Robin Fu /* 1193c0da6274SZhi-Jun Robin Fu * Invoked before destroying devinfo node, mostly during hotplug 1194c0da6274SZhi-Jun Robin Fu * operation to free pcie_bus_t data structure 1195c0da6274SZhi-Jun Robin Fu */ 1196c0da6274SZhi-Jun Robin Fu /* ARGSUSED */ 1197c0da6274SZhi-Jun Robin Fu void 1198c0da6274SZhi-Jun Robin Fu pcie_fini_bus(dev_info_t *dip, uint8_t flags) 1199c0da6274SZhi-Jun Robin Fu { 1200c0da6274SZhi-Jun Robin Fu pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 1201c0da6274SZhi-Jun Robin Fu ASSERT(bus_p); 1202c0da6274SZhi-Jun Robin Fu 1203c0da6274SZhi-Jun Robin Fu if (flags & PCIE_BUS_INITIAL) { 1204c0da6274SZhi-Jun Robin Fu pcie_fini_plat(dip); 1205c0da6274SZhi-Jun Robin Fu pcie_fini_pfd(dip); 1206c0da6274SZhi-Jun Robin Fu 1207c0da6274SZhi-Jun Robin Fu kmem_free(bus_p->bus_assigned_addr, 1208c0da6274SZhi-Jun Robin Fu (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries)); 1209c0da6274SZhi-Jun Robin Fu kmem_free(bus_p->bus_addr_ranges, 1210c0da6274SZhi-Jun Robin Fu (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries)); 1211c0da6274SZhi-Jun Robin Fu /* zero out the fields that have been destroyed */ 1212c0da6274SZhi-Jun Robin Fu bus_p->bus_assigned_addr = NULL; 1213c0da6274SZhi-Jun Robin Fu bus_p->bus_addr_ranges = NULL; 1214c0da6274SZhi-Jun Robin Fu bus_p->bus_assigned_entries = 0; 1215c0da6274SZhi-Jun Robin Fu bus_p->bus_addr_entries = 0; 1216c0da6274SZhi-Jun Robin Fu } 1217c0da6274SZhi-Jun Robin Fu 1218c0da6274SZhi-Jun Robin Fu if (flags & PCIE_BUS_FINAL) { 1219c0da6274SZhi-Jun Robin Fu if (PCIE_IS_HOTPLUG_CAPABLE(dip)) { 1220c0da6274SZhi-Jun Robin Fu (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, 1221c0da6274SZhi-Jun Robin Fu "hotplug-capable"); 1222c0da6274SZhi-Jun Robin Fu } 1223c0da6274SZhi-Jun Robin Fu 1224c0da6274SZhi-Jun Robin Fu ndi_set_bus_private(dip, B_TRUE, NULL, NULL); 1225d4bc0535SKrishna Elango kmem_free(bus_p, sizeof (pcie_bus_t)); 1226c0da6274SZhi-Jun Robin Fu } 1227d4bc0535SKrishna Elango } 1228d4bc0535SKrishna Elango 1229d4bc0535SKrishna Elango int 1230d4bc0535SKrishna Elango pcie_postattach_child(dev_info_t *cdip) 1231d4bc0535SKrishna Elango { 1232d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip); 1233d4bc0535SKrishna Elango 1234d4bc0535SKrishna Elango if (!bus_p) 1235d4bc0535SKrishna Elango return (DDI_FAILURE); 1236d4bc0535SKrishna Elango 1237d4bc0535SKrishna Elango return (pcie_enable_ce(cdip)); 1238d4bc0535SKrishna Elango } 1239d4bc0535SKrishna Elango 1240d4bc0535SKrishna Elango /* 1241d4bc0535SKrishna Elango * PCI-Express child device de-initialization. 1242d4bc0535SKrishna Elango * This function disables generic pci-express interrupts and error 1243d4bc0535SKrishna Elango * handling. 1244d4bc0535SKrishna Elango */ 1245d4bc0535SKrishna Elango void 1246d4bc0535SKrishna Elango pcie_uninitchild(dev_info_t *cdip) 1247d4bc0535SKrishna Elango { 1248d4bc0535SKrishna Elango pcie_disable_errors(cdip); 1249c0da6274SZhi-Jun Robin Fu pcie_fini_cfghdl(cdip); 1250fc256490SJason Beloro pcie_fini_dom(cdip); 1251c0da6274SZhi-Jun Robin Fu } 1252c0da6274SZhi-Jun Robin Fu 1253c0da6274SZhi-Jun Robin Fu /* 1254c0da6274SZhi-Jun Robin Fu * find the root complex dip 1255c0da6274SZhi-Jun Robin Fu */ 1256c0da6274SZhi-Jun Robin Fu dev_info_t * 1257c0da6274SZhi-Jun Robin Fu pcie_get_rc_dip(dev_info_t *dip) 1258c0da6274SZhi-Jun Robin Fu { 1259c0da6274SZhi-Jun Robin Fu dev_info_t *rcdip; 1260c0da6274SZhi-Jun Robin Fu pcie_bus_t *rc_bus_p; 1261c0da6274SZhi-Jun Robin Fu 1262c0da6274SZhi-Jun Robin Fu for (rcdip = ddi_get_parent(dip); rcdip; 1263c0da6274SZhi-Jun Robin Fu rcdip = ddi_get_parent(rcdip)) { 1264c0da6274SZhi-Jun Robin Fu rc_bus_p = PCIE_DIP2BUS(rcdip); 1265c0da6274SZhi-Jun Robin Fu if (rc_bus_p && PCIE_IS_RC(rc_bus_p)) 1266c0da6274SZhi-Jun Robin Fu break; 1267c0da6274SZhi-Jun Robin Fu } 1268c0da6274SZhi-Jun Robin Fu 1269c0da6274SZhi-Jun Robin Fu return (rcdip); 1270c0da6274SZhi-Jun Robin Fu } 1271c0da6274SZhi-Jun Robin Fu 1272c0da6274SZhi-Jun Robin Fu static boolean_t 1273c0da6274SZhi-Jun Robin Fu pcie_is_pci_device(dev_info_t *dip) 1274c0da6274SZhi-Jun Robin Fu { 1275c0da6274SZhi-Jun Robin Fu dev_info_t *pdip; 1276c0da6274SZhi-Jun Robin Fu char *device_type; 1277c0da6274SZhi-Jun Robin Fu 1278c0da6274SZhi-Jun Robin Fu pdip = ddi_get_parent(dip); 1279c0da6274SZhi-Jun Robin Fu ASSERT(pdip); 1280c0da6274SZhi-Jun Robin Fu 1281c0da6274SZhi-Jun Robin Fu if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 1282c0da6274SZhi-Jun Robin Fu "device_type", &device_type) != DDI_PROP_SUCCESS) 1283c0da6274SZhi-Jun Robin Fu return (B_FALSE); 1284c0da6274SZhi-Jun Robin Fu 1285c0da6274SZhi-Jun Robin Fu if (strcmp(device_type, "pciex") != 0 && 1286c0da6274SZhi-Jun Robin Fu strcmp(device_type, "pci") != 0) { 1287c0da6274SZhi-Jun Robin Fu ddi_prop_free(device_type); 1288c0da6274SZhi-Jun Robin Fu return (B_FALSE); 1289c0da6274SZhi-Jun Robin Fu } 1290c0da6274SZhi-Jun Robin Fu 1291c0da6274SZhi-Jun Robin Fu ddi_prop_free(device_type); 1292c0da6274SZhi-Jun Robin Fu return (B_TRUE); 1293c0da6274SZhi-Jun Robin Fu } 1294c0da6274SZhi-Jun Robin Fu 1295c0da6274SZhi-Jun Robin Fu typedef struct { 1296c0da6274SZhi-Jun Robin Fu boolean_t init; 1297c0da6274SZhi-Jun Robin Fu uint8_t flags; 1298c0da6274SZhi-Jun Robin Fu } pcie_bus_arg_t; 1299c0da6274SZhi-Jun Robin Fu 1300c0da6274SZhi-Jun Robin Fu /*ARGSUSED*/ 1301c0da6274SZhi-Jun Robin Fu static int 1302c0da6274SZhi-Jun Robin Fu pcie_fab_do_init_fini(dev_info_t *dip, void *arg) 1303c0da6274SZhi-Jun Robin Fu { 1304c0da6274SZhi-Jun Robin Fu pcie_req_id_t bdf; 1305c0da6274SZhi-Jun Robin Fu pcie_bus_arg_t *bus_arg = (pcie_bus_arg_t *)arg; 1306c0da6274SZhi-Jun Robin Fu 1307c0da6274SZhi-Jun Robin Fu if (!pcie_is_pci_device(dip)) 1308c0da6274SZhi-Jun Robin Fu goto out; 1309c0da6274SZhi-Jun Robin Fu 1310c0da6274SZhi-Jun Robin Fu if (bus_arg->init) { 1311c0da6274SZhi-Jun Robin Fu if (pcie_get_bdf_from_dip(dip, &bdf) != DDI_SUCCESS) 1312c0da6274SZhi-Jun Robin Fu goto out; 1313c0da6274SZhi-Jun Robin Fu 1314c0da6274SZhi-Jun Robin Fu (void) pcie_init_bus(dip, bdf, bus_arg->flags); 1315c0da6274SZhi-Jun Robin Fu } else { 1316c0da6274SZhi-Jun Robin Fu (void) pcie_fini_bus(dip, bus_arg->flags); 1317c0da6274SZhi-Jun Robin Fu } 1318c0da6274SZhi-Jun Robin Fu 1319c0da6274SZhi-Jun Robin Fu return (DDI_WALK_CONTINUE); 1320c0da6274SZhi-Jun Robin Fu 1321c0da6274SZhi-Jun Robin Fu out: 1322c0da6274SZhi-Jun Robin Fu return (DDI_WALK_PRUNECHILD); 1323d4bc0535SKrishna Elango } 1324d4bc0535SKrishna Elango 1325d4bc0535SKrishna Elango void 1326c0da6274SZhi-Jun Robin Fu pcie_fab_init_bus(dev_info_t *rcdip, uint8_t flags) 1327d4bc0535SKrishna Elango { 1328c0da6274SZhi-Jun Robin Fu int circular_count; 1329c0da6274SZhi-Jun Robin Fu dev_info_t *dip = ddi_get_child(rcdip); 1330c0da6274SZhi-Jun Robin Fu pcie_bus_arg_t arg; 1331d4bc0535SKrishna Elango 1332c0da6274SZhi-Jun Robin Fu arg.init = B_TRUE; 1333c0da6274SZhi-Jun Robin Fu arg.flags = flags; 1334d4bc0535SKrishna Elango 1335c0da6274SZhi-Jun Robin Fu ndi_devi_enter(rcdip, &circular_count); 1336c0da6274SZhi-Jun Robin Fu ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg); 1337c0da6274SZhi-Jun Robin Fu ndi_devi_exit(rcdip, circular_count); 1338c0da6274SZhi-Jun Robin Fu } 133926947304SEvan Yan 1340c0da6274SZhi-Jun Robin Fu void 1341c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(dev_info_t *rcdip, uint8_t flags) 1342c0da6274SZhi-Jun Robin Fu { 1343c0da6274SZhi-Jun Robin Fu int circular_count; 1344c0da6274SZhi-Jun Robin Fu dev_info_t *dip = ddi_get_child(rcdip); 1345c0da6274SZhi-Jun Robin Fu pcie_bus_arg_t arg; 134626947304SEvan Yan 1347c0da6274SZhi-Jun Robin Fu arg.init = B_FALSE; 1348c0da6274SZhi-Jun Robin Fu arg.flags = flags; 1349d4bc0535SKrishna Elango 1350c0da6274SZhi-Jun Robin Fu ndi_devi_enter(rcdip, &circular_count); 1351c0da6274SZhi-Jun Robin Fu ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg); 1352c0da6274SZhi-Jun Robin Fu ndi_devi_exit(rcdip, circular_count); 1353d4bc0535SKrishna Elango } 1354d4bc0535SKrishna Elango 1355d4bc0535SKrishna Elango void 1356d4bc0535SKrishna Elango pcie_enable_errors(dev_info_t *dip) 1357d4bc0535SKrishna Elango { 1358d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1359d4bc0535SKrishna Elango uint16_t reg16, tmp16; 1360d4bc0535SKrishna Elango uint32_t reg32, tmp32; 1361d4bc0535SKrishna Elango 1362d4bc0535SKrishna Elango ASSERT(bus_p); 1363d4bc0535SKrishna Elango 1364d4bc0535SKrishna Elango /* 1365d4bc0535SKrishna Elango * Clear any pending errors 1366d4bc0535SKrishna Elango */ 1367d4bc0535SKrishna Elango pcie_clear_errors(dip); 1368d4bc0535SKrishna Elango 1369d4bc0535SKrishna Elango if (!PCIE_IS_PCIE(bus_p)) 1370d4bc0535SKrishna Elango return; 1371d4bc0535SKrishna Elango 1372d4bc0535SKrishna Elango /* 1373d4bc0535SKrishna Elango * Enable Baseline Error Handling but leave CE reporting off (poweron 1374d4bc0535SKrishna Elango * default). 1375d4bc0535SKrishna Elango */ 1376d4bc0535SKrishna Elango if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) != 1377d4bc0535SKrishna Elango PCI_CAP_EINVAL16) { 1378d4bc0535SKrishna Elango tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK | 1379d4bc0535SKrishna Elango PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 1380d4bc0535SKrishna Elango (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 1381d4bc0535SKrishna Elango PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 1382d4bc0535SKrishna Elango (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN)); 1383d4bc0535SKrishna Elango 1384d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16); 1385d4bc0535SKrishna Elango PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16); 1386d4bc0535SKrishna Elango } 1387d4bc0535SKrishna Elango 1388d4bc0535SKrishna Elango /* Enable Root Port Baseline Error Receiving */ 1389d4bc0535SKrishna Elango if (PCIE_IS_ROOT(bus_p) && 1390d4bc0535SKrishna Elango (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) != 1391d4bc0535SKrishna Elango PCI_CAP_EINVAL16) { 1392d4bc0535SKrishna Elango 1393d4bc0535SKrishna Elango tmp16 = pcie_serr_disable_flag ? 1394d4bc0535SKrishna Elango (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) : 1395d4bc0535SKrishna Elango pcie_root_ctrl_default; 1396d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16); 1397d4bc0535SKrishna Elango PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL, 1398d4bc0535SKrishna Elango reg16); 1399d4bc0535SKrishna Elango } 1400d4bc0535SKrishna Elango 1401d4bc0535SKrishna Elango /* 1402d4bc0535SKrishna Elango * Enable PCI-Express Advanced Error Handling if Exists 1403d4bc0535SKrishna Elango */ 1404d4bc0535SKrishna Elango if (!PCIE_HAS_AER(bus_p)) 1405d4bc0535SKrishna Elango return; 1406d4bc0535SKrishna Elango 1407d4bc0535SKrishna Elango /* Set Uncorrectable Severity */ 1408d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) != 1409d4bc0535SKrishna Elango PCI_CAP_EINVAL32) { 1410d4bc0535SKrishna Elango tmp32 = pcie_aer_uce_severity; 1411d4bc0535SKrishna Elango 1412d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32); 1413d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV, 1414d4bc0535SKrishna Elango reg32); 1415d4bc0535SKrishna Elango } 1416d4bc0535SKrishna Elango 1417d4bc0535SKrishna Elango /* Enable Uncorrectable errors */ 1418d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) != 1419d4bc0535SKrishna Elango PCI_CAP_EINVAL32) { 1420d4bc0535SKrishna Elango tmp32 = pcie_aer_uce_mask; 1421d4bc0535SKrishna Elango 1422d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32); 1423d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK, 1424d4bc0535SKrishna Elango reg32); 1425d4bc0535SKrishna Elango } 1426d4bc0535SKrishna Elango 1427d4bc0535SKrishna Elango /* Enable ECRC generation and checking */ 1428d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) != 1429d4bc0535SKrishna Elango PCI_CAP_EINVAL32) { 1430d4bc0535SKrishna Elango tmp32 = reg32 | pcie_ecrc_value; 1431d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32); 1432d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32); 1433d4bc0535SKrishna Elango } 1434d4bc0535SKrishna Elango 1435d4bc0535SKrishna Elango /* Enable Secondary Uncorrectable errors if this is a bridge */ 1436d4bc0535SKrishna Elango if (!PCIE_IS_PCIE_BDG(bus_p)) 1437d4bc0535SKrishna Elango goto root; 1438d4bc0535SKrishna Elango 1439d4bc0535SKrishna Elango /* Set Uncorrectable Severity */ 1440d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) != 1441d4bc0535SKrishna Elango PCI_CAP_EINVAL32) { 1442d4bc0535SKrishna Elango tmp32 = pcie_aer_suce_severity; 1443d4bc0535SKrishna Elango 1444d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32); 1445d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV, 1446d4bc0535SKrishna Elango reg32); 1447d4bc0535SKrishna Elango } 1448d4bc0535SKrishna Elango 1449d4bc0535SKrishna Elango if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) != 1450d4bc0535SKrishna Elango PCI_CAP_EINVAL32) { 1451d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask); 1452d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32, 1453d4bc0535SKrishna Elango PCIE_AER_SUCE_MASK, reg32); 1454d4bc0535SKrishna Elango } 1455d4bc0535SKrishna Elango 1456d4bc0535SKrishna Elango root: 1457d4bc0535SKrishna Elango /* 1458d4bc0535SKrishna Elango * Enable Root Control this is a Root device 1459d4bc0535SKrishna Elango */ 1460d4bc0535SKrishna Elango if (!PCIE_IS_ROOT(bus_p)) 1461d4bc0535SKrishna Elango return; 1462d4bc0535SKrishna Elango 1463d4bc0535SKrishna Elango if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) != 1464d4bc0535SKrishna Elango PCI_CAP_EINVAL16) { 1465d4bc0535SKrishna Elango PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD, 1466d4bc0535SKrishna Elango pcie_root_error_cmd_default); 1467d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16, 1468d4bc0535SKrishna Elango PCIE_AER_RE_CMD, reg16); 1469d4bc0535SKrishna Elango } 1470d4bc0535SKrishna Elango } 1471d4bc0535SKrishna Elango 1472d4bc0535SKrishna Elango /* 1473d4bc0535SKrishna Elango * This function is used for enabling CE reporting and setting the AER CE mask. 1474d4bc0535SKrishna Elango * When called from outside the pcie module it should always be preceded by 1475d4bc0535SKrishna Elango * a call to pcie_enable_errors. 1476d4bc0535SKrishna Elango */ 1477d4bc0535SKrishna Elango int 1478d4bc0535SKrishna Elango pcie_enable_ce(dev_info_t *dip) 1479d4bc0535SKrishna Elango { 1480d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1481d4bc0535SKrishna Elango uint16_t device_sts, device_ctl; 1482d4bc0535SKrishna Elango uint32_t tmp_pcie_aer_ce_mask; 1483d4bc0535SKrishna Elango 1484d4bc0535SKrishna Elango if (!PCIE_IS_PCIE(bus_p)) 1485d4bc0535SKrishna Elango return (DDI_SUCCESS); 1486d4bc0535SKrishna Elango 1487d4bc0535SKrishna Elango /* 1488d4bc0535SKrishna Elango * The "pcie_ce_mask" property is used to control both the CE reporting 1489d4bc0535SKrishna Elango * enable field in the device control register and the AER CE mask. We 1490d4bc0535SKrishna Elango * leave CE reporting disabled if pcie_ce_mask is set to -1. 1491d4bc0535SKrishna Elango */ 1492d4bc0535SKrishna Elango 1493d4bc0535SKrishna Elango tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, 1494d4bc0535SKrishna Elango DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask); 1495d4bc0535SKrishna Elango 1496d4bc0535SKrishna Elango if (tmp_pcie_aer_ce_mask == (uint32_t)-1) { 1497d4bc0535SKrishna Elango /* 1498d4bc0535SKrishna Elango * Nothing to do since CE reporting has already been disabled. 1499d4bc0535SKrishna Elango */ 1500d4bc0535SKrishna Elango return (DDI_SUCCESS); 1501d4bc0535SKrishna Elango } 1502d4bc0535SKrishna Elango 1503d4bc0535SKrishna Elango if (PCIE_HAS_AER(bus_p)) { 1504d4bc0535SKrishna Elango /* Enable AER CE */ 1505d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask); 1506d4bc0535SKrishna Elango PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK, 1507d4bc0535SKrishna Elango 0); 1508d4bc0535SKrishna Elango 1509d4bc0535SKrishna Elango /* Clear any pending AER CE errors */ 1510d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1); 1511d4bc0535SKrishna Elango } 1512d4bc0535SKrishna Elango 1513d4bc0535SKrishna Elango /* clear any pending CE errors */ 1514d4bc0535SKrishna Elango if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) != 1515d4bc0535SKrishna Elango PCI_CAP_EINVAL16) 1516d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS, 1517d4bc0535SKrishna Elango device_sts & (~PCIE_DEVSTS_CE_DETECTED)); 1518d4bc0535SKrishna Elango 1519d4bc0535SKrishna Elango /* Enable CE reporting */ 1520d4bc0535SKrishna Elango device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 1521d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, 1522d4bc0535SKrishna Elango (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default); 1523d4bc0535SKrishna Elango PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl); 1524d4bc0535SKrishna Elango 1525d4bc0535SKrishna Elango return (DDI_SUCCESS); 1526d4bc0535SKrishna Elango } 1527d4bc0535SKrishna Elango 1528d4bc0535SKrishna Elango /* ARGSUSED */ 1529d4bc0535SKrishna Elango void 1530d4bc0535SKrishna Elango pcie_disable_errors(dev_info_t *dip) 1531d4bc0535SKrishna Elango { 1532d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1533d4bc0535SKrishna Elango uint16_t device_ctl; 1534d4bc0535SKrishna Elango uint32_t aer_reg; 1535d4bc0535SKrishna Elango 1536d4bc0535SKrishna Elango if (!PCIE_IS_PCIE(bus_p)) 1537d4bc0535SKrishna Elango return; 1538d4bc0535SKrishna Elango 1539d4bc0535SKrishna Elango /* 1540d4bc0535SKrishna Elango * Disable PCI-Express Baseline Error Handling 1541d4bc0535SKrishna Elango */ 1542d4bc0535SKrishna Elango device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 1543d4bc0535SKrishna Elango device_ctl &= ~PCIE_DEVCTL_ERR_MASK; 1544d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl); 1545d4bc0535SKrishna Elango 1546d4bc0535SKrishna Elango /* 1547d4bc0535SKrishna Elango * Disable PCI-Express Advanced Error Handling if Exists 1548d4bc0535SKrishna Elango */ 1549d4bc0535SKrishna Elango if (!PCIE_HAS_AER(bus_p)) 1550d4bc0535SKrishna Elango goto root; 1551d4bc0535SKrishna Elango 1552d4bc0535SKrishna Elango /* Disable Uncorrectable errors */ 1553d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS); 1554d4bc0535SKrishna Elango 1555d4bc0535SKrishna Elango /* Disable Correctable errors */ 1556d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS); 1557d4bc0535SKrishna Elango 1558d4bc0535SKrishna Elango /* Disable ECRC generation and checking */ 1559d4bc0535SKrishna Elango if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) != 1560d4bc0535SKrishna Elango PCI_CAP_EINVAL32) { 1561d4bc0535SKrishna Elango aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA | 1562d4bc0535SKrishna Elango PCIE_AER_CTL_ECRC_CHECK_ENA); 1563d4bc0535SKrishna Elango 1564d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg); 1565d4bc0535SKrishna Elango } 1566d4bc0535SKrishna Elango /* 1567d4bc0535SKrishna Elango * Disable Secondary Uncorrectable errors if this is a bridge 1568d4bc0535SKrishna Elango */ 1569d4bc0535SKrishna Elango if (!PCIE_IS_PCIE_BDG(bus_p)) 1570d4bc0535SKrishna Elango goto root; 1571d4bc0535SKrishna Elango 1572d4bc0535SKrishna Elango PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS); 1573d4bc0535SKrishna Elango 1574d4bc0535SKrishna Elango root: 1575d4bc0535SKrishna Elango /* 1576d4bc0535SKrishna Elango * disable Root Control this is a Root device 1577d4bc0535SKrishna Elango */ 1578d4bc0535SKrishna Elango if (!PCIE_IS_ROOT(bus_p)) 1579d4bc0535SKrishna Elango return; 1580d4bc0535SKrishna Elango 1581d4bc0535SKrishna Elango if (!pcie_serr_disable_flag) { 1582d4bc0535SKrishna Elango device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL); 1583d4bc0535SKrishna Elango device_ctl &= ~PCIE_ROOT_SYS_ERR; 1584d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl); 1585d4bc0535SKrishna Elango } 1586d4bc0535SKrishna Elango 1587d4bc0535SKrishna Elango if (!PCIE_HAS_AER(bus_p)) 1588d4bc0535SKrishna Elango return; 1589d4bc0535SKrishna Elango 1590d4bc0535SKrishna Elango if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) != 1591d4bc0535SKrishna Elango PCI_CAP_EINVAL16) { 1592d4bc0535SKrishna Elango device_ctl &= ~pcie_root_error_cmd_default; 1593d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl); 1594d4bc0535SKrishna Elango } 1595d4bc0535SKrishna Elango } 1596d4bc0535SKrishna Elango 1597d4bc0535SKrishna Elango /* 1598d4bc0535SKrishna Elango * Extract bdf from "reg" property. 1599d4bc0535SKrishna Elango */ 1600d4bc0535SKrishna Elango int 1601d4bc0535SKrishna Elango pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf) 1602d4bc0535SKrishna Elango { 1603d4bc0535SKrishna Elango pci_regspec_t *regspec; 1604d4bc0535SKrishna Elango int reglen; 1605d4bc0535SKrishna Elango 1606d4bc0535SKrishna Elango if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1607d4bc0535SKrishna Elango "reg", (int **)®spec, (uint_t *)®len) != DDI_SUCCESS) 1608d4bc0535SKrishna Elango return (DDI_FAILURE); 1609d4bc0535SKrishna Elango 1610d4bc0535SKrishna Elango if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) { 1611d4bc0535SKrishna Elango ddi_prop_free(regspec); 1612d4bc0535SKrishna Elango return (DDI_FAILURE); 1613d4bc0535SKrishna Elango } 1614d4bc0535SKrishna Elango 1615d4bc0535SKrishna Elango /* Get phys_hi from first element. All have same bdf. */ 1616d4bc0535SKrishna Elango *bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8; 1617d4bc0535SKrishna Elango 1618d4bc0535SKrishna Elango ddi_prop_free(regspec); 1619d4bc0535SKrishna Elango return (DDI_SUCCESS); 1620d4bc0535SKrishna Elango } 1621d4bc0535SKrishna Elango 1622d4bc0535SKrishna Elango dev_info_t * 1623d4bc0535SKrishna Elango pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 1624d4bc0535SKrishna Elango { 1625d4bc0535SKrishna Elango dev_info_t *cdip = rdip; 1626d4bc0535SKrishna Elango 1627d4bc0535SKrishna Elango for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 1628d4bc0535SKrishna Elango ; 1629d4bc0535SKrishna Elango 1630d4bc0535SKrishna Elango return (cdip); 1631d4bc0535SKrishna Elango } 1632d4bc0535SKrishna Elango 1633d4bc0535SKrishna Elango uint32_t 1634d4bc0535SKrishna Elango pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip) 1635d4bc0535SKrishna Elango { 1636d4bc0535SKrishna Elango dev_info_t *cdip; 1637d4bc0535SKrishna Elango 1638d4bc0535SKrishna Elango /* 1639d4bc0535SKrishna Elango * As part of the probing, the PCI fcode interpreter may setup a DMA 1640d4bc0535SKrishna Elango * request if a given card has a fcode on it using dip and rdip of the 164126947304SEvan Yan * hotplug connector i.e, dip and rdip of px/pcieb driver. In this 1642d4bc0535SKrishna Elango * case, return a invalid value for the bdf since we cannot get to the 1643d4bc0535SKrishna Elango * bdf value of the actual device which will be initiating this DMA. 1644d4bc0535SKrishna Elango */ 1645d4bc0535SKrishna Elango if (rdip == dip) 1646d4bc0535SKrishna Elango return (PCIE_INVALID_BDF); 1647d4bc0535SKrishna Elango 1648d4bc0535SKrishna Elango cdip = pcie_get_my_childs_dip(dip, rdip); 1649d4bc0535SKrishna Elango 1650d4bc0535SKrishna Elango /* 1651d4bc0535SKrishna Elango * For a given rdip, return the bdf value of dip's (px or pcieb) 1652d4bc0535SKrishna Elango * immediate child or secondary bus-id if dip is a PCIe2PCI bridge. 1653d4bc0535SKrishna Elango * 1654d4bc0535SKrishna Elango * XXX - For now, return a invalid bdf value for all PCI and PCI-X 1655d4bc0535SKrishna Elango * devices since this needs more work. 1656d4bc0535SKrishna Elango */ 1657d4bc0535SKrishna Elango return (PCI_GET_PCIE2PCI_SECBUS(cdip) ? 1658d4bc0535SKrishna Elango PCIE_INVALID_BDF : PCI_GET_BDF(cdip)); 1659d4bc0535SKrishna Elango } 1660d4bc0535SKrishna Elango 1661d4bc0535SKrishna Elango uint32_t 1662d4bc0535SKrishna Elango pcie_get_aer_uce_mask() { 1663d4bc0535SKrishna Elango return (pcie_aer_uce_mask); 1664d4bc0535SKrishna Elango } 1665d4bc0535SKrishna Elango uint32_t 1666d4bc0535SKrishna Elango pcie_get_aer_ce_mask() { 1667d4bc0535SKrishna Elango return (pcie_aer_ce_mask); 1668d4bc0535SKrishna Elango } 1669d4bc0535SKrishna Elango uint32_t 1670d4bc0535SKrishna Elango pcie_get_aer_suce_mask() { 1671d4bc0535SKrishna Elango return (pcie_aer_suce_mask); 1672d4bc0535SKrishna Elango } 1673d4bc0535SKrishna Elango uint32_t 1674d4bc0535SKrishna Elango pcie_get_serr_mask() { 1675d4bc0535SKrishna Elango return (pcie_serr_disable_flag); 1676d4bc0535SKrishna Elango } 1677d4bc0535SKrishna Elango 1678d4bc0535SKrishna Elango void 1679d4bc0535SKrishna Elango pcie_set_aer_uce_mask(uint32_t mask) { 1680d4bc0535SKrishna Elango pcie_aer_uce_mask = mask; 1681d4bc0535SKrishna Elango if (mask & PCIE_AER_UCE_UR) 1682d4bc0535SKrishna Elango pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN; 1683d4bc0535SKrishna Elango else 1684d4bc0535SKrishna Elango pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN; 1685d4bc0535SKrishna Elango 1686d4bc0535SKrishna Elango if (mask & PCIE_AER_UCE_ECRC) 1687d4bc0535SKrishna Elango pcie_ecrc_value = 0; 1688d4bc0535SKrishna Elango } 1689d4bc0535SKrishna Elango 1690d4bc0535SKrishna Elango void 1691d4bc0535SKrishna Elango pcie_set_aer_ce_mask(uint32_t mask) { 1692d4bc0535SKrishna Elango pcie_aer_ce_mask = mask; 1693d4bc0535SKrishna Elango } 1694d4bc0535SKrishna Elango void 1695d4bc0535SKrishna Elango pcie_set_aer_suce_mask(uint32_t mask) { 1696d4bc0535SKrishna Elango pcie_aer_suce_mask = mask; 1697d4bc0535SKrishna Elango } 1698d4bc0535SKrishna Elango void 1699d4bc0535SKrishna Elango pcie_set_serr_mask(uint32_t mask) { 1700d4bc0535SKrishna Elango pcie_serr_disable_flag = mask; 1701d4bc0535SKrishna Elango } 1702d4bc0535SKrishna Elango 1703d4bc0535SKrishna Elango /* 1704d4bc0535SKrishna Elango * Is the rdip a child of dip. Used for checking certain CTLOPS from bubbling 1705d4bc0535SKrishna Elango * up erronously. Ex. ISA ctlops to a PCI-PCI Bridge. 1706d4bc0535SKrishna Elango */ 1707d4bc0535SKrishna Elango boolean_t 1708d4bc0535SKrishna Elango pcie_is_child(dev_info_t *dip, dev_info_t *rdip) 1709d4bc0535SKrishna Elango { 1710d4bc0535SKrishna Elango dev_info_t *cdip = ddi_get_child(dip); 1711d4bc0535SKrishna Elango for (; cdip; cdip = ddi_get_next_sibling(cdip)) 1712d4bc0535SKrishna Elango if (cdip == rdip) 1713d4bc0535SKrishna Elango break; 1714d4bc0535SKrishna Elango return (cdip != NULL); 1715d4bc0535SKrishna Elango } 1716d4bc0535SKrishna Elango 1717d4bc0535SKrishna Elango boolean_t 1718d4bc0535SKrishna Elango pcie_is_link_disabled(dev_info_t *dip) 1719d4bc0535SKrishna Elango { 1720d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1721d4bc0535SKrishna Elango 1722d4bc0535SKrishna Elango if (PCIE_IS_PCIE(bus_p)) { 1723d4bc0535SKrishna Elango if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) & 1724d4bc0535SKrishna Elango PCIE_LINKCTL_LINK_DISABLE) 1725d4bc0535SKrishna Elango return (B_TRUE); 1726d4bc0535SKrishna Elango } 1727d4bc0535SKrishna Elango return (B_FALSE); 1728d4bc0535SKrishna Elango } 1729d4bc0535SKrishna Elango 1730d4bc0535SKrishna Elango /* 1731d4bc0535SKrishna Elango * Initialize the MPS for a root port. 1732d4bc0535SKrishna Elango * 1733d4bc0535SKrishna Elango * dip - dip of root port device. 1734d4bc0535SKrishna Elango */ 1735d4bc0535SKrishna Elango void 1736d4bc0535SKrishna Elango pcie_init_root_port_mps(dev_info_t *dip) 1737d4bc0535SKrishna Elango { 1738d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1739d4bc0535SKrishna Elango int rp_cap, max_supported = pcie_max_mps; 1740d4bc0535SKrishna Elango 1741d4bc0535SKrishna Elango (void) pcie_get_fabric_mps(ddi_get_parent(dip), 1742d4bc0535SKrishna Elango ddi_get_child(dip), &max_supported); 1743d4bc0535SKrishna Elango 1744d4bc0535SKrishna Elango rp_cap = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL, 1745d4bc0535SKrishna Elango bus_p->bus_pcie_off, PCIE_DEVCAP) & 1746d4bc0535SKrishna Elango PCIE_DEVCAP_MAX_PAYLOAD_MASK; 1747d4bc0535SKrishna Elango 1748d4bc0535SKrishna Elango if (rp_cap < max_supported) 1749d4bc0535SKrishna Elango max_supported = rp_cap; 1750d4bc0535SKrishna Elango 1751d4bc0535SKrishna Elango bus_p->bus_mps = max_supported; 1752d4bc0535SKrishna Elango (void) pcie_initchild_mps(dip); 1753d4bc0535SKrishna Elango } 1754d4bc0535SKrishna Elango 1755d4bc0535SKrishna Elango /* 1756d4bc0535SKrishna Elango * Initialize the Maximum Payload Size of a device. 1757d4bc0535SKrishna Elango * 1758d4bc0535SKrishna Elango * cdip - dip of device. 1759d4bc0535SKrishna Elango * 1760d4bc0535SKrishna Elango * returns - DDI_SUCCESS or DDI_FAILURE 1761d4bc0535SKrishna Elango */ 1762d4bc0535SKrishna Elango int 1763d4bc0535SKrishna Elango pcie_initchild_mps(dev_info_t *cdip) 1764d4bc0535SKrishna Elango { 1765d4bc0535SKrishna Elango pcie_bus_t *bus_p; 1766d4bc0535SKrishna Elango dev_info_t *pdip = ddi_get_parent(cdip); 176726947304SEvan Yan uint8_t dev_type; 1768d4bc0535SKrishna Elango 1769d4bc0535SKrishna Elango bus_p = PCIE_DIP2BUS(cdip); 1770d4bc0535SKrishna Elango if (bus_p == NULL) { 1771d4bc0535SKrishna Elango PCIE_DBG("%s: BUS not found.\n", 1772d4bc0535SKrishna Elango ddi_driver_name(cdip)); 1773d4bc0535SKrishna Elango return (DDI_FAILURE); 1774d4bc0535SKrishna Elango } 1775d4bc0535SKrishna Elango 177626947304SEvan Yan dev_type = bus_p->bus_dev_type; 177726947304SEvan Yan 177826947304SEvan Yan /* 177926947304SEvan Yan * For ARI Devices, only function zero's MPS needs to be set. 178026947304SEvan Yan */ 178126947304SEvan Yan if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) && 178226947304SEvan Yan (pcie_ari_is_enabled(pdip) == PCIE_ARI_FORW_ENABLED)) { 178326947304SEvan Yan pcie_req_id_t child_bdf; 178426947304SEvan Yan 178526947304SEvan Yan if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE) 178626947304SEvan Yan return (DDI_FAILURE); 178726947304SEvan Yan if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) != 0) 178826947304SEvan Yan return (DDI_SUCCESS); 178926947304SEvan Yan } 179026947304SEvan Yan 17919187c210SAlan Adamson, SD OSSD if (PCIE_IS_PCIE(bus_p)) { 17929187c210SAlan Adamson, SD OSSD int suggested_mrrs, fabric_mps; 17939187c210SAlan Adamson, SD OSSD uint16_t device_mps, device_mps_cap, device_mrrs, dev_ctrl; 1794d4bc0535SKrishna Elango 17959187c210SAlan Adamson, SD OSSD dev_ctrl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL); 179683e6495bSDaniel Ice if ((fabric_mps = (PCIE_IS_RP(bus_p) ? bus_p : 179783e6495bSDaniel Ice PCIE_DIP2BUS(pdip))->bus_mps) < 0) { 179883e6495bSDaniel Ice dev_ctrl = (dev_ctrl & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 179983e6495bSDaniel Ice PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | 180083e6495bSDaniel Ice (pcie_devctl_default & 180183e6495bSDaniel Ice (PCIE_DEVCTL_MAX_READ_REQ_MASK | 180283e6495bSDaniel Ice PCIE_DEVCTL_MAX_PAYLOAD_MASK)); 180383e6495bSDaniel Ice 180483e6495bSDaniel Ice PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl); 180583e6495bSDaniel Ice return (DDI_SUCCESS); 180683e6495bSDaniel Ice } 18079187c210SAlan Adamson, SD OSSD 18089187c210SAlan Adamson, SD OSSD device_mps_cap = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) & 1809d4bc0535SKrishna Elango PCIE_DEVCAP_MAX_PAYLOAD_MASK; 1810d4bc0535SKrishna Elango 18119187c210SAlan Adamson, SD OSSD device_mrrs = (dev_ctrl & PCIE_DEVCTL_MAX_READ_REQ_MASK) >> 18129187c210SAlan Adamson, SD OSSD PCIE_DEVCTL_MAX_READ_REQ_SHIFT; 18139187c210SAlan Adamson, SD OSSD 18149187c210SAlan Adamson, SD OSSD if (device_mps_cap < fabric_mps) 18159187c210SAlan Adamson, SD OSSD device_mrrs = device_mps = device_mps_cap; 18169187c210SAlan Adamson, SD OSSD else 18179187c210SAlan Adamson, SD OSSD device_mps = (uint16_t)fabric_mps; 18189187c210SAlan Adamson, SD OSSD 18199187c210SAlan Adamson, SD OSSD suggested_mrrs = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, 18209187c210SAlan Adamson, SD OSSD cdip, DDI_PROP_DONTPASS, "suggested-mrrs", device_mrrs); 18219187c210SAlan Adamson, SD OSSD 18229187c210SAlan Adamson, SD OSSD if ((device_mps == fabric_mps) || 18239187c210SAlan Adamson, SD OSSD (suggested_mrrs < device_mrrs)) 18249187c210SAlan Adamson, SD OSSD device_mrrs = (uint16_t)suggested_mrrs; 1825d4bc0535SKrishna Elango 1826d4bc0535SKrishna Elango /* 18279187c210SAlan Adamson, SD OSSD * Replace MPS and MRRS settings. 1828d4bc0535SKrishna Elango */ 18299187c210SAlan Adamson, SD OSSD dev_ctrl &= ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 18309187c210SAlan Adamson, SD OSSD PCIE_DEVCTL_MAX_PAYLOAD_MASK); 1831d4bc0535SKrishna Elango 18329187c210SAlan Adamson, SD OSSD dev_ctrl |= ((device_mrrs << PCIE_DEVCTL_MAX_READ_REQ_SHIFT) | 18339187c210SAlan Adamson, SD OSSD device_mps << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT); 1834d4bc0535SKrishna Elango 1835d4bc0535SKrishna Elango PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl); 1836d4bc0535SKrishna Elango 18379187c210SAlan Adamson, SD OSSD bus_p->bus_mps = device_mps; 1838d4bc0535SKrishna Elango } 183926947304SEvan Yan 1840d4bc0535SKrishna Elango return (DDI_SUCCESS); 1841d4bc0535SKrishna Elango } 1842d4bc0535SKrishna Elango 1843d4bc0535SKrishna Elango /* 1844d4bc0535SKrishna Elango * Scans a device tree/branch for a maximum payload size capabilities. 1845d4bc0535SKrishna Elango * 1846d4bc0535SKrishna Elango * rc_dip - dip of Root Complex. 1847d4bc0535SKrishna Elango * dip - dip of device where scan will begin. 1848d4bc0535SKrishna Elango * max_supported (IN) - maximum allowable MPS. 1849d4bc0535SKrishna Elango * max_supported (OUT) - maximum payload size capability of fabric. 1850d4bc0535SKrishna Elango */ 1851d4bc0535SKrishna Elango void 1852d4bc0535SKrishna Elango pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported) 1853d4bc0535SKrishna Elango { 1854d4bc0535SKrishna Elango if (dip == NULL) 1855d4bc0535SKrishna Elango return; 1856d4bc0535SKrishna Elango 1857d4bc0535SKrishna Elango /* 1858d4bc0535SKrishna Elango * Perform a fabric scan to obtain Maximum Payload Capabilities 1859d4bc0535SKrishna Elango */ 1860d4bc0535SKrishna Elango (void) pcie_scan_mps(rc_dip, dip, max_supported); 1861d4bc0535SKrishna Elango 1862d4bc0535SKrishna Elango PCIE_DBG("MPS: Highest Common MPS= %x\n", max_supported); 1863d4bc0535SKrishna Elango } 1864d4bc0535SKrishna Elango 1865d4bc0535SKrishna Elango /* 1866d4bc0535SKrishna Elango * Scans fabric and determines Maximum Payload Size based on 1867d4bc0535SKrishna Elango * highest common denominator alogorithm 1868d4bc0535SKrishna Elango */ 1869d4bc0535SKrishna Elango static void 1870d4bc0535SKrishna Elango pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported) 1871d4bc0535SKrishna Elango { 1872d4bc0535SKrishna Elango int circular_count; 1873d4bc0535SKrishna Elango pcie_max_supported_t max_pay_load_supported; 1874d4bc0535SKrishna Elango 1875d4bc0535SKrishna Elango max_pay_load_supported.dip = rc_dip; 1876d4bc0535SKrishna Elango max_pay_load_supported.highest_common_mps = *max_supported; 1877d4bc0535SKrishna Elango 1878d4bc0535SKrishna Elango ndi_devi_enter(ddi_get_parent(dip), &circular_count); 1879d4bc0535SKrishna Elango ddi_walk_devs(dip, pcie_get_max_supported, 1880d4bc0535SKrishna Elango (void *)&max_pay_load_supported); 1881d4bc0535SKrishna Elango ndi_devi_exit(ddi_get_parent(dip), circular_count); 188226947304SEvan Yan 1883d4bc0535SKrishna Elango *max_supported = max_pay_load_supported.highest_common_mps; 1884d4bc0535SKrishna Elango } 1885d4bc0535SKrishna Elango 1886d4bc0535SKrishna Elango /* 1887d4bc0535SKrishna Elango * Called as part of the Maximum Payload Size scan. 1888d4bc0535SKrishna Elango */ 1889d4bc0535SKrishna Elango static int 1890d4bc0535SKrishna Elango pcie_get_max_supported(dev_info_t *dip, void *arg) 1891d4bc0535SKrishna Elango { 1892d4bc0535SKrishna Elango uint32_t max_supported; 1893d4bc0535SKrishna Elango uint16_t cap_ptr; 1894d4bc0535SKrishna Elango pcie_max_supported_t *current = (pcie_max_supported_t *)arg; 1895d4bc0535SKrishna Elango pci_regspec_t *reg; 1896d4bc0535SKrishna Elango int rlen; 1897d4bc0535SKrishna Elango caddr_t virt; 1898d4bc0535SKrishna Elango ddi_acc_handle_t config_handle; 1899d4bc0535SKrishna Elango 1900d4bc0535SKrishna Elango if (ddi_get_child(current->dip) == NULL) { 1901d4bc0535SKrishna Elango goto fail1; 1902d4bc0535SKrishna Elango } 1903d4bc0535SKrishna Elango 1904d4bc0535SKrishna Elango if (pcie_dev(dip) == DDI_FAILURE) { 1905d4bc0535SKrishna Elango PCIE_DBG("MPS: pcie_get_max_supported: %s: " 1906d4bc0535SKrishna Elango "Not a PCIe dev\n", ddi_driver_name(dip)); 1907d4bc0535SKrishna Elango goto fail1; 1908d4bc0535SKrishna Elango } 1909d4bc0535SKrishna Elango 19109187c210SAlan Adamson, SD OSSD /* 19119187c210SAlan Adamson, SD OSSD * If the suggested-mrrs property exists, then don't include this 19129187c210SAlan Adamson, SD OSSD * device in the MPS capabilities scan. 19139187c210SAlan Adamson, SD OSSD */ 19149187c210SAlan Adamson, SD OSSD if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 19159187c210SAlan Adamson, SD OSSD "suggested-mrrs") != 0) 19169187c210SAlan Adamson, SD OSSD goto fail1; 19179187c210SAlan Adamson, SD OSSD 1918d4bc0535SKrishna Elango if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", 1919d4bc0535SKrishna Elango (caddr_t)®, &rlen) != DDI_PROP_SUCCESS) { 1920d4bc0535SKrishna Elango PCIE_DBG("MPS: pcie_get_max_supported: %s: " 1921d4bc0535SKrishna Elango "Can not read reg\n", ddi_driver_name(dip)); 1922d4bc0535SKrishna Elango goto fail1; 1923d4bc0535SKrishna Elango } 1924d4bc0535SKrishna Elango 1925d4bc0535SKrishna Elango if (pcie_map_phys(ddi_get_child(current->dip), reg, &virt, 1926d4bc0535SKrishna Elango &config_handle) != DDI_SUCCESS) { 1927d4bc0535SKrishna Elango PCIE_DBG("MPS: pcie_get_max_supported: %s: pcie_map_phys " 1928d4bc0535SKrishna Elango "failed\n", ddi_driver_name(dip)); 1929d4bc0535SKrishna Elango goto fail2; 1930d4bc0535SKrishna Elango } 1931d4bc0535SKrishna Elango 1932d4bc0535SKrishna Elango if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) == 1933d4bc0535SKrishna Elango DDI_FAILURE) { 1934d4bc0535SKrishna Elango goto fail3; 1935d4bc0535SKrishna Elango } 1936d4bc0535SKrishna Elango 1937d4bc0535SKrishna Elango max_supported = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 1938d4bc0535SKrishna Elango PCIE_DEVCAP) & PCIE_DEVCAP_MAX_PAYLOAD_MASK; 1939d4bc0535SKrishna Elango 1940d4bc0535SKrishna Elango PCIE_DBG("PCIE MPS: %s: MPS Capabilities %x\n", ddi_driver_name(dip), 1941d4bc0535SKrishna Elango max_supported); 1942d4bc0535SKrishna Elango 1943d4bc0535SKrishna Elango if (max_supported < current->highest_common_mps) 1944d4bc0535SKrishna Elango current->highest_common_mps = max_supported; 1945d4bc0535SKrishna Elango 1946d4bc0535SKrishna Elango fail3: 1947d4bc0535SKrishna Elango pcie_unmap_phys(&config_handle, reg); 1948d4bc0535SKrishna Elango fail2: 1949d4bc0535SKrishna Elango kmem_free(reg, rlen); 1950d4bc0535SKrishna Elango fail1: 1951d4bc0535SKrishna Elango return (DDI_WALK_CONTINUE); 1952d4bc0535SKrishna Elango } 1953d4bc0535SKrishna Elango 1954d4bc0535SKrishna Elango /* 1955d4bc0535SKrishna Elango * Determines if there are any root ports attached to a root complex. 1956d4bc0535SKrishna Elango * 1957d4bc0535SKrishna Elango * dip - dip of root complex 1958d4bc0535SKrishna Elango * 1959d4bc0535SKrishna Elango * Returns - DDI_SUCCESS if there is at least one root port otherwise 1960d4bc0535SKrishna Elango * DDI_FAILURE. 1961d4bc0535SKrishna Elango */ 1962d4bc0535SKrishna Elango int 1963d4bc0535SKrishna Elango pcie_root_port(dev_info_t *dip) 1964d4bc0535SKrishna Elango { 1965d4bc0535SKrishna Elango int port_type; 1966d4bc0535SKrishna Elango uint16_t cap_ptr; 1967d4bc0535SKrishna Elango ddi_acc_handle_t config_handle; 1968d4bc0535SKrishna Elango dev_info_t *cdip = ddi_get_child(dip); 1969d4bc0535SKrishna Elango 1970d4bc0535SKrishna Elango /* 1971d4bc0535SKrishna Elango * Determine if any of the children of the passed in dip 1972d4bc0535SKrishna Elango * are root ports. 1973d4bc0535SKrishna Elango */ 1974d4bc0535SKrishna Elango for (; cdip; cdip = ddi_get_next_sibling(cdip)) { 1975d4bc0535SKrishna Elango 1976d4bc0535SKrishna Elango if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS) 1977d4bc0535SKrishna Elango continue; 1978d4bc0535SKrishna Elango 1979d4bc0535SKrishna Elango if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, 1980d4bc0535SKrishna Elango &cap_ptr)) == DDI_FAILURE) { 1981d4bc0535SKrishna Elango pci_config_teardown(&config_handle); 1982d4bc0535SKrishna Elango continue; 1983d4bc0535SKrishna Elango } 1984d4bc0535SKrishna Elango 1985d4bc0535SKrishna Elango port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr, 1986d4bc0535SKrishna Elango PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK; 1987d4bc0535SKrishna Elango 1988d4bc0535SKrishna Elango pci_config_teardown(&config_handle); 1989d4bc0535SKrishna Elango 1990d4bc0535SKrishna Elango if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT) 1991d4bc0535SKrishna Elango return (DDI_SUCCESS); 1992d4bc0535SKrishna Elango } 1993d4bc0535SKrishna Elango 1994d4bc0535SKrishna Elango /* No root ports were found */ 1995d4bc0535SKrishna Elango 1996d4bc0535SKrishna Elango return (DDI_FAILURE); 1997d4bc0535SKrishna Elango } 1998d4bc0535SKrishna Elango 1999d4bc0535SKrishna Elango /* 2000d4bc0535SKrishna Elango * Function that determines if a device a PCIe device. 2001d4bc0535SKrishna Elango * 2002d4bc0535SKrishna Elango * dip - dip of device. 2003d4bc0535SKrishna Elango * 2004d4bc0535SKrishna Elango * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE. 2005d4bc0535SKrishna Elango */ 2006d4bc0535SKrishna Elango int 2007d4bc0535SKrishna Elango pcie_dev(dev_info_t *dip) 2008d4bc0535SKrishna Elango { 2009d4bc0535SKrishna Elango /* get parent device's device_type property */ 2010d4bc0535SKrishna Elango char *device_type; 2011d4bc0535SKrishna Elango int rc = DDI_FAILURE; 2012d4bc0535SKrishna Elango dev_info_t *pdip = ddi_get_parent(dip); 2013d4bc0535SKrishna Elango 2014d4bc0535SKrishna Elango if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 2015d4bc0535SKrishna Elango DDI_PROP_DONTPASS, "device_type", &device_type) 2016d4bc0535SKrishna Elango != DDI_PROP_SUCCESS) { 2017d4bc0535SKrishna Elango return (DDI_FAILURE); 2018d4bc0535SKrishna Elango } 2019d4bc0535SKrishna Elango 2020d4bc0535SKrishna Elango if (strcmp(device_type, "pciex") == 0) 2021d4bc0535SKrishna Elango rc = DDI_SUCCESS; 2022d4bc0535SKrishna Elango else 2023d4bc0535SKrishna Elango rc = DDI_FAILURE; 2024d4bc0535SKrishna Elango 2025d4bc0535SKrishna Elango ddi_prop_free(device_type); 2026d4bc0535SKrishna Elango return (rc); 2027d4bc0535SKrishna Elango } 2028d4bc0535SKrishna Elango 2029d4bc0535SKrishna Elango /* 2030d4bc0535SKrishna Elango * Function to map in a device's memory space. 2031d4bc0535SKrishna Elango */ 2032d4bc0535SKrishna Elango static int 2033d4bc0535SKrishna Elango pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec, 2034d4bc0535SKrishna Elango caddr_t *addrp, ddi_acc_handle_t *handlep) 2035d4bc0535SKrishna Elango { 2036d4bc0535SKrishna Elango ddi_map_req_t mr; 2037d4bc0535SKrishna Elango ddi_acc_hdl_t *hp; 2038d4bc0535SKrishna Elango int result; 2039d4bc0535SKrishna Elango ddi_device_acc_attr_t attr; 2040d4bc0535SKrishna Elango 2041d4bc0535SKrishna Elango attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 2042d4bc0535SKrishna Elango attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 2043d4bc0535SKrishna Elango attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 2044d4bc0535SKrishna Elango attr.devacc_attr_access = DDI_CAUTIOUS_ACC; 2045d4bc0535SKrishna Elango 2046d4bc0535SKrishna Elango *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 2047d4bc0535SKrishna Elango hp = impl_acc_hdl_get(*handlep); 2048d4bc0535SKrishna Elango hp->ah_vers = VERS_ACCHDL; 2049d4bc0535SKrishna Elango hp->ah_dip = dip; 2050d4bc0535SKrishna Elango hp->ah_rnumber = 0; 2051d4bc0535SKrishna Elango hp->ah_offset = 0; 2052d4bc0535SKrishna Elango hp->ah_len = 0; 2053d4bc0535SKrishna Elango hp->ah_acc = attr; 2054d4bc0535SKrishna Elango 2055d4bc0535SKrishna Elango mr.map_op = DDI_MO_MAP_LOCKED; 2056d4bc0535SKrishna Elango mr.map_type = DDI_MT_REGSPEC; 2057d4bc0535SKrishna Elango mr.map_obj.rp = (struct regspec *)phys_spec; 2058d4bc0535SKrishna Elango mr.map_prot = PROT_READ | PROT_WRITE; 2059d4bc0535SKrishna Elango mr.map_flags = DDI_MF_KERNEL_MAPPING; 2060d4bc0535SKrishna Elango mr.map_handlep = hp; 2061d4bc0535SKrishna Elango mr.map_vers = DDI_MAP_VERSION; 2062d4bc0535SKrishna Elango 2063d4bc0535SKrishna Elango result = ddi_map(dip, &mr, 0, 0, addrp); 2064d4bc0535SKrishna Elango 2065d4bc0535SKrishna Elango if (result != DDI_SUCCESS) { 2066d4bc0535SKrishna Elango impl_acc_hdl_free(*handlep); 2067d4bc0535SKrishna Elango *handlep = (ddi_acc_handle_t)NULL; 2068d4bc0535SKrishna Elango } else { 2069d4bc0535SKrishna Elango hp->ah_addr = *addrp; 2070d4bc0535SKrishna Elango } 2071d4bc0535SKrishna Elango 2072d4bc0535SKrishna Elango return (result); 2073d4bc0535SKrishna Elango } 2074d4bc0535SKrishna Elango 2075d4bc0535SKrishna Elango /* 2076d4bc0535SKrishna Elango * Map out memory that was mapped in with pcie_map_phys(); 2077d4bc0535SKrishna Elango */ 2078d4bc0535SKrishna Elango static void 2079d4bc0535SKrishna Elango pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph) 2080d4bc0535SKrishna Elango { 2081d4bc0535SKrishna Elango ddi_map_req_t mr; 2082d4bc0535SKrishna Elango ddi_acc_hdl_t *hp; 2083d4bc0535SKrishna Elango 2084d4bc0535SKrishna Elango hp = impl_acc_hdl_get(*handlep); 2085d4bc0535SKrishna Elango ASSERT(hp); 2086d4bc0535SKrishna Elango 2087d4bc0535SKrishna Elango mr.map_op = DDI_MO_UNMAP; 2088d4bc0535SKrishna Elango mr.map_type = DDI_MT_REGSPEC; 2089d4bc0535SKrishna Elango mr.map_obj.rp = (struct regspec *)ph; 2090d4bc0535SKrishna Elango mr.map_prot = PROT_READ | PROT_WRITE; 2091d4bc0535SKrishna Elango mr.map_flags = DDI_MF_KERNEL_MAPPING; 2092d4bc0535SKrishna Elango mr.map_handlep = hp; 2093d4bc0535SKrishna Elango mr.map_vers = DDI_MAP_VERSION; 2094d4bc0535SKrishna Elango 2095d4bc0535SKrishna Elango (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset, 2096d4bc0535SKrishna Elango hp->ah_len, &hp->ah_addr); 2097d4bc0535SKrishna Elango 2098d4bc0535SKrishna Elango impl_acc_hdl_free(*handlep); 2099d4bc0535SKrishna Elango *handlep = (ddi_acc_handle_t)NULL; 2100d4bc0535SKrishna Elango } 2101d4bc0535SKrishna Elango 2102d4bc0535SKrishna Elango void 2103d4bc0535SKrishna Elango pcie_set_rber_fatal(dev_info_t *dip, boolean_t val) 2104d4bc0535SKrishna Elango { 2105d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 2106d4bc0535SKrishna Elango bus_p->bus_pfd->pe_rber_fatal = val; 2107d4bc0535SKrishna Elango } 2108d4bc0535SKrishna Elango 2109d4bc0535SKrishna Elango /* 2110d4bc0535SKrishna Elango * Return parent Root Port's pe_rber_fatal value. 2111d4bc0535SKrishna Elango */ 2112d4bc0535SKrishna Elango boolean_t 2113d4bc0535SKrishna Elango pcie_get_rber_fatal(dev_info_t *dip) 2114d4bc0535SKrishna Elango { 2115d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 2116d4bc0535SKrishna Elango pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip); 2117d4bc0535SKrishna Elango return (rp_bus_p->bus_pfd->pe_rber_fatal); 2118d4bc0535SKrishna Elango } 2119d4bc0535SKrishna Elango 212026947304SEvan Yan int 212126947304SEvan Yan pcie_ari_supported(dev_info_t *dip) 212226947304SEvan Yan { 212326947304SEvan Yan uint32_t devcap2; 212426947304SEvan Yan uint16_t pciecap; 212526947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 212626947304SEvan Yan uint8_t dev_type; 212726947304SEvan Yan 212826947304SEvan Yan PCIE_DBG("pcie_ari_supported: dip=%p\n", dip); 212926947304SEvan Yan 213026947304SEvan Yan if (bus_p == NULL) 213126947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED); 213226947304SEvan Yan 213326947304SEvan Yan dev_type = bus_p->bus_dev_type; 213426947304SEvan Yan 213526947304SEvan Yan if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) && 213626947304SEvan Yan (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT)) 213726947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED); 213826947304SEvan Yan 213926947304SEvan Yan if (pcie_disable_ari) { 214026947304SEvan Yan PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip); 214126947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED); 214226947304SEvan Yan } 214326947304SEvan Yan 214426947304SEvan Yan pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP); 214526947304SEvan Yan 214626947304SEvan Yan if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) { 214726947304SEvan Yan PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip); 214826947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED); 214926947304SEvan Yan } 215026947304SEvan Yan 215126947304SEvan Yan devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2); 215226947304SEvan Yan 215326947304SEvan Yan PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n", 215426947304SEvan Yan dip, devcap2); 215526947304SEvan Yan 215626947304SEvan Yan if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) { 215726947304SEvan Yan PCIE_DBG("pcie_ari_supported: " 215826947304SEvan Yan "dip=%p: ARI Forwarding is supported\n", dip); 215926947304SEvan Yan return (PCIE_ARI_FORW_SUPPORTED); 216026947304SEvan Yan } 216126947304SEvan Yan return (PCIE_ARI_FORW_NOT_SUPPORTED); 216226947304SEvan Yan } 216326947304SEvan Yan 216426947304SEvan Yan int 216526947304SEvan Yan pcie_ari_enable(dev_info_t *dip) 216626947304SEvan Yan { 216726947304SEvan Yan uint16_t devctl2; 216826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 216926947304SEvan Yan 217026947304SEvan Yan PCIE_DBG("pcie_ari_enable: dip=%p\n", dip); 217126947304SEvan Yan 217226947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 217326947304SEvan Yan return (DDI_FAILURE); 217426947304SEvan Yan 217526947304SEvan Yan devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2); 217626947304SEvan Yan devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN; 217726947304SEvan Yan PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2); 217826947304SEvan Yan 217926947304SEvan Yan PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n", 218026947304SEvan Yan dip, devctl2); 218126947304SEvan Yan 218226947304SEvan Yan return (DDI_SUCCESS); 218326947304SEvan Yan } 218426947304SEvan Yan 218526947304SEvan Yan int 218626947304SEvan Yan pcie_ari_disable(dev_info_t *dip) 218726947304SEvan Yan { 218826947304SEvan Yan uint16_t devctl2; 218926947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 219026947304SEvan Yan 219126947304SEvan Yan PCIE_DBG("pcie_ari_disable: dip=%p\n", dip); 219226947304SEvan Yan 219326947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 219426947304SEvan Yan return (DDI_FAILURE); 219526947304SEvan Yan 219626947304SEvan Yan devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2); 219726947304SEvan Yan devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN; 219826947304SEvan Yan PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2); 219926947304SEvan Yan 220026947304SEvan Yan PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n", 220126947304SEvan Yan dip, devctl2); 220226947304SEvan Yan 220326947304SEvan Yan return (DDI_SUCCESS); 220426947304SEvan Yan } 220526947304SEvan Yan 220626947304SEvan Yan int 220726947304SEvan Yan pcie_ari_is_enabled(dev_info_t *dip) 220826947304SEvan Yan { 220926947304SEvan Yan uint16_t devctl2; 221026947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 221126947304SEvan Yan 221226947304SEvan Yan PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip); 221326947304SEvan Yan 221426947304SEvan Yan if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED) 221526947304SEvan Yan return (PCIE_ARI_FORW_DISABLED); 221626947304SEvan Yan 221726947304SEvan Yan devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2); 221826947304SEvan Yan 221926947304SEvan Yan PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n", 222026947304SEvan Yan dip, devctl2); 222126947304SEvan Yan 222226947304SEvan Yan if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) { 222326947304SEvan Yan PCIE_DBG("pcie_ari_is_enabled: " 222426947304SEvan Yan "dip=%p: ARI Forwarding is enabled\n", dip); 222526947304SEvan Yan return (PCIE_ARI_FORW_ENABLED); 222626947304SEvan Yan } 222726947304SEvan Yan 222826947304SEvan Yan return (PCIE_ARI_FORW_DISABLED); 222926947304SEvan Yan } 223026947304SEvan Yan 223126947304SEvan Yan int 223226947304SEvan Yan pcie_ari_device(dev_info_t *dip) 223326947304SEvan Yan { 223426947304SEvan Yan ddi_acc_handle_t handle; 223526947304SEvan Yan uint16_t cap_ptr; 223626947304SEvan Yan 223726947304SEvan Yan PCIE_DBG("pcie_ari_device: dip=%p\n", dip); 223826947304SEvan Yan 223926947304SEvan Yan /* 224026947304SEvan Yan * XXX - This function may be called before the bus_p structure 224126947304SEvan Yan * has been populated. This code can be changed to remove 224226947304SEvan Yan * pci_config_setup()/pci_config_teardown() when the RFE 224326947304SEvan Yan * to populate the bus_p structures early in boot is putback. 224426947304SEvan Yan */ 224526947304SEvan Yan 224626947304SEvan Yan /* First make sure it is a PCIe device */ 224726947304SEvan Yan 224826947304SEvan Yan if (pci_config_setup(dip, &handle) != DDI_SUCCESS) 224926947304SEvan Yan return (PCIE_NOT_ARI_DEVICE); 225026947304SEvan Yan 225126947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr)) 225226947304SEvan Yan != DDI_SUCCESS) { 225326947304SEvan Yan pci_config_teardown(&handle); 225426947304SEvan Yan return (PCIE_NOT_ARI_DEVICE); 225526947304SEvan Yan } 225626947304SEvan Yan 225726947304SEvan Yan /* Locate the ARI Capability */ 225826947304SEvan Yan 225926947304SEvan Yan if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), 226026947304SEvan Yan &cap_ptr)) == DDI_FAILURE) { 226126947304SEvan Yan pci_config_teardown(&handle); 226226947304SEvan Yan return (PCIE_NOT_ARI_DEVICE); 226326947304SEvan Yan } 226426947304SEvan Yan 226526947304SEvan Yan /* ARI Capability was found so it must be a ARI device */ 226626947304SEvan Yan PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip); 226726947304SEvan Yan 226826947304SEvan Yan pci_config_teardown(&handle); 226926947304SEvan Yan return (PCIE_ARI_DEVICE); 227026947304SEvan Yan } 227126947304SEvan Yan 227226947304SEvan Yan int 227326947304SEvan Yan pcie_ari_get_next_function(dev_info_t *dip, int *func) 227426947304SEvan Yan { 227526947304SEvan Yan uint32_t val; 227626947304SEvan Yan uint16_t cap_ptr, next_function; 227726947304SEvan Yan ddi_acc_handle_t handle; 227826947304SEvan Yan 227926947304SEvan Yan /* 228026947304SEvan Yan * XXX - This function may be called before the bus_p structure 228126947304SEvan Yan * has been populated. This code can be changed to remove 228226947304SEvan Yan * pci_config_setup()/pci_config_teardown() when the RFE 228326947304SEvan Yan * to populate the bus_p structures early in boot is putback. 228426947304SEvan Yan */ 228526947304SEvan Yan 228626947304SEvan Yan if (pci_config_setup(dip, &handle) != DDI_SUCCESS) 228726947304SEvan Yan return (DDI_FAILURE); 228826947304SEvan Yan 228926947304SEvan Yan if ((PCI_CAP_LOCATE(handle, 229026947304SEvan Yan PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) { 229126947304SEvan Yan pci_config_teardown(&handle); 229226947304SEvan Yan return (DDI_FAILURE); 229326947304SEvan Yan } 229426947304SEvan Yan 229526947304SEvan Yan val = PCI_CAP_GET32(handle, NULL, cap_ptr, PCIE_ARI_CAP); 229626947304SEvan Yan 229726947304SEvan Yan next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) & 229826947304SEvan Yan PCIE_ARI_CAP_NEXT_FUNC_MASK; 229926947304SEvan Yan 230026947304SEvan Yan pci_config_teardown(&handle); 230126947304SEvan Yan 230226947304SEvan Yan *func = next_function; 230326947304SEvan Yan 230426947304SEvan Yan return (DDI_SUCCESS); 230526947304SEvan Yan } 230626947304SEvan Yan 230726947304SEvan Yan dev_info_t * 230826947304SEvan Yan pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function) 230926947304SEvan Yan { 231026947304SEvan Yan pcie_req_id_t child_bdf; 231126947304SEvan Yan dev_info_t *cdip; 231226947304SEvan Yan 231326947304SEvan Yan for (cdip = ddi_get_child(dip); cdip; 231426947304SEvan Yan cdip = ddi_get_next_sibling(cdip)) { 231526947304SEvan Yan 231626947304SEvan Yan if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE) 231726947304SEvan Yan return (NULL); 231826947304SEvan Yan 231926947304SEvan Yan if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function) 232026947304SEvan Yan return (cdip); 232126947304SEvan Yan } 232226947304SEvan Yan return (NULL); 232326947304SEvan Yan } 232426947304SEvan Yan 2325d4bc0535SKrishna Elango #ifdef DEBUG 2326d4bc0535SKrishna Elango 2327d4bc0535SKrishna Elango static void 2328d4bc0535SKrishna Elango pcie_print_bus(pcie_bus_t *bus_p) 2329d4bc0535SKrishna Elango { 2330d4bc0535SKrishna Elango pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip); 2331d4bc0535SKrishna Elango pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags); 2332d4bc0535SKrishna Elango 2333d4bc0535SKrishna Elango pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf); 2334d4bc0535SKrishna Elango pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id); 2335d4bc0535SKrishna Elango pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id); 2336d4bc0535SKrishna Elango pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type); 2337d4bc0535SKrishna Elango pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type); 2338d4bc0535SKrishna Elango pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus); 2339d4bc0535SKrishna Elango pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off); 2340d4bc0535SKrishna Elango pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off); 2341d4bc0535SKrishna Elango pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off); 2342d4bc0535SKrishna Elango pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver); 2343d4bc0535SKrishna Elango } 2344d4bc0535SKrishna Elango 2345d4bc0535SKrishna Elango /* 2346d4bc0535SKrishna Elango * For debugging purposes set pcie_dbg_print != 0 to see printf messages 2347d4bc0535SKrishna Elango * during interrupt. 2348d4bc0535SKrishna Elango * 2349d4bc0535SKrishna Elango * When a proper solution is in place this code will disappear. 2350d4bc0535SKrishna Elango * Potential solutions are: 2351d4bc0535SKrishna Elango * o circular buffers 2352d4bc0535SKrishna Elango * o taskq to print at lower pil 2353d4bc0535SKrishna Elango */ 2354d4bc0535SKrishna Elango int pcie_dbg_print = 0; 2355d4bc0535SKrishna Elango void 2356d4bc0535SKrishna Elango pcie_dbg(char *fmt, ...) 2357d4bc0535SKrishna Elango { 2358d4bc0535SKrishna Elango va_list ap; 2359d4bc0535SKrishna Elango 2360d4bc0535SKrishna Elango if (!pcie_debug_flags) { 2361d4bc0535SKrishna Elango return; 2362d4bc0535SKrishna Elango } 2363d4bc0535SKrishna Elango va_start(ap, fmt); 2364d4bc0535SKrishna Elango if (servicing_interrupt()) { 2365d4bc0535SKrishna Elango if (pcie_dbg_print) { 2366d4bc0535SKrishna Elango prom_vprintf(fmt, ap); 2367d4bc0535SKrishna Elango } 2368d4bc0535SKrishna Elango } else { 2369d4bc0535SKrishna Elango prom_vprintf(fmt, ap); 2370d4bc0535SKrishna Elango } 2371d4bc0535SKrishna Elango va_end(ap); 2372d4bc0535SKrishna Elango } 2373d4bc0535SKrishna Elango #endif /* DEBUG */ 2374d4bc0535SKrishna Elango 2375d4bc0535SKrishna Elango #if defined(__i386) || defined(__amd64) 2376d4bc0535SKrishna Elango static void 2377d4bc0535SKrishna Elango pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl, boolean_t *empty_io_range, 2378d4bc0535SKrishna Elango boolean_t *empty_mem_range) 2379d4bc0535SKrishna Elango { 2380d4bc0535SKrishna Elango uint8_t class, subclass; 2381d4bc0535SKrishna Elango uint_t val; 2382d4bc0535SKrishna Elango 2383d4bc0535SKrishna Elango class = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS); 2384d4bc0535SKrishna Elango subclass = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS); 2385d4bc0535SKrishna Elango 2386d4bc0535SKrishna Elango if ((class == PCI_CLASS_BRIDGE) && (subclass == PCI_BRIDGE_PCI)) { 2387d4bc0535SKrishna Elango val = (((uint_t)pci_config_get8(cfg_hdl, PCI_BCNF_IO_BASE_LOW) & 2388d4bc0535SKrishna Elango PCI_BCNF_IO_MASK) << 8); 2389d4bc0535SKrishna Elango /* 2390d4bc0535SKrishna Elango * Assuming that a zero based io_range[0] implies an 2391d4bc0535SKrishna Elango * invalid I/O range. Likewise for mem_range[0]. 2392d4bc0535SKrishna Elango */ 2393d4bc0535SKrishna Elango if (val == 0) 2394d4bc0535SKrishna Elango *empty_io_range = B_TRUE; 2395d4bc0535SKrishna Elango val = (((uint_t)pci_config_get16(cfg_hdl, PCI_BCNF_MEM_BASE) & 2396d4bc0535SKrishna Elango PCI_BCNF_MEM_MASK) << 16); 2397d4bc0535SKrishna Elango if (val == 0) 2398d4bc0535SKrishna Elango *empty_mem_range = B_TRUE; 2399d4bc0535SKrishna Elango } 2400d4bc0535SKrishna Elango } 2401c0da6274SZhi-Jun Robin Fu 2402d4bc0535SKrishna Elango #endif /* defined(__i386) || defined(__amd64) */ 2403