Merge tag 'pci-v4.19-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[linux-2.6-microblaze.git] / drivers / pci / pci.c
index aa1684d..29ff961 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/string.h>
 #include <linux/log2.h>
 #include <linux/logic_pio.h>
-#include <linux/pci-aspm.h>
 #include <linux/pm_wakeup.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
@@ -115,6 +114,9 @@ static bool pcie_ari_disabled;
 /* If set, the PCIe ATS capability will not be used. */
 static bool pcie_ats_disabled;
 
+/* If set, the PCI config space of each device is printed during boot. */
+bool pci_early_dump;
+
 bool pci_ats_disabled(void)
 {
        return pcie_ats_disabled;
@@ -191,6 +193,168 @@ void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar)
 EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
 #endif
 
+/**
+ * pci_dev_str_match_path - test if a path string matches a device
+ * @dev:    the PCI device to test
+ * @p:      string to match the device against
+ * @endptr: pointer to the string after the match
+ *
+ * Test if a string (typically from a kernel parameter) formatted as a
+ * path of device/function addresses matches a PCI device. The string must
+ * be of the form:
+ *
+ *   [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
+ *
+ * A path for a device can be obtained using 'lspci -t'.  Using a path
+ * is more robust against bus renumbering than using only a single bus,
+ * device and function address.
+ *
+ * Returns 1 if the string matches the device, 0 if it does not and
+ * a negative error code if it fails to parse the string.
+ */
+static int pci_dev_str_match_path(struct pci_dev *dev, const char *path,
+                                 const char **endptr)
+{
+       int ret;
+       int seg, bus, slot, func;
+       char *wpath, *p;
+       char end;
+
+       *endptr = strchrnul(path, ';');
+
+       wpath = kmemdup_nul(path, *endptr - path, GFP_KERNEL);
+       if (!wpath)
+               return -ENOMEM;
+
+       while (1) {
+               p = strrchr(wpath, '/');
+               if (!p)
+                       break;
+               ret = sscanf(p, "/%x.%x%c", &slot, &func, &end);
+               if (ret != 2) {
+                       ret = -EINVAL;
+                       goto free_and_exit;
+               }
+
+               if (dev->devfn != PCI_DEVFN(slot, func)) {
+                       ret = 0;
+                       goto free_and_exit;
+               }
+
+               /*
+                * Note: we don't need to get a reference to the upstream
+                * bridge because we hold a reference to the top level
+                * device which should hold a reference to the bridge,
+                * and so on.
+                */
+               dev = pci_upstream_bridge(dev);
+               if (!dev) {
+                       ret = 0;
+                       goto free_and_exit;
+               }
+
+               *p = 0;
+       }
+
+       ret = sscanf(wpath, "%x:%x:%x.%x%c", &seg, &bus, &slot,
+                    &func, &end);
+       if (ret != 4) {
+               seg = 0;
+               ret = sscanf(wpath, "%x:%x.%x%c", &bus, &slot, &func, &end);
+               if (ret != 3) {
+                       ret = -EINVAL;
+                       goto free_and_exit;
+               }
+       }
+
+       ret = (seg == pci_domain_nr(dev->bus) &&
+              bus == dev->bus->number &&
+              dev->devfn == PCI_DEVFN(slot, func));
+
+free_and_exit:
+       kfree(wpath);
+       return ret;
+}
+
+/**
+ * pci_dev_str_match - test if a string matches a device
+ * @dev:    the PCI device to test
+ * @p:      string to match the device against
+ * @endptr: pointer to the string after the match
+ *
+ * Test if a string (typically from a kernel parameter) matches a specified
+ * PCI device. The string may be of one of the following formats:
+ *
+ *   [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
+ *   pci:<vendor>:<device>[:<subvendor>:<subdevice>]
+ *
+ * The first format specifies a PCI bus/device/function address which
+ * may change if new hardware is inserted, if motherboard firmware changes,
+ * or due to changes caused in kernel parameters. If the domain is
+ * left unspecified, it is taken to be 0.  In order to be robust against
+ * bus renumbering issues, a path of PCI device/function numbers may be used
+ * to address the specific device.  The path for a device can be determined
+ * through the use of 'lspci -t'.
+ *
+ * The second format matches devices using IDs in the configuration
+ * space which may match multiple devices in the system. A value of 0
+ * for any field will match all devices. (Note: this differs from
+ * in-kernel code that uses PCI_ANY_ID which is ~0; this is for
+ * legacy reasons and convenience so users don't have to specify
+ * FFFFFFFFs on the command line.)
+ *
+ * Returns 1 if the string matches the device, 0 if it does not and
+ * a negative error code if the string cannot be parsed.
+ */
+static int pci_dev_str_match(struct pci_dev *dev, const char *p,
+                            const char **endptr)
+{
+       int ret;
+       int count;
+       unsigned short vendor, device, subsystem_vendor, subsystem_device;
+
+       if (strncmp(p, "pci:", 4) == 0) {
+               /* PCI vendor/device (subvendor/subdevice) IDs are specified */
+               p += 4;
+               ret = sscanf(p, "%hx:%hx:%hx:%hx%n", &vendor, &device,
+                            &subsystem_vendor, &subsystem_device, &count);
+               if (ret != 4) {
+                       ret = sscanf(p, "%hx:%hx%n", &vendor, &device, &count);
+                       if (ret != 2)
+                               return -EINVAL;
+
+                       subsystem_vendor = 0;
+                       subsystem_device = 0;
+               }
+
+               p += count;
+
+               if ((!vendor || vendor == dev->vendor) &&
+                   (!device || device == dev->device) &&
+                   (!subsystem_vendor ||
+                           subsystem_vendor == dev->subsystem_vendor) &&
+                   (!subsystem_device ||
+                           subsystem_device == dev->subsystem_device))
+                       goto found;
+       } else {
+               /*
+                * PCI Bus, Device, Function IDs are specified
+                *  (optionally, may include a path of devfns following it)
+                */
+               ret = pci_dev_str_match_path(dev, p, &p);
+               if (ret < 0)
+                       return ret;
+               else if (ret)
+                       goto found;
+       }
+
+       *endptr = p;
+       return 0;
+
+found:
+       *endptr = p;
+       return 1;
+}
 
 static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
                                   u8 pos, int cap, int *ttl)
