Merge tag 'pci-v4.1-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Apr 2015 22:45:47 +0000 (15:45 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Apr 2015 22:45:47 +0000 (15:45 -0700)
Pull PCI changes from Bjorn Helgaas:
 "Enumeration
    - Read capability list as dwords, not bytes (Sean O. Stalley)

  Resource management
    - Don't check for PNP overlaps with unassigned PCI BARs (Bjorn Helgaas)
    - Mark invalid BARs as unassigned (Bjorn Helgaas)
    - Show driver, BAR#, and resource on pci_ioremap_bar() failure (Bjorn Helgaas)
    - Fail pci_ioremap_bar() on unassigned resources (Bjorn Helgaas)
    - Assign resources before drivers claim devices (Yijing Wang)
    - Claim bus resources before pci_bus_add_devices() (Yijing Wang)

  Power management
    - Optimize device state transition delays (Aaron Lu)
    - Don't clear ASPM bits when the FADT declares it's unsupported (Matthew Garrett)

  Virtualization
    - Add ACS quirks for Intel 1G NICs (Alex Williamson)

  IOMMU
    - Add ptr to OF node arg to of_iommu_configure() (Murali Karicheri)
    - Move of_dma_configure() to device.c to help re-use (Murali Karicheri)
    - Fix size when dma-range is not used (Murali Karicheri)
    - Add helper functions pci_get[put]_host_bridge_device() (Murali Karicheri)
    - Add of_pci_dma_configure() to update DMA configuration (Murali Karicheri)
    - Update DMA configuration from DT (Murali Karicheri)
    - dma-mapping: limit IOMMU mapping size (Murali Karicheri)
    - Calculate device DMA masks based on DT dma-range size (Murali Karicheri)

  ARM Versatile host bridge driver
    - Check for devm_ioremap_resource() failures (Jisheng Zhang)

  Broadcom iProc host bridge driver
    - Add Broadcom iProc PCIe driver (Ray Jui)

  Marvell MVEBU host bridge driver
    - Add suspend/resume support (Thomas Petazzoni)

  Renesas R-Car host bridge driver
    - Fix position of MSI enable bit (Nobuhiro Iwamatsu)
    - Write zeroes to reserved PCIEPARL bits (Nobuhiro Iwamatsu)
    - Change PCIEPARL and PCIEPARH to PCIEPALR and PCIEPAUR (Nobuhiro Iwamatsu)
    - Verify that mem_res is 64K-aligned (Nobuhiro Iwamatsu)

  Samsung Exynos host bridge driver
    - Fix INTx enablement statement termination error (Jaehoon Chung)

  Miscellaneous
    - Make a shareable UUID for PCI firmware ACPI _DSM (Aaron Lu)
    - Clarify policy for vendor IDs in pci.txt (Michael S. Tsirkin)"

* tag 'pci-v4.1-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (36 commits)
  PCI: Read capability list as dwords, not bytes
  PCI: layerscape: Simplify platform_get_resource_byname() failure checking
  PCI: keystone: Don't dereference possible NULL pointer
  PCI: versatile: Check for devm_ioremap_resource() failures
  PCI: Don't clear ASPM bits when the FADT declares it's unsupported
  PCI: Clarify policy for vendor IDs in pci.txt
  PCI/ACPI: Optimize device state transition delays
  PCI: Export pci_find_host_bridge() for use inside PCI core
  PCI: Make a shareable UUID for PCI firmware ACPI _DSM
  PCI: Fix typo in Thunderbolt kernel message
  PCI: exynos: Fix INTx enablement statement termination error
  PCI: iproc: Add Broadcom iProc PCIe support
  PCI: iproc: Add DT docs for Broadcom iProc PCIe driver
  PCI: Export symbols required for loadable host driver modules
  PCI: Add ACS quirks for Intel 1G NICs
  PCI: mvebu: Add suspend/resume support
  PCI: Cleanup control flow
  sparc/PCI: Claim bus resources before pci_bus_add_devices()
  PCI: Assign resources before drivers claim devices (pci_scan_root_bus())
  PCI: Fail pci_ioremap_bar() on unassigned resources
  ...

