|
@@ -1762,6 +1762,48 @@ static void pci_configure_extended_tags(struct pci_dev *dev)
|
|
PCI_EXP_DEVCTL_EXT_TAG);
|
|
PCI_EXP_DEVCTL_EXT_TAG);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * 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)
|
|
static void pci_configure_device(struct pci_dev *dev)
|
|
{
|
|
{
|
|
struct hotplug_params hpp;
|
|
struct hotplug_params hpp;
|
|
@@ -1769,6 +1811,7 @@ static void pci_configure_device(struct pci_dev *dev)
|
|
|
|
|
|
pci_configure_mps(dev);
|
|
pci_configure_mps(dev);
|
|
pci_configure_extended_tags(dev);
|
|
pci_configure_extended_tags(dev);
|
|
|
|
+ pci_configure_relaxed_ordering(dev);
|
|
|
|
|
|
memset(&hpp, 0, sizeof(hpp));
|
|
memset(&hpp, 0, sizeof(hpp));
|
|
ret = pci_get_hp_params(dev, &hpp);
|
|
ret = pci_get_hp_params(dev, &hpp);
|