pcie.c revision c92295a9ebe31a65582ec97d4d772e0efd2ff240
1N/A * The contents of this file are subject to the terms of the 1N/A * Common Development and Distribution License (the "License"). 1N/A * You may not use this file except in compliance with the License. 1N/A * See the License for the specific language governing permissions 1N/A * and limitations under the License. 1N/A * When distributing Covered Code, include this CDDL HEADER in each 1N/A * If applicable, add the following below this CDDL HEADER, with the 1N/A * fields enclosed by brackets "[]" replaced with your own identifying 1N/A * information: Portions Copyright [yyyy] [name of copyright owner] 1N/A * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 1N/A/* Local functions prototypes */ 1N/A#
endif /* defined(__i386) || defined(__amd64) */ 1N/A/* Variable to control default PCI-Express config settings */ /* xxx_fw are bits that are controlled by FW and should not be modified */ 0xF800;
/* Reserved Bits */ 0xF000;
/* Reserved Bits */ /* PCI-Express Base error defaults */ /* PCI-Express Device Control Register */ /* PCI-Express AER Root Control Register */ /* PCI-Express Root Error Command Register */ /* ECRC settings in the PCIe AER Control Register */ * If a particular platform wants to disable certain errors such as UR/MA, * instead of using #defines have the platform's PCIe Root Complex driver set * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions. For * x86 the closest thing to a PCIe root complex driver is NPE. For SPARC the * closest PCIe root complex driver is PX. * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86 * systems may want to disable SERR in general. For root ports, enabling SERR * causes NMIs which are not handled and results in a watchdog timeout error. /* Default severities needed for eversholt. Error handling doesn't care */ "PCI Express Framework Module" * Global Variables needed for a non-atomic version of ddi_fm_ereport_post. * Currently used to send the pci.fabric ereports whose payload depends on the * type of PCI device it is being sent for. * Create a "devctl" minor node to support DEVCTL_DEVICE_* * and DEVCTL_BUS_* ioctls to this bus. PCIE_DBG(
"Failed to create devctl minor node for %s%d\n",
* On some x86 platforms, we observed unexpected hotplug * initialization failures in recent years. The known cause * is a hardware issue: while the problem PCI bridges have * the Hotplug Capable registers set, the machine actually * does not implement the expected ACPI object. * We don't want to stop PCI driver attach and system boot * just because of this hotplug initialization failure. * Continue with a debug message printed. PCIE_DBG(
"%s%d: Failed setting hotplug framework\n",
#
endif /* defined(__sparc) */ PCIE_DBG(
"Failed to uninitialize hotplug for %s%d\n",
* PCIe module interface for enabling hotplug interrupt. * It should be called after pcie_init() is done and bus driver's * interrupt handlers have being attached. * PCIe module interface for disabling hotplug interrupt. * It should be called before pcie_uninit() is called and bus driver's * interrupt handlers is dettached. * Make sure the open is for the right file type. * Handle the open by tracking the device state. * We can use the generic implementation for devctl ioctl /* Create an config access special to error handling */ * PCI-Express child device initialization. * This function enables generic pci-express interrupts and error * @param pdip root dip (root nexus's dip) * @param cdip child's dip (device's dip) * @return DDI_SUCCESS or DDI_FAILURE * Update pcie_bus_t with real Vendor Id Device Id. * For assigned devices in IOV environment, the OBP will return * faked device id/vendor id on configration read and for both * properties in root domain. translate_devid() function will * platforms, so that we can utilize the properties here to get * For unassigned devices or devices in non-IOV environment, the * operation below won't make a difference. * The IOV implementation only supports assignment of PCIE * endpoint devices. Devices under pci-pci bridges don't need /* Clear the device's status register */ /* Setup the device's command register */ * Check for empty IO and Mem ranges on bridges. If so disable IO/Mem * access as it can cause a hang if enabled. PCIE_DBG(
"No I/O range found for %s, bdf 0x%x\n",
PCIE_DBG(
"No Mem range found for %s, bdf 0x%x\n",
#
endif /* defined(__i386) || defined(__amd64) */ * If the device has a bus control register then program it * based on the settings in the command register. /* Clear the device's secondary status register */ /* Setup the device's secondary command register */ * Workaround for this Nvidia bridge. Don't enable the SERR * enable bit in the bridge control register as it could lead to * Enable Master Abort Mode only if URs have not been masked. * For PCI and PCIe-PCI bridges, enabling this bit causes a * Master Aborts/UR to be forwarded as a UR/TA or SERR. If this * bit is masked, posted requests are dropped and non-posted * requests are returned with -1. /* Setup PCIe device control register */ /* note: MPS/MRRS are initialized in pcie_initchild_mps() */ /* Allocate the root fault struct for both RC and RP */ * Special functions to allocate pf_data_t's for PCIe root complexes. * Note: Root Complex not Root Port * init pcie_bus_t for root complex * Only a few of the fields in bus_t is valid for root complex. * The fields that are bracketed are initialized in this routine: * dev_info_t * bus_rp_dip * ddi_acc_handle_t bus_cfg_hdl * pcie_req_id_t bus_rp_bdf * uint32_t bus_dev_ven_id * uint16_t <bus_dev_type> * pci_bus_range_t bus_bus_range * ppb_ranges_t * bus_addr_ranges * pci_regspec_t * bus_assigned_addr * int bus_assigned_entries * pcie_domain_t * <bus_dom> * uint64_t bus_cfgacc_base * void * bus_plat_private /* Fake that there are AER logs */ /* Needed only for handle lookup */ * partially init pcie_bus_t for device (dip,bdf) for accessing pci * This routine is invoked during boot, either after creating a devinfo node * (x86 case) or during px driver attach (sparc case); it is also invoked * in hotplug context after a devinfo node is created. * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL * dev_info_t * <bus_rp_dip> * ddi_acc_handle_t bus_cfg_hdl * pcie_req_id_t <bus_bdf> * pcie_req_id_t <bus_rp_bdf> * uint32_t <bus_dev_ven_id> * uint16_t <bus_dev_type> * uint8_t <bus_bdg_secbus * uint16_t <bus_pcie_off> * uint16_t <bus_pcix_off> * pci_bus_range_t bus_bus_range * ppb_ranges_t * bus_addr_ranges * pci_regspec_t * bus_assigned_addr * int bus_assigned_entries * pcie_domain_t * bus_dom * uint64_t bus_cfgacc_base * void * bus_plat_private * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL * dev_info_t * bus_rp_dip * ddi_acc_handle_t bus_cfg_hdl * pcie_req_id_t bus_rp_bdf * uint32_t bus_dev_ven_id * uint8_t <bus_bdg_secbus> * pci_bus_range_t <bus_bus_range> * ppb_ranges_t * <bus_addr_ranges> * pci_regspec_t * <bus_assigned_addr> * int <bus_assigned_entries> * pcie_domain_t * bus_dom * uint64_t bus_cfgacc_base * void * <bus_plat_private> /* Save the Vendor ID, Device ID and revision ID */ /* Save the Header Type */ * Figure out the device type and all the relavant capability offsets goto caps_done;
/* capability not supported */ /* Relevant conventional capabilities first */ /* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */ /* Check and save PCIe hotplug capability information */ /* Check and save PCI hotplug (SHPC) capability information */ /* Then, relevant extended capabilities */ /* Extended caps: PCIE_EXT_CAP_ID_AER */ /* save RP dip and RP bdf */ * If RP dip and RP bdf in parent's bus_t have * been initialized, simply use these instead of * continuing up to the RC. * When debugging be aware that some NVIDIA x86 * architectures have 2 nodes for each RP, One at Bus * 0x0 and one at Bus 0x80. The requester is from Bus /* already initialized? */ /* Save the Range information if device is a switch/bridge */ /* get "bus_range" property */ errstr =
"Cannot find \"bus-range\" property";
"PCIE init err info failed BDF 0x%x:%s\n",
/* get secondary bus number */ /* Get "ranges" property */ /* save "assigned-addresses" property array, ignore failues */ PCIE_DBG(
"Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
* Invoked before destroying devinfo node, mostly during hotplug * operation to free pcie_bus_t data structure /* zero out the fields that have been destroyed */ * PCI-Express child device de-initialization. * This function disables generic pci-express interrupts and error * find the root complex dip * Clear any pending errors * Enable Baseline Error Handling but leave CE reporting off (poweron /* Enable Root Port Baseline Error Receiving */ * Enable PCI-Express Advanced Error Handling if Exists /* Set Uncorrectable Severity */ /* Enable Uncorrectable errors */ /* Enable ECRC generation and checking */ /* Enable Secondary Uncorrectable errors if this is a bridge */ /* Set Uncorrectable Severity */ * Enable Root Control this is a Root device * This function is used for enabling CE reporting and setting the AER CE mask. * When called from outside the pcie module it should always be preceded by * a call to pcie_enable_errors. * The "pcie_ce_mask" property is used to control both the CE reporting * enable field in the device control register and the AER CE mask. We * leave CE reporting disabled if pcie_ce_mask is set to -1. * Nothing to do since CE reporting has already been disabled. /* Clear any pending AER CE errors */ /* clear any pending CE errors */ /* Enable CE reporting */ * Disable PCI-Express Baseline Error Handling * Disable PCI-Express Advanced Error Handling if Exists /* Disable Uncorrectable errors */ /* Disable Correctable errors */ /* Disable ECRC generation and checking */ * Disable Secondary Uncorrectable errors if this is a bridge * disable Root Control this is a Root device * Extract bdf from "reg" property. /* Get phys_hi from first element. All have same bdf. */ * As part of the probing, the PCI fcode interpreter may setup a DMA * request if a given card has a fcode on it using dip and rdip of the * hotplug connector i.e, dip and rdip of px/pcieb driver. In this * case, return a invalid value for the bdf since we cannot get to the * bdf value of the actual device which will be initiating this DMA. * For a given rdip, return the bdf value of dip's (px or pcieb) * immediate child or secondary bus-id if dip is a PCIe2PCI bridge. * XXX - For now, return a invalid bdf value for all PCI and PCI-X * devices since this needs more work. * Is the rdip a child of dip. Used for checking certain CTLOPS from bubbling * up erronously. Ex. ISA ctlops to a PCI-PCI Bridge. * Initialize the MPS for a root port. * dip - dip of root port device. * Initialize the Maximum Payload Size of a device. * returns - DDI_SUCCESS or DDI_FAILURE * For ARI Devices, only function zero's MPS needs to be set. * Replace MPS and MRRS settings. * Scans a device tree/branch for a maximum payload size capabilities. * rc_dip - dip of Root Complex. * dip - dip of device where scan will begin. * max_supported (IN) - maximum allowable MPS. * max_supported (OUT) - maximum payload size capability of fabric. * Perform a fabric scan to obtain Maximum Payload Capabilities * Scans fabric and determines Maximum Payload Size based on * highest common denominator alogorithm * Called as part of the Maximum Payload Size scan. PCIE_DBG(
"MPS: pcie_get_max_supported: %s: " * If the suggested-mrrs property exists, then don't include this * device in the MPS capabilities scan. PCIE_DBG(
"MPS: pcie_get_max_supported: %s: " PCIE_DBG(
"MPS: pcie_get_max_supported: %s: pcie_map_phys " * Determines if there are any root ports attached to a root complex. * dip - dip of root complex * Returns - DDI_SUCCESS if there is at least one root port otherwise * Determine if any of the children of the passed in dip /* No root ports were found */ * Function that determines if a device a PCIe device. * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE. /* get parent device's device_type property */ * Function to map in a device's memory space. * Map out memory that was mapped in with pcie_map_phys(); * Return parent Root Port's pe_rber_fatal value. PCIE_DBG(
"pcie_ari_supported: dip=%p: ARI Disabled\n",
dip);
PCIE_DBG(
"pcie_ari_supported: dip=%p: Not 2.0\n",
dip);
PCIE_DBG(
"pcie_ari_supported: dip=%p: DevCap2=0x%x\n",
"dip=%p: ARI Forwarding is supported\n",
dip);
PCIE_DBG(
"pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n",
PCIE_DBG(
"pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n",
PCIE_DBG(
"pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n",
"dip=%p: ARI Forwarding is enabled\n",
dip);
* XXX - This function may be called before the bus_p structure * has been populated. This code can be changed to remove * pci_config_setup()/pci_config_teardown() when the RFE * to populate the bus_p structures early in boot is putback. /* First make sure it is a PCIe device */ /* Locate the ARI Capability */ /* ARI Capability was found so it must be a ARI device */ * XXX - This function may be called before the bus_p structure * has been populated. This code can be changed to remove * pci_config_setup()/pci_config_teardown() when the RFE * to populate the bus_p structures early in boot is putback. * For debugging purposes set pcie_dbg_print != 0 to see printf messages * When a proper solution is in place this code will disappear. * Potential solutions are: * o taskq to print at lower pil * Assuming that a zero based io_range[0] implies an * invalid I/O range. Likewise for mem_range[0]. #
endif /* defined(__i386) || defined(__amd64) */