]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/pci/probe.c
Merge tag 'pci-v4.14-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[mirror_ubuntu-bionic-kernel.git] / drivers / pci / probe.c
index e03f95bd1b599391a5c748df35953dc4fdec12dc..ff94b69738a87a8ec5b77e57624e1412c7ab4916 100644 (file)
@@ -1791,6 +1791,48 @@ int pci_configure_extended_tags(struct pci_dev *dev, void *ign)
        return 0;
 }
 
+/**
+ * pcie_relaxed_ordering_enabled - Probe for PCIe relaxed ordering enable
+ * @dev: PCI device to query
+ *
+ * Returns true if the device has enabled relaxed ordering attribute.
+ */
+bool pcie_relaxed_ordering_enabled(struct pci_dev *dev)
+{
+       u16 v;
+
+       pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &v);
+
+       return !!(v & PCI_EXP_DEVCTL_RELAX_EN);
+}
+EXPORT_SYMBOL(pcie_relaxed_ordering_enabled);
+
+static void pci_configure_relaxed_ordering(struct pci_dev *dev)
+{
+       struct pci_dev *root;
+
+       /* PCI_EXP_DEVICE_RELAX_EN is RsvdP in VFs */
+       if (dev->is_virtfn)
+               return;
+
+       if (!pcie_relaxed_ordering_enabled(dev))
+               return;
+
+       /*
+        * For now, we only deal with Relaxed Ordering issues with Root
+        * Ports. Peer-to-Peer DMA is another can of worms.
+        */
+       root = pci_find_pcie_root_port(dev);
+       if (!root)
+               return;
+
+       if (root->dev_flags & PCI_DEV_FLAGS_NO_RELAXED_ORDERING) {
+               pcie_capability_clear_word(dev, PCI_EXP_DEVCTL,
+                                          PCI_EXP_DEVCTL_RELAX_EN);
+               dev_info(&dev->dev, "Disable Relaxed Ordering because the Root Port didn't support it\n");
+       }
+}
+
 static void pci_configure_device(struct pci_dev *dev)
 {
        struct hotplug_params hpp;
@@ -1798,6 +1840,7 @@ static void pci_configure_device(struct pci_dev *dev)
 
        pci_configure_mps(dev);
        pci_configure_extended_tags(dev, NULL);
+       pci_configure_relaxed_ordering(dev);
 
        memset(&hpp, 0, sizeof(hpp));
        ret = pci_get_hp_params(dev, &hpp);