Merge tag 'pci-v4.4-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci

Pull PCI updates from Bjorn Helgaas:
 "Resource management:
   - Add support for Enhanced Allocation devices (Sean O. Stalley)
   - Add Enhanced Allocation register entries (Sean O. Stalley)
   - Handle IORESOURCE_PCI_FIXED when sizing resources (David Daney)
   - Handle IORESOURCE_PCI_FIXED when assigning resources (David Daney)
   - Handle Enhanced Allocation capability for SR-IOV devices (David Daney)
   - Clear IORESOURCE_UNSET when reverting to firmware-assigned address (Bjorn Helgaas)
   - Make Enhanced Allocation bitmasks more obvious (Bjorn Helgaas)
   - Expand Enhanced Allocation BAR output (Bjorn Helgaas)
   - Add of_pci_check_probe_only to parse "linux,pci-probe-only" (Marc Zyngier)
   - Fix lookup of linux,pci-probe-only property (Marc Zyngier)
   - Add sparc mem64 resource parsing for root bus (Yinghai Lu)

  PCI device hotplug:
   - pciehp: Queue power work requests in dedicated function (Guenter Roeck)

  Driver binding:
   - Add builtin_pci_driver() to avoid registration boilerplate (Paul Gortmaker)

  Virtualization:
   - Set SR-IOV NumVFs to zero after enumeration (Alexander Duyck)
   - Remove redundant validation of SR-IOV offset/stride registers (Alexander Duyck)
   - Remove VFs in reverse order if virtfn_add() fails (Alexander Duyck)
   - Reorder pcibios_sriov_disable() (Alexander Duyck)
   - Wait 1 second between disabling VFs and clearing NumVFs (Alexander Duyck)
   - Fix sriov_enable() error path for pcibios_enable_sriov() failures (Alexander Duyck)
   - Enable SR-IOV ARI Capable Hierarchy before reading TotalVFs (Ben Shelton)
   - Don't try to restore VF BARs (Wei Yang)

  MSI:
   - Don't alloc pcibios-irq when MSI is enabled (Joerg Roedel)
   - Add msi_controller setup_irqs() method for special multivector setup (Lucas Stach)
   - Export all remapped MSIs to sysfs attributes (Romain Bezut)
   - Disable MSI on SiS 761 (Ondrej Zary)

  AER:
   - Clear error status registers during enumeration and restore (Taku Izumi)

  Generic host bridge driver:
   - Fix lookup of linux,pci-probe-only property (Marc Zyngier)
   - Allow multiple hosts with different map_bus() methods (David Daney)
   - Pass starting bus number to pci_scan_root_bus() (David Daney)
   - Fix address window calculation for non-zero starting bus (David Daney)

  Altera host bridge driver:
   - Add msi.h to ARM Kbuild (Ley Foon Tan)
   - Add Altera PCIe host controller driver (Ley Foon Tan)
   - Add Altera PCIe MSI driver (Ley Foon Tan)

  APM X-Gene host bridge driver:
   - Remove msi_controller assignment (Duc Dang)

  Broadcom iProc host bridge driver:
   - Fix header comment "Corporation" misspelling (Florian Fainelli)
   - Fix code comment to match code (Ray Jui)
   - Remove unused struct iproc_pcie.irqs[] (Ray Jui)
   - Call pci_fixup_irqs() for ARM64 as well as ARM (Ray Jui)
   - Fix PCIe reset logic (Ray Jui)
   - Improve link detection logic (Ray Jui)
   - Update PCIe device tree bindings (Ray Jui)
   - Add outbound mapping support (Ray Jui)

  Freescale i.MX6 host bridge driver:
   - Return real error code from imx6_add_pcie_port() (Fabio Estevam)
   - Add PCIE_PHY_RX_ASIC_OUT_VALID definition (Fabio Estevam)

  Freescale Layerscape host bridge driver:
   - Remove ls_pcie_establish_link() (Minghuan Lian)
   - Ignore PCIe controllers in Endpoint mode (Minghuan Lian)
   - Factor out SCFG related function (Minghuan Lian)
   - Update ls_add_pcie_port() (Minghuan Lian)
   - Remove unused fields from struct ls_pcie (Minghuan Lian)
   - Add support for LS1043a and LS2080a (Minghuan Lian)
   - Add ls_pcie_msi_host_init() (Minghuan Lian)

  HiSilicon host bridge driver:
   - Add HiSilicon SoC Hip05 PCIe driver (Zhou Wang)

  Marvell MVEBU host bridge driver:
   - Return zero for reserved or unimplemented config space (Russell King)
   - Use exact config access size; don't read/modify/write (Russell King)
   - Use of_get_available_child_count() (Russell King)
   - Use for_each_available_child_of_node() to walk child nodes (Russell King)
   - Report full node name when reporting a DT error (Russell King)
   - Use port->name rather than "PCIe%d.%d" (Russell King)
   - Move port parsing and resource claiming to  separate function (Russell King)
   - Fix memory leaks and refcount leaks (Russell King)
   - Split port parsing and resource claiming from  port setup (Russell King)
   - Use gpio_set_value_cansleep() (Russell King)
   - Use devm_kcalloc() to allocate an array (Russell King)
   - Use gpio_desc to carry around gpio (Russell King)
   - Improve clock/reset handling (Russell King)
   - Add PCI Express root complex capability block (Russell King)
   - Remove code restricting accesses to slot 0 (Russell King)

  NVIDIA Tegra host bridge driver:
   - Wrap static pgprot_t initializer with __pgprot() (Ard Biesheuvel)

  Renesas R-Car host bridge driver:
   - Build pci-rcar-gen2.c only on ARM (Geert Uytterhoeven)
   - Build pcie-rcar.c only on ARM (Geert Uytterhoeven)
   - Make PCI aware of the I/O resources (Phil Edworthy)
   - Remove dependency on ARM-specific struct hw_pci (Phil Edworthy)
   - Set root bus nr to that provided in DT (Phil Edworthy)
   - Fix I/O offset for multiple host bridges (Phil Edworthy)

  ST Microelectronics SPEAr13xx host bridge driver:
   - Fix dw_pcie_cfg_read/write() usage (Gabriele Paoloni)

  Synopsys DesignWare host bridge driver:
   - Make "clocks" and "clock-names" optional DT properties (Bhupesh Sharma)
   - Use exact access size in dw_pcie_cfg_read() (Gabriele Paoloni)
   - Simplify dw_pcie_cfg_read/write() interfaces (Gabriele Paoloni)
   - Require config accesses to be naturally aligned (Gabriele Paoloni)
   - Make "num-lanes" an optional DT property (Gabriele Paoloni)
   - Move calculation of bus addresses to DRA7xx (Gabriele Paoloni)
   - Replace ARM pci_sys_data->align_resource with global function pointer (Gabriele Paoloni)
   - Factor out MSI msg setup (Lucas Stach)
   - Implement multivector MSI IRQ setup (Lucas Stach)
   - Make get_msi_addr() return phys_addr_t, not u32 (Lucas Stach)
   - Set up high part of MSI target address (Lucas Stach)
   - Fix PORT_LOGIC_LINK_WIDTH_MASK (Zhou Wang)
   - Revert "PCI: designware: Program ATU with untranslated address" (Zhou Wang)
   - Use of_pci_get_host_bridge_resources() to parse DT (Zhou Wang)
   - Make driver arch-agnostic (Zhou Wang)

  Miscellaneous:
   - Make x86 pci_subsys_init() static (Alexander Kuleshov)
   - Turn off Request Attributes to avoid Chelsio T5 Completion erratum (Hariprasad Shenai)"

