Merge branch 'parisc-5.9-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[linux-2.6-microblaze.git] / drivers / pci / pci.c
index c9338f9..a458c46 100644 (file)
@@ -777,6 +777,133 @@ int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask)
        return 0;
 }
 
+static int pci_acs_enable;
+
+/**
+ * pci_request_acs - ask for ACS to be enabled if supported
+ */
+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 = dev->acs_cap;
+       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 capabilities
+ * @dev: the PCI device
+ */
+static void pci_std_enable_acs(struct pci_dev *dev)
+{
+       int pos;
+       u16 cap;
+       u16 ctrl;
+
+       pos = dev->acs_cap;
+       if (!pos)
+               return;
+
+       pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
+       pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
+
+       /* Source Validation */
+       ctrl |= (cap & PCI_ACS_SV);
+
+       /* P2P Request Redirect */
+       ctrl |= (cap & PCI_ACS_RR);
+
+       /* P2P Completion Redirect */
+       ctrl |= (cap & PCI_ACS_CR);
+
+       /* Upstream Forwarding */
+       ctrl |= (cap & PCI_ACS_UF);
+
+       pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+}
+
+/**
+ * pci_enable_acs - enable ACS if hardware support it
+ * @dev: the PCI device
+ */
+static void pci_enable_acs(struct pci_dev *dev)
+{
+       if (!pci_acs_enable)
+               goto disable_acs_redir;
+
+       if (!pci_dev_specific_enable_acs(dev))
+               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);
+}
+
 /**
  * pci_restore_bars - restore a device's BAR values (e.g. after wake-up)
  * @dev: PCI device to have its BARs restored
@@ -2046,6 +2173,14 @@ int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
 }
 EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
 
+void pcie_clear_device_status(struct pci_dev *dev)
+{
+       u16 sta;
+
+       pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
+       pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
+}
+
 /**
  * pcie_clear_root_pme_status - Clear root port PME interrupt status.
  * @dev: PCIe root port or event collector.
@@ -3230,139 +3365,12 @@ void pci_configure_ari(struct pci_dev *dev)
        }
 }
 
-static int pci_acs_enable;
-
-/**
- * pci_request_acs - ask for ACS to be enabled if supported
- */
-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 capabilities
- * @dev: the PCI device
- */
-static void pci_std_enable_acs(struct pci_dev *dev)
-{
-       int pos;
-       u16 cap;
-       u16 ctrl;
-
-       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
-       if (!pos)
-               return;
-
-       pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
-       pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
-
-       /* Source Validation */
-       ctrl |= (cap & PCI_ACS_SV);
-
-       /* P2P Request Redirect */
-       ctrl |= (cap & PCI_ACS_RR);
-
-       /* P2P Completion Redirect */
-       ctrl |= (cap & PCI_ACS_CR);
-
-       /* Upstream Forwarding */
-       ctrl |= (cap & PCI_ACS_UF);
-
-       pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
-}
-
-/**
- * pci_enable_acs - enable ACS if hardware support it
- * @dev: the PCI device
- */
-void pci_enable_acs(struct pci_dev *dev)
-{
-       if (!pci_acs_enable)
-               goto disable_acs_redir;
-
-       if (!pci_dev_specific_enable_acs(dev))
-               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)
 {
        int pos;
        u16 cap, ctrl;
 
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+       pos = pdev->acs_cap;
        if (!pos)
                return false;
 
@@ -3487,6 +3495,18 @@ bool pci_acs_path_enabled(struct pci_dev *start,
        return true;
 }
 
+/**
+ * pci_acs_init - Initialize ACS if hardware supports it
+ * @dev: the PCI device
+ */
+void pci_acs_init(struct pci_dev *dev)
+{
+       dev->acs_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+
+       if (dev->acs_cap)
+               pci_enable_acs(dev);
+}
+
 /**
  * pci_rebar_find_pos - find position of resize ctrl reg for BAR
  * @pdev: PCI device
@@ -5676,6 +5696,7 @@ EXPORT_SYMBOL(pcie_get_readrq);
 int pcie_set_readrq(struct pci_dev *dev, int rq)
 {
        u16 v;
+       int ret;
 
        if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
                return -EINVAL;
@@ -5694,8 +5715,10 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
 
        v = (ffs(rq) - 8) << 12;
 
-       return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
+       ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
                                                  PCI_EXP_DEVCTL_READRQ, v);
+
+       return pcibios_err_to_errno(ret);
 }
 EXPORT_SYMBOL(pcie_set_readrq);
 
@@ -5726,6 +5749,7 @@ EXPORT_SYMBOL(pcie_get_mps);
 int pcie_set_mps(struct pci_dev *dev, int mps)
 {
        u16 v;
+       int ret;
 
        if (mps < 128 || mps > 4096 || !is_power_of_2(mps))
                return -EINVAL;
@@ -5735,8 +5759,10 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
                return -EINVAL;
        v <<= 5;
 
-       return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
+       ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
                                                  PCI_EXP_DEVCTL_PAYLOAD, v);
+
+       return pcibios_err_to_errno(ret);
 }
 EXPORT_SYMBOL(pcie_set_mps);