1  2 
arch/arm/mm/dma-mapping.c
arch/sparc/kernel/pci.c
arch/x86/pci/common.c
drivers/pci/pci-acpi.c

@@@ -171,7 -171,7 +171,7 @@@ static int __dma_supported(struct devic
         */
        if (sizeof(mask) != sizeof(dma_addr_t) &&
            mask > (dma_addr_t)~0 &&
 -          dma_to_pfn(dev, ~0) < max_pfn) {
 +          dma_to_pfn(dev, ~0) < max_pfn - 1) {
                if (warn) {
                        dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n",
                                 mask);
@@@ -2027,6 -2027,13 +2027,13 @@@ static bool arm_setup_iommu_dma_ops(str
        if (!iommu)
                return false;
  
+       /*
+        * currently arm_iommu_create_mapping() takes a max of size_t
+        * for size param. So check this limit for now.
+        */
+       if (size > SIZE_MAX)
+               return false;
        mapping = arm_iommu_create_mapping(dev->bus, dma_base, size);
        if (IS_ERR(mapping)) {
                pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",
diff --combined arch/sparc/kernel/pci.c
@@@ -639,7 -639,10 +639,7 @@@ static void pci_claim_bus_resources(str
                                       (unsigned long long)r->end,
                                       (unsigned int)r->flags);
  
 -                      if (pci_claim_resource(dev, i) == 0)
 -                              continue;
 -
 -                      pci_claim_bridge_resource(dev, i);
 +                      pci_claim_resource(dev, i);
                }
        }
  
@@@ -674,11 -677,10 +674,10 @@@ struct pci_bus *pci_scan_one_pbm(struc
        }
  
        pci_of_scan_bus(pbm, node, bus);
-       pci_bus_add_devices(bus);
        pci_bus_register_of_sysfs(bus);
  
        pci_claim_bus_resources(bus);
+       pci_bus_add_devices(bus);
        return bus;
  }
  
diff --combined arch/x86/pci/common.c
@@@ -490,7 -490,9 +490,9 @@@ void pcibios_scan_root(int busnum
        if (!bus) {
                pci_free_resource_list(&resources);
                kfree(sd);
+               return;
        }
+       pci_bus_add_devices(bus);
  }
  
  void __init pcibios_set_cache_line_size(void)
        }
  }
  
 -/*
 - * Some device drivers assume dev->irq won't change after calling
 - * pci_disable_device(). So delay releasing of IRQ resource to driver
 - * unbinding time. Otherwise it will break PM subsystem and drivers
 - * like xen-pciback etc.
 - */
 -static int pci_irq_notifier(struct notifier_block *nb, unsigned long action,
 -                          void *data)
 -{
 -      struct pci_dev *dev = to_pci_dev(data);
 -
 -      if (action != BUS_NOTIFY_UNBOUND_DRIVER)
 -              return NOTIFY_DONE;
 -
 -      if (pcibios_disable_irq)
 -              pcibios_disable_irq(dev);
 -
 -      return NOTIFY_OK;
 -}
 -
 -static struct notifier_block pci_irq_nb = {
 -      .notifier_call = pci_irq_notifier,
 -      .priority = INT_MIN,
 -};
 -
  int __init pcibios_init(void)
  {
        if (!raw_pci_ops) {
  
        if (pci_bf_sort >= pci_force_bf)
                pci_sort_breadthfirst();
 -
 -      bus_register_notifier(&pci_bus_type, &pci_irq_nb);
 -
        return 0;
  }
  
@@@ -683,12 -713,6 +685,12 @@@ int pcibios_enable_device(struct pci_de
        return 0;
  }
  
 +void pcibios_disable_device (struct pci_dev *dev)
 +{
 +      if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
 +              pcibios_disable_irq(dev);
 +}
 +
  int pci_ext_cfg_avail(void)
  {
        if (raw_pci_ext_ops)
diff --combined drivers/pci/pci-acpi.c
  #include <linux/pm_qos.h>
  #include "pci.h"
  
+ /*
+  * The UUID is defined in the PCI Firmware Specification available here:
+  * https://www.pcisig.com/members/downloads/pcifw_r3_1_13Dec10.pdf
+  */
+ const u8 pci_acpi_dsm_uuid[] = {
+       0xd0, 0x37, 0xc9, 0xe5, 0x53, 0x35, 0x7a, 0x4d,
+       0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d
+ };
  phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
  {
        acpi_status status = AE_NOT_EXIST;
@@@ -248,9 -257,6 +257,9 @@@ int pci_get_hp_params(struct pci_dev *d
        acpi_handle handle, phandle;
        struct pci_bus *pbus;
  
 +      if (acpi_pci_disabled)
 +              return -ENODEV;
 +
        handle = NULL;
        for (pbus = dev->bus; pbus; pbus = pbus->parent) {
                handle = acpi_pci_get_bridge_handle(pbus);
@@@ -531,11 -537,32 +540,32 @@@ static struct pci_platform_pm_ops acpi_
  
  void acpi_pci_add_bus(struct pci_bus *bus)
  {
+       union acpi_object *obj;
+       struct pci_host_bridge *bridge;
        if (acpi_pci_disabled || !bus->bridge)
                return;
  
        acpi_pci_slot_enumerate(bus);
        acpiphp_enumerate_slots(bus);
+       /*
+        * For a host bridge, check its _DSM for function 8 and if
+        * that is available, mark it in pci_host_bridge.
+        */
+       if (!pci_is_root_bus(bus))
+               return;
+       obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), pci_acpi_dsm_uuid, 3,
+                               RESET_DELAY_DSM, NULL);
+       if (!obj)
+               return;
+       if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) {
+               bridge = pci_find_host_bridge(bus);
+               bridge->ignore_reset_delay = 1;
+       }
+       ACPI_FREE(obj);
  }
  
  void acpi_pci_remove_bus(struct pci_bus *bus)
@@@ -561,6 -588,57 +591,57 @@@ static struct acpi_device *acpi_pci_fin
                                      check_children);
  }
  
