aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2014-02-03 16:27:33 -0500
committerBjorn Helgaas <bhelgaas@google.com>2014-02-11 15:49:56 -0500
commit2c74424470a0f98df8d6540642aff96d1a0b94b3 (patch)
tree61f24a066645ddd7884d8545b579e0754c2763ce
parent38dbfb59d1175ef458d006556061adeaa8751b72 (diff)
PCI: Add device-specific PCI ACS enable
Some devices support PCI ACS-like features, but don't report it using the standard PCIe capabilities. We already provide hooks for device-specific testing of ACS, but not for device-specific enabling of ACS. This provides that setup hook. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/pci/pci.c26
-rw-r--r--drivers/pci/quirks.c25
-rw-r--r--include/linux/pci.h2
3 files changed, 47 insertions, 6 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1febe90831b4..b89502ff3139 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2180,21 +2180,18 @@ void pci_request_acs(void)
2180} 2180}
2181 2181
2182/** 2182/**
2183 * pci_enable_acs - enable ACS if hardware support it 2183 * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
2184 * @dev: the PCI device 2184 * @dev: the PCI device
2185 */ 2185 */
2186void pci_enable_acs(struct pci_dev *dev) 2186static int pci_std_enable_acs(struct pci_dev *dev)
2187{ 2187{
2188 int pos; 2188 int pos;
2189 u16 cap; 2189 u16 cap;
2190 u16 ctrl; 2190 u16 ctrl;
2191 2191
2192 if (!pci_acs_enable)
2193 return;
2194
2195 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS); 2192 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
2196 if (!pos) 2193 if (!pos)
2197 return; 2194 return -ENODEV;
2198 2195
2199 pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap); 2196 pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
2200 pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl); 2197 pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
@@ -2212,6 +2209,23 @@ void pci_enable_acs(struct pci_dev *dev)
2212 ctrl |= (cap & PCI_ACS_UF); 2209 ctrl |= (cap & PCI_ACS_UF);
2213 2210
2214 pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl); 2211 pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
2212
2213 return 0;
2214}
2215
2216/**
2217 * pci_enable_acs - enable ACS if hardware support it
2218 * @dev: the PCI device
2219 */
2220void pci_enable_acs(struct pci_dev *dev)
2221{
2222 if (!pci_acs_enable)
2223 return;
2224
2225 if (!pci_std_enable_acs(dev))
2226 return;
2227
2228 pci_dev_specific_enable_acs(dev);
2215} 2229}
2216 2230
2217static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) 2231static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 5cb726c193de..f681fb08f5e4 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3461,3 +3461,28 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
3461 3461
3462 return -ENOTTY; 3462 return -ENOTTY;
3463} 3463}
3464
3465static const struct pci_dev_enable_acs {
3466 u16 vendor;
3467 u16 device;
3468 int (*enable_acs)(struct pci_dev *dev);
3469} pci_dev_enable_acs[] = {
3470 { 0 }
3471};
3472
3473void pci_dev_specific_enable_acs(struct pci_dev *dev)
3474{
3475 const struct pci_dev_enable_acs *i;
3476 int ret;
3477
3478 for (i = pci_dev_enable_acs; i->enable_acs; i++) {
3479 if ((i->vendor == dev->vendor ||
3480 i->vendor == (u16)PCI_ANY_ID) &&
3481 (i->device == dev->device ||
3482 i->device == (u16)PCI_ANY_ID)) {
3483 ret = i->enable_acs(dev);
3484 if (ret >= 0)
3485 return;
3486 }
3487 }
3488}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index fb57c892b214..0f76d0f66365 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1510,6 +1510,7 @@ enum pci_fixup_pass {
1510void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); 1510void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
1511struct pci_dev *pci_get_dma_source(struct pci_dev *dev); 1511struct pci_dev *pci_get_dma_source(struct pci_dev *dev);
1512int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); 1512int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
1513void pci_dev_specific_enable_acs(struct pci_dev *dev);
1513#else 1514#else
1514static inline void pci_fixup_device(enum pci_fixup_pass pass, 1515static inline void pci_fixup_device(enum pci_fixup_pass pass,
1515 struct pci_dev *dev) { } 1516 struct pci_dev *dev) { }
@@ -1522,6 +1523,7 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev,
1522{ 1523{
1523 return -ENOTTY; 1524 return -ENOTTY;
1524} 1525}
1526static inline void pci_dev_specific_enable_acs(struct pci_dev *dev) { }
1525#endif 1527#endif
1526 1528
1527void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); 1529void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);