return (ctrl & acs_flags) == acs_flags;
}
+/**
+ * pci_std_toggle_acs_sv - toggle ACS source validation feature
+ * @dev - pcie switch/RP
+ * @enable - enable (true) or disable (false) source validation
+ *
+ * Returns : false on failure (if SV capability is not implemented)
+ * previous acs_sv state (true or false)
+ */
+bool pci_std_toggle_acs_sv(struct pci_dev *dev, bool enable)
+{
+ int pos;
+ u16 cap;
+ u16 ctrl;
+ bool retval;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+ if (!pos)
+ return false;
+
+ pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
+
+ if (!(cap & PCI_ACS_SV))
+ return false;
+
+ pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
+
+ retval = !!(ctrl & cap & PCI_ACS_SV);
+ if (enable)
+ ctrl |= (cap & PCI_ACS_SV);
+ else
+ ctrl &= ~(cap & PCI_ACS_SV);
+
+ pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+
+ return retval;
+}
/**
* pci_acs_enabled - test ACS against required flags for a given device
* @pdev: device to test
}
EXPORT_SYMBOL(pci_alloc_dev);
-bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
- int crs_timeout)
+static bool __pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn,
+ u32 *l, int crs_timeout)
{
int delay = 1;
return true;
}
-EXPORT_SYMBOL(pci_bus_read_dev_vendor_id);
+
+bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
+ int crs_timeout)
+{
+ bool found;
+ bool enable = false;
+ bool idt_workaround = (bus->self &&
+ (bus->self->vendor == PCI_VENDOR_ID_IDT));
+ /*
+ * Some IDT switches flag an ACS violation for config reads
+ * even though the PCI spec allows for it (PCIe 3.1, 6.1.12.1)
+ * It flags it because the bus number is not properly set in the
+ * completion. The workaround is to do a dummy write to properly
+ * latch number once the device is ready for config operations
+ */
+
+ if (idt_workaround)
+ enable = pci_std_toggle_acs_sv(bus->self, false);
+
+ found = __pci_bus_read_dev_vendor_id(bus, devfn, l, crs_timeout);
+
+ /*
+ * The fact that we can read the vendor id indicates that the device
+ * is ready for config operations. Do the write as part of the errata
+ * workaround.
+ */
+ if (idt_workaround) {
+ if (found)
+ pci_bus_write_config_word(bus, devfn, PCI_VENDOR_ID, 0);
+ if (enable)
+ pci_std_toggle_acs_sv(bus->self, enable);
+ }
+
+ return found;
+}
+ EXPORT_SYMBOL(pci_bus_read_dev_vendor_id);
/*
* Read the config data for a PCI device, sanity-check it