+ /**
+  * pci_acpi_optimize_delay - optimize PCI D3 and D3cold delay from ACPI
+  * @pdev: the PCI device whose delay is to be updated
+  * @adev: the companion ACPI device of this PCI device
+  *
+  * Update the d3_delay and d3cold_delay of a PCI device from the ACPI _DSM
+  * control method of either the device itself or the PCI host bridge.
+  *
+  * Function 8, "Reset Delay," applies to the entire hierarchy below a PCI
+  * host bridge.  If it returns one, the OS may assume that all devices in
+  * the hierarchy have already completed power-on reset delays.
+  *
+  * Function 9, "Device Readiness Durations," applies only to the object
+  * where it is located.  It returns delay durations required after various
+  * events if the device requires less time than the spec requires.  Delays
+  * from this function take precedence over the Reset Delay function.
+  *
+  * These _DSM functions are defined by the draft ECN of January 28, 2014,
+  * titled "ACPI additions for FW latency optimizations."
+  */
+ static void pci_acpi_optimize_delay(struct pci_dev *pdev,
+                                   acpi_handle handle)
+ {
+       struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
+       int value;
+       union acpi_object *obj, *elements;
+       if (bridge->ignore_reset_delay)
+               pdev->d3cold_delay = 0;
+       obj = acpi_evaluate_dsm(handle, pci_acpi_dsm_uuid, 3,
+                               FUNCTION_DELAY_DSM, NULL);
+       if (!obj)
+               return;
+       if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) {
+               elements = obj->package.elements;
+               if (elements[0].type == ACPI_TYPE_INTEGER) {
+                       value = (int)elements[0].integer.value / 1000;
+                       if (value < PCI_PM_D3COLD_WAIT)
+                               pdev->d3cold_delay = value;
+               }
+               if (elements[3].type == ACPI_TYPE_INTEGER) {
+                       value = (int)elements[3].integer.value / 1000;
+                       if (value < PCI_PM_D3_WAIT)
+                               pdev->d3_delay = value;
+               }
+       }
+       ACPI_FREE(obj);
+ }
  static void pci_acpi_setup(struct device *dev)
  {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        if (!adev)
                return;
  
+       pci_acpi_optimize_delay(pci_dev, adev->handle);
        pci_acpi_add_pm_notifier(adev, pci_dev);
        if (!adev->wakeup.flags.valid)
                return;