Merge tag 'pci-v5.15-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[linux-2.6-microblaze.git] / drivers / pci / pci.c
index a5e6759..ce2ab62 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/vmalloc.h>
 #include <asm/dma.h>
 #include <linux/aer.h>
+#include <linux/bitfield.h>
 #include "pci.h"
 
 DEFINE_MUTEX(pci_slot_mutex);
@@ -72,6 +73,11 @@ static void pci_dev_d3_sleep(struct pci_dev *dev)
                msleep(delay);
 }
 
+bool pci_reset_supported(struct pci_dev *dev)
+{
+       return dev->reset_methods[0] != 0;
+}
+
 #ifdef CONFIG_PCI_DOMAINS
 int pci_domains_supported = 1;
 #endif
@@ -206,32 +212,36 @@ int pci_status_get_and_clear_errors(struct pci_dev *pdev)
 EXPORT_SYMBOL_GPL(pci_status_get_and_clear_errors);
 
 #ifdef CONFIG_HAS_IOMEM
-void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
+static void __iomem *__pci_ioremap_resource(struct pci_dev *pdev, int bar,
+                                           bool write_combine)
 {
        struct resource *res = &pdev->resource[bar];
+       resource_size_t start = res->start;
+       resource_size_t size = resource_size(res);
 
        /*
         * Make sure the BAR is actually a memory resource, not an IO resource
         */
        if (res->flags & IORESOURCE_UNSET || !(res->flags & IORESOURCE_MEM)) {
-               pci_warn(pdev, "can't ioremap BAR %d: %pR\n", bar, res);
+               pci_err(pdev, "can't ioremap BAR %d: %pR\n", bar, res);
                return NULL;
        }
-       return ioremap(res->start, resource_size(res));
+
+       if (write_combine)
+               return ioremap_wc(start, size);
+
+       return ioremap(start, size);
+}
+
+void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
+{
+       return __pci_ioremap_resource(pdev, bar, false);
 }
 EXPORT_SYMBOL_GPL(pci_ioremap_bar);
 
 void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar)
 {
-       /*
-        * Make sure the BAR is actually a memory resource, not an IO resource
-        */
-       if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
-               WARN_ON(1);
-               return NULL;
-       }
-       return ioremap_wc(pci_resource_start(pdev, bar),
-                         pci_resource_len(pdev, bar));
+       return __pci_ioremap_resource(pdev, bar, true);
 }
 EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
 #endif
@@ -265,7 +275,7 @@ static int pci_dev_str_match_path(struct pci_dev *dev, const char *path,
 
        *endptr = strchrnul(path, ';');
 
-       wpath = kmemdup_nul(path, *endptr - path, GFP_KERNEL);
+       wpath = kmemdup_nul(path, *endptr - path, GFP_ATOMIC);
        if (!wpath)
                return -ENOMEM;
 
@@ -915,8 +925,8 @@ static void pci_std_enable_acs(struct pci_dev *dev)
        /* Upstream Forwarding */
        ctrl |= (cap & PCI_ACS_UF);
 
-       /* Enable Translation Blocking for external devices */
-       if (dev->external_facing || dev->untrusted)
+       /* Enable Translation Blocking for external devices and noats */
+       if (pci_ats_disabled() || dev->external_facing || dev->untrusted)
                ctrl |= (cap & PCI_ACS_TB);
 
        pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
@@ -4628,32 +4638,12 @@ int pci_wait_for_pending_transaction(struct pci_dev *dev)
 }
 EXPORT_SYMBOL(pci_wait_for_pending_transaction);
 