@@ -1171,6 +1335,33 @@ static void pci_restore_config_space(struct pci_dev *pdev)
        }
 }
 
+static void pci_restore_rebar_state(struct pci_dev *pdev)
+{
+       unsigned int pos, nbars, i;
+       u32 ctrl;
+
+       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
+       if (!pos)
+               return;
+
+       pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
+       nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >>
+                   PCI_REBAR_CTRL_NBAR_SHIFT;
+
+       for (i = 0; i < nbars; i++, pos += 8) {
+               struct resource *res;
+               int bar_idx, size;
+
+               pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
+               bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
+               res = pdev->resource + bar_idx;
+               size = order_base_2((resource_size(res) >> 20) | 1) - 1;
+               ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
+               ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT;
+               pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
+       }
+}
+
 /**
  * pci_restore_state - Restore the saved state of a PCI device
  * @dev: - PCI device that we're dealing with
@@ -1186,6 +1377,7 @@ void pci_restore_state(struct pci_dev *dev)
        pci_restore_pri_state(dev);
        pci_restore_ats_state(dev);
        pci_restore_vc_state(dev);
+       pci_restore_rebar_state(dev);
 
        pci_cleanup_aer_error_status_regs(dev);
 
@@ -2045,6 +2237,7 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
                case PCI_D2:
                        if (pci_no_d1d2(dev))
                                break;
+                       /* else: fall through */
                default:
                        target_state = state;
                }
@@ -2290,7 +2483,7 @@ void pci_config_pm_runtime_put(struct pci_dev *pdev)
  * @bridge: Bridge to check
  *
  * This function checks if it is possible to move the bridge to D3.
- * Currently we only allow D3 for recent enough PCIe ports.
+ * Currently we only allow D3 for recent enough PCIe ports and Thunderbolt.
  */
 bool pci_bridge_d3_possible(struct pci_dev *bridge)
 {
@@ -2305,18 +2498,27 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge)
                        return false;
 
                /*
-                * Hotplug interrupts cannot be delivered if the link is down,
-                * so parents of a hotplug port must stay awake. In addition,
-                * hotplug ports handled by firmware in System Management Mode
+                * Hotplug ports handled by firmware in System Management Mode
                 * may not be put into D3 by the OS (Thunderbolt on non-Macs).
-                * For simplicity, disallow in general for now.
                 */
-               if (bridge->is_hotplug_bridge)
+               if (bridge->is_hotplug_bridge && !pciehp_is_native(bridge))
                        return false;
 
                if (pci_bridge_d3_force)
                        return true;
 