* tag 'pci-v4.4-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (94 commits)
  PCI: altera: Add Altera PCIe MSI driver
  PCI: hisi: Add HiSilicon SoC Hip05 PCIe driver
  PCI: layerscape: Add ls_pcie_msi_host_init()
  PCI: layerscape: Add support for LS1043a and LS2080a
  PCI: layerscape: Remove unused fields from struct ls_pcie
  PCI: layerscape: Update ls_add_pcie_port()
  PCI: layerscape: Factor out SCFG related function
  PCI: layerscape: Ignore PCIe controllers in Endpoint mode
  PCI: layerscape: Remove ls_pcie_establish_link()
  PCI: designware: Make "clocks" and "clock-names" optional DT properties
  PCI: designware: Make driver arch-agnostic
  ARM/PCI: Replace pci_sys_data->align_resource with global function pointer
  PCI: designware: Use of_pci_get_host_bridge_resources() to parse DT
  Revert "PCI: designware: Program ATU with untranslated address"
  PCI: designware: Move calculation of bus addresses to DRA7xx
  PCI: designware: Make "num-lanes" an optional DT property
  PCI: designware: Require config accesses to be naturally aligned
  PCI: designware: Simplify dw_pcie_cfg_read/write() interfaces
  PCI: designware: Use exact access size in dw_pcie_cfg_read()
  PCI: spear: Fix dw_pcie_cfg_read/write() usage
  ...