-/**
- * pcie_has_flr - check if a device supports function level resets
- * @dev: device to check
- *
- * Returns true if the device advertises support for PCIe function level
- * resets.
- */
-bool pcie_has_flr(struct pci_dev *dev)
-{
-       u32 cap;
-
-       if (dev->dev_flags & PCI_DEV_FLAGS_NO_FLR_RESET)
-               return false;
-
-       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
  * @dev: device to reset
  *
- * Initiate a function level reset on @dev.  The caller should ensure the
- * device supports FLR before calling this function, e.g. by using the
- * pcie_has_flr() helper.
+ * Initiate a function level reset unconditionally on @dev without
+ * checking any flags and DEVCAP
  */
 int pcie_flr(struct pci_dev *dev)
 {
@@ -4676,7 +4666,29 @@ int pcie_flr(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pcie_flr);
 
-static int pci_af_flr(struct pci_dev *dev, int probe)
+/**
+ * pcie_reset_flr - initiate a PCIe function level reset
+ * @dev: device to reset
+ * @probe: if true, return 0 if device can be reset this way
+ *
+ * Initiate a function level reset on @dev.
+ */
+int pcie_reset_flr(struct pci_dev *dev, bool probe)
+{
+       if (dev->dev_flags & PCI_DEV_FLAGS_NO_FLR_RESET)
+               return -ENOTTY;
+
+       if (!(dev->devcap & PCI_EXP_DEVCAP_FLR))
+               return -ENOTTY;
+
+       if (probe)
+               return 0;
+
+       return pcie_flr(dev);
+}
+EXPORT_SYMBOL_GPL(pcie_reset_flr);
+
+static int pci_af_flr(struct pci_dev *dev, bool probe)
 {
        int pos;
        u8 cap;
@@ -4723,7 +4735,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
 /**
  * pci_pm_reset - Put device into PCI_D3 and back into PCI_D0.
  * @dev: Device to reset.
- * @probe: If set, only check if the device can be reset this way.
+ * @probe: if true, return 0 if the device can be reset this way.
  *
  * If @dev supports native PCI PM and its PCI_PM_CTRL_NO_SOFT_RESET flag is
  * unset, it will be reinitialized internally when going from PCI_D3hot to
@@ -4735,7 +4747,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
  * by default (i.e. unless the @dev's d3hot_delay field has a different value).
  * Moreover, only devices in D0 can be reset by this function.
  */
-static int pci_pm_reset(struct pci_dev *dev, int probe)
+static int pci_pm_reset(struct pci_dev *dev, bool probe)
 {
        u16 csr;
 
@@ -4995,7 +5007,7 @@ int pci_bridge_secondary_bus_reset(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_bridge_secondary_bus_reset);
 
-static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
+static int pci_parent_bus_reset(struct pci_dev *dev, bool probe)
 {
        struct pci_dev *pdev;
 
@@ -5013,7 +5025,7 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
        return pci_bridge_secondary_bus_reset(dev->bus->self);
 }
 
-static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
+static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, bool probe)
 {
        int rc = -ENOTTY;
 
@@ -5028,7 +5040,7 @@ static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
        return rc;
 }
 
-static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
+static int pci_dev_reset_slot_function(struct pci_dev *dev, bool probe)
 {
        if (dev->multifunction || dev->subordinate || !dev->slot ||
            dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
@@ -5037,7 +5049,7 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
        return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
 }
 
-static int pci_reset_bus_function(struct pci_dev *dev, int probe)
+static int pci_reset_bus_function(struct pci_dev *dev, bool probe)
 {
        int rc;
 
@@ -5121,6 +5133,139 @@ static void pci_dev_restore(struct pci_dev *dev)
                err_handler->reset_done(dev);
 }
 
+/* dev->reset_methods[] is a 0-terminated list of indices into this array */
+static const struct pci_reset_fn_method pci_reset_fn_methods[] = {
+       { },
+       { pci_dev_specific_reset, .name = "device_specific" },
+       { pci_dev_acpi_reset, .name = "acpi" },
+       { pcie_reset_flr, .name = "flr" },
+       { pci_af_flr, .name = "af_flr" },
+       { pci_pm_reset, .name = "pm" },
+       { pci_reset_bus_function, .name = "bus" },
+};
+
+static ssize_t reset_method_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       ssize_t len = 0;
+       int i, m;
+
+       for (i = 0; i < PCI_NUM_RESET_METHODS; i++) {
+               m = pdev->reset_methods[i];
+               if (!m)
+                       break;
+
+               len += sysfs_emit_at(buf, len, "%s%s", len ? " " : "",
+                                    pci_reset_fn_methods[m].name);
+       }
+
+       if (len)
+               len += sysfs_emit_at(buf, len, "\n");
+
+       return len;
+}
+
+static int reset_method_lookup(const char *name)
+{
+       int m;
+
+       for (m = 1; m < PCI_NUM_RESET_METHODS; m++) {
+               if (sysfs_streq(name, pci_reset_fn_methods[m].name))
+                       return m;
+       }
+
+       return 0;       /* not found */
+}
+
+static ssize_t reset_method_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       char *options, *name;
+       int m, n;
+       u8 reset_methods[PCI_NUM_RESET_METHODS] = { 0 };
+
+       if (sysfs_streq(buf, "")) {
+               pdev->reset_methods[0] = 0;
+               pci_warn(pdev, "All device reset methods disabled by user");
+               return count;
+       }
+
+       if (sysfs_streq(buf, "default")) {
+               pci_init_reset_methods(pdev);
+               return count;
+       }
+
+       options = kstrndup(buf, count, GFP_KERNEL);
+       if (!options)
+               return -ENOMEM;
+
+       n = 0;
+       while ((name = strsep(&options, " ")) != NULL) {
+               if (sysfs_streq(name, ""))
+                       continue;
+
+               name = strim(name);
+
+               m = reset_method_lookup(name);
+               if (!m) {
+                       pci_err(pdev, "Invalid reset method '%s'", name);
+                       goto error;
+               }
+
+               if (pci_reset_fn_methods[m].reset_fn(pdev, PCI_RESET_PROBE)) {
+                       pci_err(pdev, "Unsupported reset method '%s'", name);
+                       goto error;
+               }
+
+               if (n == PCI_NUM_RESET_METHODS - 1) {
+                       pci_err(pdev, "Too many reset methods\n");
+                       goto error;
+               }
+
+               reset_methods[n++] = m;
+       }
+
+       reset_methods[n] = 0;
+
+       /* Warn if dev-specific supported but not highest priority */
+       if (pci_reset_fn_methods[1].reset_fn(pdev, PCI_RESET_PROBE) == 0 &&
+           reset_methods[0] != 1)
+               pci_warn(pdev, "Device-specific reset disabled/de-prioritized by user");
+       memcpy(pdev->reset_methods, reset_methods, sizeof(pdev->reset_methods));
+       kfree(options);
+       return count;
+
+error:
+       /* Leave previous methods unchanged */
+       kfree(options);
+       return -EINVAL;
+}
+static DEVICE_ATTR_RW(reset_method);
+
+static struct attribute *pci_dev_reset_method_attrs[] = {
+       &dev_attr_reset_method.attr,
+       NULL,
+};
+
+static umode_t pci_dev_reset_method_attr_is_visible(struct kobject *kobj,
+                                                   struct attribute *a, int n)
+{
+       struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
+
+       if (!pci_reset_supported(pdev))
+               return 0;
+
+       return a->mode;
+}
+
+const struct attribute_group pci_dev_reset_method_attr_group = {
+       .attrs = pci_dev_reset_method_attrs,
+       .is_visible = pci_dev_reset_method_attr_is_visible,
+};
+
 /**
  * __pci_reset_function_locked - reset a PCI device function while holding
  * the @dev mutex lock.
@@ -5143,66 +5288,64 @@ static void pci_dev_restore(struct pci_dev *dev)
  */
 int __pci_reset_function_locked(struct pci_dev *dev)
 {
-       int rc;
+       int i, m, rc = -ENOTTY;
 
        might_sleep();
 
        /*
-        * A reset method returns -ENOTTY if it doesn't support this device
-        * and we should try the next method.
+        * A reset method returns -ENOTTY if it doesn't support this device and
+        * we should try the next method.
         *
-        * If it returns 0 (success), we're finished.  If it returns any
-        * other error, we're also finished: this indicates that further
-        * reset mechanisms might be broken on the device.
+        * If it returns 0 (success), we're finished.  If it returns any other
+        * error, we're also finished: this indicates that further reset
+        * mechanisms might be broken on the device.
         */
-       rc = pci_dev_specific_reset(dev, 0);
-       if (rc != -ENOTTY)
-               return rc;
-       if (pcie_has_flr(dev)) {
-               rc = pcie_flr(dev);
+       for (i = 0; i < PCI_NUM_RESET_METHODS; i++) {
+               m = dev->reset_methods[i];
+               if (!m)
+                       return -ENOTTY;
+
+               rc = pci_reset_fn_methods[m].reset_fn(dev, PCI_RESET_DO_RESET);
+               if (!rc)
+                       return 0;
                if (rc != -ENOTTY)
                        return rc;
        }
-       rc = pci_af_flr(dev, 0);
-       if (rc != -ENOTTY)
-               return rc;
-       rc = pci_pm_reset(dev, 0);
-       if (rc != -ENOTTY)
-               return rc;
-       return pci_reset_bus_function(dev, 0);
+
+       return -ENOTTY;
 }
 EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
 
 /**
- * pci_probe_reset_function - check whether the device can be safely reset
- * @dev: PCI device to reset
+ * pci_init_reset_methods - check whether device can be safely reset
+ * and store supported reset mechanisms.
+ * @dev: PCI device to check for reset mechanisms
  *
  * Some devices allow an individual function to be reset without affecting
- * other functions in the same device.  The PCI device must be responsive
- * to PCI config space in order to use this function.
+ * other functions in the same device.  The PCI device must be in D0-D3hot
+ * state.
  *
- * Returns 0 if the device function can be reset or negative if the
- * device doesn't support resetting a single function.
+ * Stores reset mechanisms supported by device in reset_methods byte array
+ * which is a member of struct pci_dev.
  */
-int pci_probe_reset_function(struct pci_dev *dev)
+void pci_init_reset_methods(struct pci_dev *dev)
 {
-       int rc;
+       int m, i, rc;
+
+       BUILD_BUG_ON(ARRAY_SIZE(pci_reset_fn_methods) != PCI_NUM_RESET_METHODS);
 
        might_sleep();
 
-       rc = pci_dev_specific_reset(dev, 1);
-       if (rc != -ENOTTY)
-               return rc;
-       if (pcie_has_flr(dev))
-               return 0;
-       rc = pci_af_flr(dev, 1);
-       if (rc != -ENOTTY)
-               return rc;
-       rc = pci_pm_reset(dev, 1);
-       if (rc != -ENOTTY)
-               return rc;
+       i = 0;
+       for (m = 1; m < PCI_NUM_RESET_METHODS; m++) {
+               rc = pci_reset_fn_methods[m].reset_fn(dev, PCI_RESET_PROBE);
+               if (!rc)
+                       dev->reset_methods[i++] = m;
+               else if (rc != -ENOTTY)
+                       break;
+       }
 
-       return pci_reset_bus_function(dev, 1);
+       dev->reset_methods[i] = 0;
 }
 
 /**
@@ -5225,7 +5368,7 @@ int pci_reset_function(struct pci_dev *dev)
 {
        int rc;
 
-       if (!dev->reset_fn)
+       if (!pci_reset_supported(dev))
                return -ENOTTY;
 
        pci_dev_lock(dev);
@@ -5261,7 +5404,7 @@ int pci_reset_function_locked(struct pci_dev *dev)
 {
        int rc;
 
-       if (!dev->reset_fn)
+       if (!pci_reset_supported(dev))
                return -ENOTTY;
 
        pci_dev_save_and_disable(dev);
@@ -5284,7 +5427,7 @@ int pci_try_reset_function(struct pci_dev *dev)
 {
        int rc;
 
-       if (!dev->reset_fn)
+       if (!pci_reset_supported(dev))
                return -ENOTTY;
 
        if (!pci_dev_trylock(dev))
@@ -5512,7 +5655,7 @@ static void pci_slot_restore_locked(struct pci_slot *slot)
        }
 }
 
-static int pci_slot_reset(struct pci_slot *slot, int probe)
+static int pci_slot_reset(struct pci_slot *slot, bool probe)
 {
        int rc;
 
@@ -5540,7 +5683,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe)
  */
 int pci_probe_reset_slot(struct pci_slot *slot)
 {
-       return pci_slot_reset(slot, 1);
+       return pci_slot_reset(slot, PCI_RESET_PROBE);
 }
 EXPORT_SYMBOL_GPL(pci_probe_reset_slot);
 
@@ -5563,14 +5706,14 @@ static int __pci_reset_slot(struct pci_slot *slot)
 {
        int rc;
 
-       rc = pci_slot_reset(slot, 1);
+       rc = pci_slot_reset(slot, PCI_RESET_PROBE);
        if (rc)
                return rc;
 
        if (pci_slot_trylock(slot)) {
                pci_slot_save_and_disable_locked(slot);
                might_sleep();
-               rc = pci_reset_hotplug_slot(slot->hotplug, 0);
+               rc = pci_reset_hotplug_slot(slot->hotplug, PCI_RESET_DO_RESET);
                pci_slot_restore_locked(slot);
                pci_slot_unlock(slot);
        } else
@@ -5579,7 +5722,7 @@ static int __pci_reset_slot(struct pci_slot *slot)
        return rc;
 }
 
-static int pci_bus_reset(struct pci_bus *bus, int probe)
+static int pci_bus_reset(struct pci_bus *bus, bool probe)
 {
        int ret;
 
@@ -5625,14 +5768,14 @@ int pci_bus_error_reset(struct pci_dev *bridge)
                        goto bus_reset;
 
        list_for_each_entry(slot, &bus->slots, list)
-               if (pci_slot_reset(slot, 0))
+               if (pci_slot_reset(slot, PCI_RESET_DO_RESET))
                        goto bus_reset;
 
        mutex_unlock(&pci_slot_mutex);
        return 0;
 bus_reset:
        mutex_unlock(&pci_slot_mutex);
-       return pci_bus_reset(bridge->subordinate, 0);
+       return pci_bus_reset(bridge->subordinate, PCI_RESET_DO_RESET);
 }
 
 /**
@@ -5643,7 +5786,7 @@ bus_reset:
  */
 int pci_probe_reset_bus(struct pci_bus *bus)
 {
-       return pci_bus_reset(bus, 1);
+       return pci_bus_reset(bus, PCI_RESET_PROBE);
 }
 EXPORT_SYMBOL_GPL(pci_probe_reset_bus);
 
@@ -5657,7 +5800,7 @@ static int __pci_reset_bus(struct pci_bus *bus)
 {
        int rc;
 
-       rc = pci_bus_reset(bus, 1);
+       rc = pci_bus_reset(bus, PCI_RESET_PROBE);
        if (rc)
                return rc;