+               /* Even the oldest 2010 Thunderbolt controller supports D3. */
+               if (bridge->is_thunderbolt)
+                       return true;
+
+               /*
+                * Hotplug ports handled natively by the OS were not validated
+                * by vendors for runtime D3 at least until 2018 because there
+                * was no OS support.
+                */
+               if (bridge->is_hotplug_bridge)
+                       return false;
+
                /*
                 * It should be safe to put PCIe ports from 2015 or newer
                 * to D3.
@@ -2820,6 +3022,66 @@ void pci_request_acs(void)
        pci_acs_enable = 1;
 }
 
+static const char *disable_acs_redir_param;
+
+/**
+ * pci_disable_acs_redir - disable ACS redirect capabilities
+ * @dev: the PCI device
+ *
+ * For only devices specified in the disable_acs_redir parameter.
+ */
+static void pci_disable_acs_redir(struct pci_dev *dev)
+{
+       int ret = 0;
+       const char *p;
+       int pos;
+       u16 ctrl;
+
+       if (!disable_acs_redir_param)
+               return;
+
+       p = disable_acs_redir_param;
+       while (*p) {
+               ret = pci_dev_str_match(dev, p, &p);
+               if (ret < 0) {
+                       pr_info_once("PCI: Can't parse disable_acs_redir parameter: %s\n",
+                                    disable_acs_redir_param);
+
+                       break;
+               } else if (ret == 1) {
+                       /* Found a match */
+                       break;
+               }
+
+               if (*p != ';' && *p != ',') {
+                       /* End of param or invalid format */
+                       break;
+               }
+               p++;
+       }
+
+       if (ret != 1)
+               return;
+
+       if (!pci_dev_specific_disable_acs_redir(dev))
+               return;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+       if (!pos) {
+               pci_warn(dev, "cannot disable ACS redirect for this hardware as it does not have ACS capabilities\n");
+               return;
+       }
+
+       pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
+
+       /* P2P Request & Completion Redirect */
+       ctrl &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC);
+
+       pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+
+       pci_info(dev, "disabled ACS redirect\n");
+}
+
 /**
  * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
  * @dev: the PCI device
@@ -2859,12 +3121,22 @@ static void pci_std_enable_acs(struct pci_dev *dev)
 void pci_enable_acs(struct pci_dev *dev)
 {
        if (!pci_acs_enable)
-               return;
+               goto disable_acs_redir;
 
        if (!pci_dev_specific_enable_acs(dev))
-               return;
+               goto disable_acs_redir;
 
        pci_std_enable_acs(dev);
+
+disable_acs_redir:
+       /*
+        * Note: pci_disable_acs_redir() must be called even if ACS was not
+        * enabled by the kernel because it may have been enabled by
+        * platform firmware.  So if we are told to disable it, we should
+        * always disable it after setting the kernel's default
+        * preferences.
+        */
+       pci_disable_acs_redir(dev);
 }
 
 static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
@@ -3070,7 +3342,7 @@ int pci_rebar_get_current_size(struct pci_dev *pdev, int bar)
                return pos;
 
        pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
-       return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> 8;
+       return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> PCI_REBAR_CTRL_BAR_SHIFT;
 }
 
 /**
@@ -3093,7 +3365,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size)
 
        pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
        ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
-       ctrl |= size << 8;
+       ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT;
        pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
        return 0;
 }
@@ -4077,7 +4349,7 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
  * Returns true if the device advertises support for PCIe function level
  * resets.
  */
-static bool pcie_has_flr(struct pci_dev *dev)
+bool pcie_has_flr(struct pci_dev *dev)
 {
        u32 cap;
 
@@ -4087,6 +4359,7 @@ static bool pcie_has_flr(struct pci_dev *dev)
        pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
        return cap & PCI_EXP_DEVCAP_FLR;
 }
+EXPORT_SYMBOL_GPL(pcie_has_flr);
 
 /**
  * pcie_flr - initiate a PCIe function level reset
@@ -4262,19 +4535,18 @@ void __weak pcibios_reset_secondary_bus(struct pci_dev *dev)
 }
 
 /**
- * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge.
+ * pci_bridge_secondary_bus_reset - Reset the secondary bus on a PCI bridge.
  * @dev: Bridge device
  *
  * Use the bridge control register to assert reset on the secondary bus.
  * Devices on the secondary bus are left in power-on state.
  */