This commit is contained in:
Linus Torvalds
2015-11-06 11:29:53 -08:00
58 changed files with 2904 additions and 685 deletions

View File

@@ -27,6 +27,7 @@
#include <linux/pci_hotplug.h>
#include <asm-generic/pci-bridge.h>
#include <asm/setup.h>
#include <linux/aer.h>
#include "pci.h"
const char *pci_power_names[] = {
@@ -457,6 +458,30 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev,
}
EXPORT_SYMBOL(pci_find_parent_resource);
/**
* pci_find_pcie_root_port - return PCIe Root Port
* @dev: PCI device to query
*
* Traverse up the parent chain and return the PCIe Root Port PCI Device
* for a given PCI Device.
*/
struct pci_dev *pci_find_pcie_root_port(struct pci_dev *dev)
{
struct pci_dev *bridge, *highest_pcie_bridge = NULL;
bridge = pci_upstream_bridge(dev);
while (bridge && pci_is_pcie(bridge)) {
highest_pcie_bridge = bridge;
bridge = pci_upstream_bridge(bridge);
}
if (pci_pcie_type(highest_pcie_bridge) != PCI_EXP_TYPE_ROOT_PORT)
return NULL;
return highest_pcie_bridge;
}
EXPORT_SYMBOL(pci_find_pcie_root_port);
/**
* pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos
* @dev: the PCI device to operate on
@@ -484,7 +509,7 @@ int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask)
}
/**
* pci_restore_bars - restore a devices BAR values (e.g. after wake-up)
* pci_restore_bars - restore a device's BAR values (e.g. after wake-up)
* @dev: PCI device to have its BARs restored
*
* Restore the BAR values for a given device, so as to make it
@@ -494,6 +519,10 @@ static void pci_restore_bars(struct pci_dev *dev)
{
int i;
/* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */
if (dev->is_virtfn)
return;
for (i = 0; i < PCI_BRIDGE_RESOURCES; i++)
pci_update_resource(dev, i);
}
@@ -1099,6 +1128,8 @@ void pci_restore_state(struct pci_dev *dev)
pci_restore_ats_state(dev);
pci_restore_vc_state(dev);
pci_cleanup_aer_error_status_regs(dev);
pci_restore_config_space(dev);
pci_restore_pcix_state(dev);
@@ -2196,6 +2227,198 @@ void pci_pm_init(struct pci_dev *dev)
}
}
static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop)
{
unsigned long flags = IORESOURCE_PCI_FIXED;
switch (prop) {
case PCI_EA_P_MEM:
case PCI_EA_P_VF_MEM:
flags |= IORESOURCE_MEM;
break;
case PCI_EA_P_MEM_PREFETCH:
case PCI_EA_P_VF_MEM_PREFETCH:
flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
break;
case PCI_EA_P_IO:
flags |= IORESOURCE_IO;
break;
default:
return 0;
}
return flags;
}
static struct resource *pci_ea_get_resource(struct pci_dev *dev, u8 bei,
u8 prop)
{
if (bei <= PCI_EA_BEI_BAR5 && prop <= PCI_EA_P_IO)
return &dev->resource[bei];
#ifdef CONFIG_PCI_IOV
else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5 &&
(prop == PCI_EA_P_VF_MEM || prop == PCI_EA_P_VF_MEM_PREFETCH))
return &dev->resource[PCI_IOV_RESOURCES +
bei - PCI_EA_BEI_VF_BAR0];
#endif
else if (bei == PCI_EA_BEI_ROM)
return &dev->resource[PCI_ROM_RESOURCE];
else
return NULL;
}
/* Read an Enhanced Allocation (EA) entry */
static int pci_ea_read(struct pci_dev *dev, int offset)
{
struct resource *res;
int ent_size, ent_offset = offset;
resource_size_t start, end;
unsigned long flags;
u32 dw0, bei, base, max_offset;
u8 prop;
bool support_64 = (sizeof(resource_size_t) >= 8);
pci_read_config_dword(dev, ent_offset, &dw0);
ent_offset += 4;
/* Entry size field indicates DWORDs after 1st */
ent_size = ((dw0 & PCI_EA_ES) + 1) << 2;
if (!(dw0 & PCI_EA_ENABLE)) /* Entry not enabled */
goto out;
bei = (dw0 & PCI_EA_BEI) >> 4;
prop = (dw0 & PCI_EA_PP) >> 8;
/*
* If the Property is in the reserved range, try the Secondary
* Property instead.
*/
if (prop > PCI_EA_P_BRIDGE_IO && prop < PCI_EA_P_MEM_RESERVED)
prop = (dw0 & PCI_EA_SP) >> 16;
if (prop > PCI_EA_P_BRIDGE_IO)
goto out;
res = pci_ea_get_resource(dev, bei, prop);
if (!res) {
dev_err(&dev->dev, "Unsupported EA entry BEI: %u\n", bei);
goto out;
}
flags = pci_ea_flags(dev, prop);
if (!flags) {
dev_err(&dev->dev, "Unsupported EA properties: %#x\n", prop);
goto out;
}
/* Read Base */
pci_read_config_dword(dev, ent_offset, &base);
start = (base & PCI_EA_FIELD_MASK);
ent_offset += 4;
/* Read MaxOffset */
pci_read_config_dword(dev, ent_offset, &max_offset);
ent_offset += 4;
/* Read Base MSBs (if 64-bit entry) */
if (base & PCI_EA_IS_64) {
u32 base_upper;
pci_read_config_dword(dev, ent_offset, &base_upper);
ent_offset += 4;
flags |= IORESOURCE_MEM_64;
/* entry starts above 32-bit boundary, can't use */
if (!support_64 && base_upper)
goto out;
if (support_64)
start |= ((u64)base_upper << 32);
}
end = start + (max_offset | 0x03);
/* Read MaxOffset MSBs (if 64-bit entry) */
if (max_offset & PCI_EA_IS_64) {
u32 max_offset_upper;
pci_read_config_dword(dev, ent_offset, &max_offset_upper);
ent_offset += 4;
flags |= IORESOURCE_MEM_64;
/* entry too big, can't use */
if (!support_64 && max_offset_upper)
goto out;
if (support_64)
end += ((u64)max_offset_upper << 32);
}
if (end < start) {
dev_err(&dev->dev, "EA Entry crosses address boundary\n");
goto out;
}
if (ent_size != ent_offset - offset) {
dev_err(&dev->dev,
"EA Entry Size (%d) does not match length read (%d)\n",
ent_size, ent_offset - offset);
goto out;
}
res->name = pci_name(dev);
res->start = start;
res->end = end;
res->flags = flags;
if (bei <= PCI_EA_BEI_BAR5)
dev_printk(KERN_DEBUG, &dev->dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
bei, res, prop);
else if (bei == PCI_EA_BEI_ROM)
dev_printk(KERN_DEBUG, &dev->dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n",
res, prop);
else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5)
dev_printk(KERN_DEBUG, &dev->dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
bei - PCI_EA_BEI_VF_BAR0, res, prop);
else
dev_printk(KERN_DEBUG, &dev->dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n",
bei, res, prop);
out:
return offset + ent_size;
}
/* Enhanced Allocation Initalization */
void pci_ea_init(struct pci_dev *dev)
{
int ea;
u8 num_ent;
int offset;
int i;
/* find PCI EA capability in list */
ea = pci_find_capability(dev, PCI_CAP_ID_EA);
if (!ea)
return;
/* determine the number of entries */
pci_bus_read_config_byte(dev->bus, dev->devfn, ea + PCI_EA_NUM_ENT,
&num_ent);
num_ent &= PCI_EA_NUM_ENT_MASK;
offset = ea + PCI_EA_FIRST_ENT;
/* Skip DWORD 2 for type 1 functions */
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
offset += 4;
/* parse each EA entry */
for (i = 0; i < num_ent; ++i)
offset = pci_ea_read(dev, offset);
}
static void pci_add_saved_cap(struct pci_dev *pci_dev,
struct pci_cap_saved_state *new_cap)
{