Merge tag 'maintainers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[cascardo/linux.git] / drivers / pci / pci.c
index 053670e..8156744 100644 (file)
@@ -94,6 +94,9 @@ u8 pci_cache_line_size;
  */
 unsigned int pcibios_max_latency = 255;
 
+/* If set, the PCIe ARI capability will not be used. */
+static bool pcie_ari_disabled;
+
 /**
  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
  * @bus: pointer to PCI bus structure to search
@@ -825,6 +828,19 @@ EXPORT_SYMBOL(pci_choose_state);
 #define pcie_cap_has_sltctl2(type, flags)              \
                ((flags & PCI_EXP_FLAGS_VERS) > 1)
 
+static struct pci_cap_saved_state *pci_find_saved_cap(
+       struct pci_dev *pci_dev, char cap)
+{
+       struct pci_cap_saved_state *tmp;
+       struct hlist_node *pos;
+
+       hlist_for_each_entry(tmp, pos, &pci_dev->saved_cap_space, next) {
+               if (tmp->cap.cap_nr == cap)
+                       return tmp;
+       }
+       return NULL;
+}
+
 static int pci_save_pcie_state(struct pci_dev *dev)
 {
        int pos, i = 0;
@@ -959,6 +975,7 @@ void pci_restore_state(struct pci_dev *dev)
 {
        int i;
        u32 val;
+       int tries;
 
        if (!dev->state_saved)
                return;
@@ -973,12 +990,16 @@ void pci_restore_state(struct pci_dev *dev)
         */
        for (i = 15; i >= 0; i--) {
                pci_read_config_dword(dev, i * 4, &val);
-               if (val != dev->saved_config_space[i]) {
+               tries = 10;             
+               while (tries && val != dev->saved_config_space[i]) {
                        dev_dbg(&dev->dev, "restoring config "
                                "space at offset %#x (was %#x, writing %#x)\n",
                                i, val, (int)dev->saved_config_space[i]);
                        pci_write_config_dword(dev,i * 4,
                                dev->saved_config_space[i]);
+                       pci_read_config_dword(dev, i * 4, &val);
+                       mdelay(10);
+                       tries--;
                }
        }
        pci_restore_pcix_state(dev);
@@ -1864,6 +1885,12 @@ void platform_pci_wakeup_init(struct pci_dev *dev)
        platform_pci_sleep_wake(dev, false);
 }
 
+static void pci_add_saved_cap(struct pci_dev *pci_dev,
+       struct pci_cap_saved_state *new_cap)
+{
+       hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
+}
+
 /**
  * pci_add_save_buffer - allocate buffer for saving given capability registers
  * @dev: the PCI device
@@ -1911,6 +1938,15 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
                        "unable to preallocate PCI-X save buffer\n");
 }
 
+void pci_free_cap_save_buffers(struct pci_dev *dev)
+{
+       struct pci_cap_saved_state *tmp;
+       struct hlist_node *pos, *n;
+
+       hlist_for_each_entry_safe(tmp, pos, n, &dev->saved_cap_space, next)
+               kfree(tmp);
+}
+
 /**
  * pci_enable_ari - enable ARI forwarding if hardware support it
  * @dev: the PCI device
@@ -1922,7 +1958,7 @@ void pci_enable_ari(struct pci_dev *dev)
        u16 flags, ctrl;
        struct pci_dev *bridge;
 
-       if (!pci_is_pcie(dev) || dev->devfn)
+       if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn)
                return;
 
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
@@ -3661,6 +3697,68 @@ int pci_is_reassigndev(struct pci_dev *dev)
        return (pci_specified_resource_alignment(dev) != 0);
 }
 
+/*
+ * This function disables memory decoding and releases memory resources
+ * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
+ * It also rounds up size to specified alignment.
+ * Later on, the kernel will assign page-aligned memory resource back
+ * to the device.
+ */
+void pci_reassigndev_resource_alignment(struct pci_dev *dev)
+{
+       int i;
+       struct resource *r;
+       resource_size_t align, size;
+       u16 command;
+
+       if (!pci_is_reassigndev(dev))
+               return;
+
+       if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
+               dev_warn(&dev->dev,
+                       "Can't reassign resources to host bridge.\n");
+               return;
+       }
+
+       dev_info(&dev->dev,
+               "Disabling memory decoding and releasing memory resources.\n");
+       pci_read_config_word(dev, PCI_COMMAND, &command);
+       command &= ~PCI_COMMAND_MEMORY;
+       pci_write_config_word(dev, PCI_COMMAND, command);
+
+       align = pci_specified_resource_alignment(dev);
+       for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
+               r = &dev->resource[i];
+               if (!(r->flags & IORESOURCE_MEM))
+                       continue;
+               size = resource_size(r);
+               if (size < align) {
+                       size = align;
+                       dev_info(&dev->dev,
+                               "Rounding up size of resource #%d to %#llx.\n",
+                               i, (unsigned long long)size);
+               }
+               r->end = size - 1;
+               r->start = 0;
+       }
+       /* Need to disable bridge's resource window,
+        * to enable the kernel to reassign new resource
+        * window later on.
+        */
+       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+               for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+                       r = &dev->resource[i];
+                       if (!(r->flags & IORESOURCE_MEM))
+                               continue;
+                       r->end = resource_size(r) - 1;
+                       r->start = 0;
+               }
+               pci_disable_bridge_window(dev);
+       }
+}
+
 ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
 {
        if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1)
@@ -3739,10 +3837,14 @@ static int __init pci_setup(char *str)
                                pci_no_msi();
                        } else if (!strcmp(str, "noaer")) {
                                pci_no_aer();
+                       } else if (!strncmp(str, "realloc=", 8)) {
+                               pci_realloc_get_opt(str + 8);
                        } else if (!strncmp(str, "realloc", 7)) {
-                               pci_realloc();
+                               pci_realloc_get_opt("on");
                        } else if (!strcmp(str, "nodomains")) {
                                pci_no_domains();
+                       } else if (!strncmp(str, "noari", 5)) {
+                               pcie_ari_disabled = true;
                        } else if (!strncmp(str, "cbiosize=", 9)) {
                                pci_cardbus_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "cbmemsize=", 10)) {