-int pci_reset_bridge_secondary_bus(struct pci_dev *dev)
+int pci_bridge_secondary_bus_reset(struct pci_dev *dev)
 {
        pcibios_reset_secondary_bus(dev);
 
        return pci_dev_wait(dev, "bus reset", PCIE_RESET_READY_POLL_MS);
 }
-EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus);
 
 static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
 {
@@ -4291,9 +4563,7 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
        if (probe)
                return 0;
 
-       pci_reset_bridge_secondary_bus(dev->bus->self);
-
-       return 0;
+       return pci_bridge_secondary_bus_reset(dev->bus->self);
 }
 
 static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
@@ -4825,7 +5095,7 @@ int pci_probe_reset_slot(struct pci_slot *slot)
 EXPORT_SYMBOL_GPL(pci_probe_reset_slot);
 
 /**
- * pci_reset_slot - reset a PCI slot
+ * __pci_reset_slot - Try to reset a PCI slot
  * @slot: PCI slot to reset
  *
  * A PCI bus may host multiple slots, each slot may support a reset mechanism
@@ -4837,33 +5107,9 @@ EXPORT_SYMBOL_GPL(pci_probe_reset_slot);
  * through this function.  PCI config space of all devices in the slot and
  * behind the slot is saved before and restored after reset.
  *
- * Return 0 on success, non-zero on error.
- */
-int pci_reset_slot(struct pci_slot *slot)
-{
-       int rc;
-
-       rc = pci_slot_reset(slot, 1);
-       if (rc)
-               return rc;
-
-       pci_slot_save_and_disable(slot);
-
-       rc = pci_slot_reset(slot, 0);
-
-       pci_slot_restore(slot);
-
-       return rc;
-}
-EXPORT_SYMBOL_GPL(pci_reset_slot);
-
-/**
- * pci_try_reset_slot - Try to reset a PCI slot
- * @slot: PCI slot to reset
- *
  * Same as above except return -EAGAIN if the slot cannot be locked
  */
-int pci_try_reset_slot(struct pci_slot *slot)
+static int __pci_reset_slot(struct pci_slot *slot)
 {
        int rc;
 
@@ -4884,10 +5130,11 @@ int pci_try_reset_slot(struct pci_slot *slot)
 
        return rc;
 }
