Merge tag 'pm+acpi-4.4-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[firefly-linux-kernel-4.4.55.git] / drivers / pci / probe.c
index d35f83d80b15e72fb032cc25522a68d4e5910e22..e735c728e3b34aa441d1bc140e5473554af8385d 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
+#include <linux/aer.h>
+#include <linux/acpi.h>
 #include <asm-generic/pci-bridge.h>
 #include "pci.h"
 
@@ -1598,6 +1600,9 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
 
 static void pci_init_capabilities(struct pci_dev *dev)
 {
+       /* Enhanced Allocation */
+       pci_ea_init(dev);
+
        /* MSI/MSI-X list */
        pci_msi_init_pci_dev(dev);
 
@@ -1621,17 +1626,52 @@ static void pci_init_capabilities(struct pci_dev *dev)
 
        /* Enable ACS P2P upstream forwarding */
        pci_enable_acs(dev);
+
+       pci_cleanup_aer_error_status_regs(dev);
+}
+
+/*
+ * This is the equivalent of pci_host_bridge_msi_domain that acts on
+ * devices. Firmware interfaces that can select the MSI domain on a
+ * per-device basis should be called from here.
+ */
+static struct irq_domain *pci_dev_msi_domain(struct pci_dev *dev)
+{
+       struct irq_domain *d;
+
+       /*
+        * If a domain has been set through the pcibios_add_device
+        * callback, then this is the one (platform code knows best).
+        */
+       d = dev_get_msi_domain(&dev->dev);
+       if (d)
+               return d;
+
+       /*
+        * Let's see if we have a firmware interface able to provide
+        * the domain.
+        */
+       d = pci_msi_get_device_domain(dev);
+       if (d)
+               return d;
+
+       return NULL;
 }
 
 static void pci_set_msi_domain(struct pci_dev *dev)
 {
+       struct irq_domain *d;
+
        /*
-        * If no domain has been set through the pcibios_add_device
-        * callback, inherit the default from the bus device.
+        * If the platform or firmware interfaces cannot supply a
+        * device-specific MSI domain, then inherit the default domain
+        * from the host bridge itself.
         */
-       if (!dev_get_msi_domain(&dev->dev))
-               dev_set_msi_domain(&dev->dev,
-                                  dev_get_msi_domain(&dev->bus->dev));
+       d = pci_dev_msi_domain(dev);
+       if (!d)
+               d = dev_get_msi_domain(&dev->bus->dev);
+
+       dev_set_msi_domain(&dev->dev, d);
 }
 
 /**
@@ -1639,7 +1679,7 @@ static void pci_set_msi_domain(struct pci_dev *dev)
  * @dev: ptr to pci_dev struct of the PCI device
  *
  * Function to update PCI devices's DMA configuration using the same
- * info from the OF node of host bridge's parent (if any).
+ * info from the OF node or ACPI node of host bridge's parent (if any).
  */
 static void pci_dma_configure(struct pci_dev *dev)
 {
@@ -1648,6 +1688,15 @@ static void pci_dma_configure(struct pci_dev *dev)
        if (IS_ENABLED(CONFIG_OF) && dev->dev.of_node) {
                if (bridge->parent)
                        of_dma_configure(&dev->dev, bridge->parent->of_node);
+       } else if (has_acpi_companion(bridge)) {
+               struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
+               enum dev_dma_attr attr = acpi_get_dma_attr(adev);
+
+               if (attr == DEV_DMA_NOT_SUPPORTED)
+                       dev_warn(&dev->dev, "DMA not supported.\n");
+               else
+                       arch_setup_dma_ops(&dev->dev, 0, 0, NULL,
+                                          attr == DEV_DMA_COHERENT);
        }
 
        pci_put_host_bridge_device(bridge);