-EXPORT_SYMBOL_GPL(pci_try_reset_slot);
 
 static int pci_bus_reset(struct pci_bus *bus, int probe)
 {
+       int ret;
+
        if (!bus->self || !pci_bus_resetable(bus))
                return -ENOTTY;
 
@@ -4898,11 +5145,11 @@ static int pci_bus_reset(struct pci_bus *bus, int probe)
 
        might_sleep();
 
-       pci_reset_bridge_secondary_bus(bus->self);
+       ret = pci_bridge_secondary_bus_reset(bus->self);
 
        pci_bus_unlock(bus);
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -4918,15 +5165,12 @@ int pci_probe_reset_bus(struct pci_bus *bus)
 EXPORT_SYMBOL_GPL(pci_probe_reset_bus);
 
 /**
- * pci_reset_bus - reset a PCI bus
+ * __pci_reset_bus - Try to reset a PCI bus
  * @bus: top level PCI bus to reset
  *
- * Do a bus reset on the given bus and any subordinate buses, saving
- * and restoring state of all devices.
- *
- * Return 0 on success, non-zero on error.
+ * Same as above except return -EAGAIN if the bus cannot be locked
  */
-int pci_reset_bus(struct pci_bus *bus)
+static int __pci_reset_bus(struct pci_bus *bus)
 {
        int rc;
 
@@ -4936,42 +5180,30 @@ int pci_reset_bus(struct pci_bus *bus)
 
        pci_bus_save_and_disable(bus);
 
-       rc = pci_bus_reset(bus, 0);
+       if (pci_bus_trylock(bus)) {
+               might_sleep();
+               rc = pci_bridge_secondary_bus_reset(bus->self);
+               pci_bus_unlock(bus);
+       } else
+               rc = -EAGAIN;
 
        pci_bus_restore(bus);
 
        return rc;
 }
-EXPORT_SYMBOL_GPL(pci_reset_bus);
 
 /**
- * pci_try_reset_bus - Try to reset a PCI bus
- * @bus: top level PCI bus to reset
+ * pci_reset_bus - Try to reset a PCI bus
+ * @pdev: top level PCI device to reset via slot/bus
  *
  * Same as above except return -EAGAIN if the bus cannot be locked
  */
-int pci_try_reset_bus(struct pci_bus *bus)
+int pci_reset_bus(struct pci_dev *pdev)
 {
-       int rc;
-
-       rc = pci_bus_reset(bus, 1);
-       if (rc)
-               return rc;
-
-       pci_bus_save_and_disable(bus);
-
-       if (pci_bus_trylock(bus)) {
-               might_sleep();
-               pci_reset_bridge_secondary_bus(bus->self);
-               pci_bus_unlock(bus);
-       } else
-               rc = -EAGAIN;
-
-       pci_bus_restore(bus);
-
-       return rc;
+       return pci_probe_reset_slot(pdev->slot) ?
+           __pci_reset_slot(pdev->slot) : __pci_reset_bus(pdev->bus);
 }
-EXPORT_SYMBOL_GPL(pci_try_reset_bus);
+EXPORT_SYMBOL_GPL(pci_reset_bus);
 
 /**
  * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
@@ -5304,14 +5536,16 @@ u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
 }
 
 /**
- * pcie_print_link_status - Report the PCI device's link speed and width
+ * __pcie_print_link_status - Report the PCI device's link speed and width
  * @dev: PCI device to query
+ * @verbose: Print info even when enough bandwidth is available
  *
- * Report the available bandwidth at the device.  If this is less than the
- * device is capable of, report the device's maximum possible bandwidth and
- * the upstream link that limits its performance to less than that.
+ * If the available bandwidth at the device is less than the device is
+ * capable of, report the device's maximum possible bandwidth and the
+ * upstream link that limits its performance.  If @verbose, always print
+ * the available bandwidth, even if the device isn't constrained.
  */
-void pcie_print_link_status(struct pci_dev *dev)
+void __pcie_print_link_status(struct pci_dev *dev, bool verbose)
 {
        enum pcie_link_width width, width_cap;
        enum pci_bus_speed speed, speed_cap;
@@ -5321,11 +5555,11 @@ void pcie_print_link_status(struct pci_dev *dev)
        bw_cap = pcie_bandwidth_capable(dev, &speed_cap, &width_cap);
        bw_avail = pcie_bandwidth_available(dev, &limiting_dev, &speed, &width);
 
-       if (bw_avail >= bw_cap)
+       if (bw_avail >= bw_cap && verbose)
                pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth (%s x%d link)\n",
                         bw_cap / 1000, bw_cap % 1000,
                         PCIE_SPEED2STR(speed_cap), width_cap);
-       else
+       else if (bw_avail < bw_cap)
                pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth, limited by %s x%d link at %s (capable of %u.%03u Gb/s with %s x%d link)\n",
                         bw_avail / 1000, bw_avail % 1000,
                         PCIE_SPEED2STR(speed), width,
@@ -5333,6 +5567,17 @@ void pcie_print_link_status(struct pci_dev *dev)
                         bw_cap / 1000, bw_cap % 1000,
                         PCIE_SPEED2STR(speed_cap), width_cap);
 }
+
+/**
+ * pcie_print_link_status - Report the PCI device's link speed and width
+ * @dev: PCI device to query
+ *
+ * Report the available bandwidth at the device.
+ */
+void pcie_print_link_status(struct pci_dev *dev)
+{
+       __pcie_print_link_status(dev, true);
+}
 EXPORT_SYMBOL(pcie_print_link_status);
 
 /**
@@ -5427,8 +5672,19 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
  * @dev: the PCI device for which alias is added
  * @devfn: alias slot and function
  *
- * This helper encodes 8-bit devfn as bit number in dma_alias_mask.
- * It should be called early, preferably as PCI fixup header quirk.
+ * This helper encodes an 8-bit devfn as a bit number in dma_alias_mask
+ * which is used to program permissible bus-devfn source addresses for DMA
+ * requests in an IOMMU.  These aliases factor into IOMMU group creation
+ * and are useful for devices generating DMA requests beyond or different
+ * from their logical bus-devfn.  Examples include device quirks where the
+ * device simply uses the wrong devfn, as well as non-transparent bridges
+ * where the alias may be a proxy for devices in another domain.
+ *
+ * IOMMU group creation is performed during device discovery or addition,
+ * prior to any potential DMA mapping and therefore prior to driver probing
+ * (especially for userspace assigned devices where IOMMU group definition
+ * cannot be left as a userspace activity).  DMA aliases should therefore
+ * be configured via quirks, such as the PCI fixup header quirk.
  */
 void pci_add_dma_alias(struct pci_dev *dev, u8 devfn)
 {
@@ -5494,10 +5750,10 @@ static DEFINE_SPINLOCK(resource_alignment_lock);
 static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
                                                        bool *resize)
 {
-       int seg, bus, slot, func, align_order, count;
-       unsigned short vendor, device, subsystem_vendor, subsystem_device;
+       int align_order, count;
        resource_size_t align = pcibios_default_alignment();
-       char *p;
+       const char *p;
+       int ret;
 
        spin_lock(&resource_alignment_lock);
        p = resource_alignment_param;
@@ -5517,58 +5773,21 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
                } else {
                        align_order = -1;
                }
-               if (strncmp(p, "pci:", 4) == 0) {
-                       /* PCI vendor/device (subvendor/subdevice) ids are specified */
-                       p += 4;
-                       if (sscanf(p, "%hx:%hx:%hx:%hx%n",
-                               &vendor, &device, &subsystem_vendor, &subsystem_device, &count) != 4) {
-                               if (sscanf(p, "%hx:%hx%n", &vendor, &device, &count) != 2) {
-                                       printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: pci:%s\n",
-                                               p);
-                                       break;
-                               }
-                               subsystem_vendor = subsystem_device = 0;
-                       }
-                       p += count;
-                       if ((!vendor || (vendor == dev->vendor)) &&
-                               (!device || (device == dev->device)) &&
-                               (!subsystem_vendor || (subsystem_vendor == dev->subsystem_vendor)) &&
-                               (!subsystem_device || (subsystem_device == dev->subsystem_device))) {
-                               *resize = true;
-                               if (align_order == -1)
-                                       align = PAGE_SIZE;
-                               else
-                                       align = 1 << align_order;
-                               /* Found */
-                               break;
-                       }
-               }
-               else {
-                       if (sscanf(p, "%x:%x:%x.%x%n",
-                               &seg, &bus, &slot, &func, &count) != 4) {
-                               seg = 0;
-                               if (sscanf(p, "%x:%x.%x%n",
-                                               &bus, &slot, &func, &count) != 3) {
-                                       /* Invalid format */
-                                       printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n",
-                                               p);
-                                       break;
-                               }
-                       }
-                       p += count;
-                       if (seg == pci_domain_nr(dev->bus) &&
-                               bus == dev->bus->number &&
-                               slot == PCI_SLOT(dev->devfn) &&
-                               func == PCI_FUNC(dev->devfn)) {
-                               *resize = true;
-                               if (align_order == -1)
-                                       align = PAGE_SIZE;
-                               else
-                                       align = 1 << align_order;
-                               /* Found */
-                               break;
-                       }
+
+               ret = pci_dev_str_match(dev, p, &p);
+               if (ret == 1) {
+                       *resize = true;
+                       if (align_order == -1)
+                               align = PAGE_SIZE;
+                       else
+                               align = 1 << align_order;
+                       break;
+               } else if (ret < 0) {
+                       pr_err("PCI: Can't parse resource_alignment parameter: %s\n",
+                              p);
+                       break;
                }
+
                if (*p != ';' && *p != ',') {
                        /* End of param or invalid format */
                        break;
@@ -5845,6 +6064,8 @@ static int __init pci_setup(char *str)
                                pcie_ats_disabled = true;
                        } else if (!strcmp(str, "noaer")) {
                                pci_no_aer();
+                       } else if (!strcmp(str, "earlydump")) {
+                               pci_early_dump = true;
                        } else if (!strncmp(str, "realloc=", 8)) {
                                pci_realloc_get_opt(str + 8);
                        } else if (!strncmp(str, "realloc", 7)) {
@@ -5881,6 +6102,8 @@ static int __init pci_setup(char *str)
                                pcie_bus_config = PCIE_BUS_PEER2PEER;
                        } else if (!strncmp(str, "pcie_scan_all", 13)) {
                                pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS);
+                       } else if (!strncmp(str, "disable_acs_redir=", 18)) {
+                               disable_acs_redir_param = str + 18;
                        } else {
                                printk(KERN_ERR "PCI: Unknown option `%s'\n",
                                                str);