* [PATCH v3 00/11] PCI: Fix ATS deadlock
@ 2015-08-11 15:50 Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 01/11] iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth Bjorn Helgaas
` (11 more replies)
0 siblings, 12 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:50 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
Gregor reported a deadlock [1] when enabling a VF that supports ATS.
This series is intended to fix that. The second patch should be enough to
fix the deadlock; the rest are simplification and cleanup.
These are based on v4.2-rc2.
[1] http://permalink.gmane.org/gmane.linux.kernel.iommu/9433
Changes between v2 and v3:
- Initialize info->ats.enabled, qdep in intel-iommu.c (Yinghai)
- Use "u8 enabled:1", not "int enabled:1" in intel-iommu.c state
- WARN_ON() if enabling ATS when already enabled (Joerg)
- Return -EBUSY, not -EINVAL if enabling ATS when already enabled
- Added Reviewed-by from Joerg
Changes between v1 and v2:
- Remove use of pci_ats_enabled() (intel-iommu.c)
- Call pci_ats_queue_depth() only once per device and cache result
(intel-iommu.c)
- Remove pci_ats_enabled() interface
- Stop caching queue depth in pci_dev to save space
- Add PF refcount of how many associated VFs have ATS enabled
- Add comment that ATS must be enabled on PF before on VFs
- Require ATS to be disabled on all VFs and PF before changing STU
---
Bjorn Helgaas (11):
iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth
PCI: Allocate ATS struct during enumeration
PCI: Embed ATS info directly into struct pci_dev
PCI: Reduce size of ATS structure elements
PCI: Rationalize pci_ats_queue_depth() error checking
PCI: Inline the ATS setup code into pci_ats_init()
PCI: Use pci_physfn() rather than looking up physfn by hand
PCI: Clean up ATS error handling
PCI: Move ATS declarations to linux/pci.h so they're all together
PCI: Stop caching ATS Invalidate Queue Depth
PCI: Remove pci_ats_enabled()
drivers/iommu/intel-iommu.c | 28 ++++++---
drivers/pci/ats.c | 132 +++++++++++++++----------------------------
drivers/pci/probe.c | 3 +
include/linux/pci-ats.h | 49 ----------------
include/linux/pci.h | 18 ++++++
5 files changed, 85 insertions(+), 145 deletions(-)
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 01/11] iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
@ 2015-08-11 15:51 ` Bjorn Helgaas
2015-08-13 7:53 ` Joerg Roedel
2015-08-11 15:51 ` [PATCH v3 02/11] PCI: Allocate ATS struct during enumeration Bjorn Helgaas
` (10 subsequent siblings)
11 siblings, 1 reply; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:51 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
We check the ATS state (enabled/disabled) and fetch the PCI ATS Invalidate
Queue Depth in performance-sensitive paths. It's easy to cache these,
which removes dependencies on PCI.
Remember the ATS enabled state. When enabling, read the queue depth once
and cache it in the device_domain_info struct. This is similar to what
amd_iommu.c does.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
---
drivers/iommu/intel-iommu.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index a98a7b2..c22a549 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -408,6 +408,10 @@ struct device_domain_info {
struct list_head global; /* link to global list */
u8 bus; /* PCI bus number */
u8 devfn; /* PCI devfn number */
+ struct {
+ u8 enabled:1;
+ u8 qdep;
+ } ats; /* ATS state */
struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
struct intel_iommu *iommu; /* IOMMU used by this device */
struct dmar_domain *domain; /* pointer to domain */
@@ -1391,19 +1395,26 @@ iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu,
static void iommu_enable_dev_iotlb(struct device_domain_info *info)
{
+ struct pci_dev *pdev;
+
if (!info || !dev_is_pci(info->dev))
return;
- pci_enable_ats(to_pci_dev(info->dev), VTD_PAGE_SHIFT);
+ pdev = to_pci_dev(info->dev);
+ if (pci_enable_ats(pdev, VTD_PAGE_SHIFT))
+ return;
+
+ info->ats.enabled = 1;
+ info->ats.qdep = pci_ats_queue_depth(pdev);
}
static void iommu_disable_dev_iotlb(struct device_domain_info *info)
{
- if (!info->dev || !dev_is_pci(info->dev) ||
- !pci_ats_enabled(to_pci_dev(info->dev)))
+ if (!info->ats.enabled)
return;
pci_disable_ats(to_pci_dev(info->dev));
+ info->ats.enabled = 0;
}
static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
@@ -1415,16 +1426,11 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
spin_lock_irqsave(&device_domain_lock, flags);
list_for_each_entry(info, &domain->devices, link) {
- struct pci_dev *pdev;
- if (!info->dev || !dev_is_pci(info->dev))
- continue;
-
- pdev = to_pci_dev(info->dev);
- if (!pci_ats_enabled(pdev))
+ if (!info->ats.enabled)
continue;
sid = info->bus << 8 | info->devfn;
- qdep = pci_ats_queue_depth(pdev);
+ qdep = info->ats.qdep;
qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask);
}
spin_unlock_irqrestore(&device_domain_lock, flags);
@@ -2272,6 +2278,8 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu,
info->bus = bus;
info->devfn = devfn;
+ info->ats.enabled = 0;
+ info->ats.qdep = 0;
info->dev = dev;
info->domain = domain;
info->iommu = iommu;
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 02/11] PCI: Allocate ATS struct during enumeration
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 01/11] iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth Bjorn Helgaas
@ 2015-08-11 15:51 ` Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 03/11] PCI: Embed ATS info directly into struct pci_dev Bjorn Helgaas
` (9 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:51 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
Previously, we allocated pci_ats structures when an IOMMU driver called
pci_enable_ats(). An SR-IOV VF shares the STU setting with its PF, so when
enabling ATS on the VF, we allocated a pci_ats struct for the PF if it
didn't already have one. We held the sriov->lock to serialize threads
concurrently enabling ATS on several VFS so only one would allocate the PF
pci_ats.
Gregor reported a deadlock here:
pci_enable_sriov
sriov_enable
virtfn_add
mutex_lock(dev->sriov->lock) # acquire sriov->lock
pci_device_add
device_add
BUS_NOTIFY_ADD_DEVICE notifier chain
iommu_bus_notifier
amd_iommu_add_device # iommu_ops.add_device
init_iommu_group
iommu_group_get_for_dev
iommu_group_add_device
__iommu_attach_device
amd_iommu_attach_device # iommu_ops.attach_device
attach_device
pci_enable_ats
mutex_lock(dev->sriov->lock) # deadlock
There's no reason to delay allocating the pci_ats struct, and if we
allocate it for each device at enumeration-time, there's no need for
locking in pci_enable_ats().
Allocate pci_ats struct during enumeration, when we initialize other
capabilities.
Note that this implementation requires ATS to be enabled on the PF first,
before on any of the VFs because the PF controls the STU for all the VFs.
Link: http://permalink.gmane.org/gmane.linux.kernel.iommu/9433
Reported-by: Gregor Dick <gdick@solarflare.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Joerg Roedel <jroedel@suse.de>
---
drivers/pci/ats.c | 98 ++++++++++++++++++++---------------------------
drivers/pci/probe.c | 3 +
drivers/pci/remove.c | 1
include/linux/pci-ats.h | 2 -
include/linux/pci.h | 9 ++++
5 files changed, 56 insertions(+), 57 deletions(-)
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index a8099d4..2026f53 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -17,7 +17,7 @@
#include "pci.h"
-static int ats_alloc_one(struct pci_dev *dev, int ps)
+static void ats_alloc_one(struct pci_dev *dev)
{
int pos;
u16 cap;
@@ -25,20 +25,19 @@ static int ats_alloc_one(struct pci_dev *dev, int ps)
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
if (!pos)
- return -ENODEV;
+ return;
ats = kzalloc(sizeof(*ats), GFP_KERNEL);
- if (!ats)
- return -ENOMEM;
+ if (!ats) {
+ dev_warn(&dev->dev, "can't allocate space for ATS state\n");
+ return;
+ }
ats->pos = pos;
- ats->stu = ps;
pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
PCI_ATS_MAX_QDEP;
dev->ats = ats;
-
- return 0;
}
static void ats_free_one(struct pci_dev *dev)
@@ -47,6 +46,16 @@ static void ats_free_one(struct pci_dev *dev)
dev->ats = NULL;
}
+void pci_ats_init(struct pci_dev *dev)
+{
+ ats_alloc_one(dev);
+}
+
+void pci_ats_free(struct pci_dev *dev)
+{
+ ats_free_one(dev);
+}
+
/**
* pci_enable_ats - enable the ATS capability
* @dev: the PCI device
@@ -56,43 +65,35 @@ static void ats_free_one(struct pci_dev *dev)
*/
int pci_enable_ats(struct pci_dev *dev, int ps)
{
- int rc;
u16 ctrl;
BUG_ON(dev->ats && dev->ats->is_enabled);
+ if (!dev->ats)
+ return -EINVAL;
+
if (ps < PCI_ATS_MIN_STU)
return -EINVAL;
- if (dev->is_physfn || dev->is_virtfn) {
- struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
+ /*
+ * Note that enabling ATS on a VF fails unless it's already enabled
+ * with the same STU on the PF.
+ */
+ ctrl = PCI_ATS_CTRL_ENABLE;
+ if (dev->is_virtfn) {
+ struct pci_dev *pdev = dev->physfn;
- mutex_lock(&pdev->sriov->lock);
- if (pdev->ats)
- rc = pdev->ats->stu == ps ? 0 : -EINVAL;
- else
- rc = ats_alloc_one(pdev, ps);
+ if (pdev->ats->stu != ps)
+ return -EINVAL;
- if (!rc)
- pdev->ats->ref_cnt++;
- mutex_unlock(&pdev->sriov->lock);
- if (rc)
- return rc;
- }
-
- if (!dev->is_physfn) {
- rc = ats_alloc_one(dev, ps);
- if (rc)
- return rc;
+ atomic_inc(&pdev->ats->ref_cnt); /* count enabled VFs */
+ } else {
+ dev->ats->stu = ps;
+ ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);
}
-
- ctrl = PCI_ATS_CTRL_ENABLE;
- if (!dev->is_virtfn)
- ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
dev->ats->is_enabled = 1;
-
return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_ats);
@@ -107,24 +108,20 @@ void pci_disable_ats(struct pci_dev *dev)
BUG_ON(!dev->ats || !dev->ats->is_enabled);
+ if (atomic_read(&dev->ats->ref_cnt))
+ return; /* VFs still enabled */
+
+ if (dev->is_virtfn) {
+ struct pci_dev *pdev = dev->physfn;
+
+ atomic_dec(&pdev->ats->ref_cnt);
+ }
+
pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
ctrl &= ~PCI_ATS_CTRL_ENABLE;
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
dev->ats->is_enabled = 0;
-
- if (dev->is_physfn || dev->is_virtfn) {
- struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
-
- mutex_lock(&pdev->sriov->lock);
- pdev->ats->ref_cnt--;
- if (!pdev->ats->ref_cnt)
- ats_free_one(pdev);
- mutex_unlock(&pdev->sriov->lock);
- }
-
- if (!dev->is_physfn)
- ats_free_one(dev);
}
EXPORT_SYMBOL_GPL(pci_disable_ats);
@@ -140,7 +137,6 @@ void pci_restore_ats_state(struct pci_dev *dev)
ctrl = PCI_ATS_CTRL_ENABLE;
if (!dev->is_virtfn)
ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);
-
pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
}
EXPORT_SYMBOL_GPL(pci_restore_ats_state);
@@ -159,23 +155,13 @@ EXPORT_SYMBOL_GPL(pci_restore_ats_state);
*/
int pci_ats_queue_depth(struct pci_dev *dev)
{
- int pos;
- u16 cap;
-
if (dev->is_virtfn)
return 0;
if (dev->ats)
return dev->ats->qdep;
- pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
- if (!pos)
- return -ENODEV;
-
- pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
-
- return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
- PCI_ATS_MAX_QDEP;
+ return -ENODEV;
}
EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cefd636..c206398 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1540,6 +1540,9 @@ static void pci_init_capabilities(struct pci_dev *dev)
/* Single Root I/O Virtualization */
pci_iov_init(dev);
+ /* Address Translation Services */
+ pci_ats_init(dev);
+
/* Enable ACS P2P upstream forwarding */
pci_enable_acs(dev);
}
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 8a280e9..27617b8 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -26,6 +26,7 @@ static void pci_stop_dev(struct pci_dev *dev)
dev->is_added = 0;
}
+ pci_ats_free(dev);
if (dev->bus->self)
pcie_aspm_exit_link_state(dev);
}
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index 7203178..e2dcc2f 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -8,7 +8,7 @@ struct pci_ats {
int pos; /* capability position */
int stu; /* Smallest Translation Unit */
int qdep; /* Invalidate Queue Depth */
- int ref_cnt; /* Physical Function reference count */
+ atomic_t ref_cnt; /* number of VFs with ATS enabled */
unsigned int is_enabled:1; /* Enable bit is set */
};
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 8a0321a..1817819 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1294,6 +1294,15 @@ int ht_create_irq(struct pci_dev *dev, int idx);
void ht_destroy_irq(unsigned int irq);
#endif /* CONFIG_HT_IRQ */
+#ifdef CONFIG_PCI_ATS
+/* Address Translation Service */
+void pci_ats_init(struct pci_dev *dev);
+void pci_ats_free(struct pci_dev *dev);
+#else
+static inline void pci_ats_init(struct pci_dev *dev) { }
+static inline void pci_ats_free(struct pci_dev *dev) { }
+#endif
+
void pci_cfg_access_lock(struct pci_dev *dev);
bool pci_cfg_access_trylock(struct pci_dev *dev);
void pci_cfg_access_unlock(struct pci_dev *dev);
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 03/11] PCI: Embed ATS info directly into struct pci_dev
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 01/11] iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 02/11] PCI: Allocate ATS struct during enumeration Bjorn Helgaas
@ 2015-08-11 15:51 ` Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 04/11] PCI: Reduce size of ATS structure elements Bjorn Helgaas
` (8 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:51 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
The pci_ats struct is small and will get smaller, so I don't think it's
worth allocating it separately from the pci_dev struct.
Embed the ATS fields directly into struct pci_dev.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Joerg Roedel <jroedel@suse.de>
---
drivers/pci/ats.c | 61 ++++++++++++++++-------------------------------
drivers/pci/remove.c | 1 -
include/linux/pci-ats.h | 10 +-------
include/linux/pci.h | 8 ++++--
4 files changed, 27 insertions(+), 53 deletions(-)
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 2026f53..690ae6e 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -21,29 +21,15 @@ static void ats_alloc_one(struct pci_dev *dev)
{
int pos;
u16 cap;
- struct pci_ats *ats;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
if (!pos)
return;
- ats = kzalloc(sizeof(*ats), GFP_KERNEL);
- if (!ats) {
- dev_warn(&dev->dev, "can't allocate space for ATS state\n");
- return;
- }
-
- ats->pos = pos;
- pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
- ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
+ dev->ats_cap = pos;
+ pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap);
+ dev->ats_qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
PCI_ATS_MAX_QDEP;
- dev->ats = ats;
-}
-
-static void ats_free_one(struct pci_dev *dev)
-{
- kfree(dev->ats);
- dev->ats = NULL;
}
void pci_ats_init(struct pci_dev *dev)
@@ -51,11 +37,6 @@ void pci_ats_init(struct pci_dev *dev)
ats_alloc_one(dev);
}
-void pci_ats_free(struct pci_dev *dev)
-{
- ats_free_one(dev);
-}
-
/**
* pci_enable_ats - enable the ATS capability
* @dev: the PCI device
@@ -67,9 +48,9 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
{
u16 ctrl;
- BUG_ON(dev->ats && dev->ats->is_enabled);
+ BUG_ON(dev->ats_cap && dev->ats_enabled);
- if (!dev->ats)
+ if (!dev->ats_cap)
return -EINVAL;
if (ps < PCI_ATS_MIN_STU)
@@ -83,17 +64,17 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
if (dev->is_virtfn) {
struct pci_dev *pdev = dev->physfn;
- if (pdev->ats->stu != ps)
+ if (pdev->ats_stu != ps)
return -EINVAL;
- atomic_inc(&pdev->ats->ref_cnt); /* count enabled VFs */
+ atomic_inc(&pdev->ats_ref_cnt); /* count enabled VFs */
} else {
- dev->ats->stu = ps;
- ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);
+ dev->ats_stu = ps;
+ ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
}
- pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
+ pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
- dev->ats->is_enabled = 1;
+ dev->ats_enabled = 1;
return 0;
}
EXPORT_SYMBOL_GPL(pci_enable_ats);
@@ -106,22 +87,22 @@ void pci_disable_ats(struct pci_dev *dev)
{
u16 ctrl;
- BUG_ON(!dev->ats || !dev->ats->is_enabled);
+ BUG_ON(!dev->ats_cap || !dev->ats_enabled);
- if (atomic_read(&dev->ats->ref_cnt))
+ if (atomic_read(&dev->ats_ref_cnt))
return; /* VFs still enabled */
if (dev->is_virtfn) {
struct pci_dev *pdev = dev->physfn;
- atomic_dec(&pdev->ats->ref_cnt);
+ atomic_dec(&pdev->ats_ref_cnt);
}
- pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
+ pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, &ctrl);
ctrl &= ~PCI_ATS_CTRL_ENABLE;
- pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
+ pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
- dev->ats->is_enabled = 0;
+ dev->ats_enabled = 0;
}
EXPORT_SYMBOL_GPL(pci_disable_ats);
@@ -136,8 +117,8 @@ void pci_restore_ats_state(struct pci_dev *dev)
ctrl = PCI_ATS_CTRL_ENABLE;
if (!dev->is_virtfn)
- ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);
- pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
+ ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
+ pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
}
EXPORT_SYMBOL_GPL(pci_restore_ats_state);
@@ -158,8 +139,8 @@ int pci_ats_queue_depth(struct pci_dev *dev)
if (dev->is_virtfn)
return 0;
- if (dev->ats)
- return dev->ats->qdep;
+ if (dev->ats_cap)
+ return dev->ats_qdep;
return -ENODEV;
}
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 27617b8..8a280e9 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -26,7 +26,6 @@ static void pci_stop_dev(struct pci_dev *dev)
dev->is_added = 0;
}
- pci_ats_free(dev);
if (dev->bus->self)
pcie_aspm_exit_link_state(dev);
}
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index e2dcc2f..5d81d47 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -4,14 +4,6 @@
#include <linux/pci.h>
/* Address Translation Service */
-struct pci_ats {
- int pos; /* capability position */
- int stu; /* Smallest Translation Unit */
- int qdep; /* Invalidate Queue Depth */
- atomic_t ref_cnt; /* number of VFs with ATS enabled */
- unsigned int is_enabled:1; /* Enable bit is set */
-};
-
#ifdef CONFIG_PCI_ATS
int pci_enable_ats(struct pci_dev *dev, int ps);
@@ -26,7 +18,7 @@ int pci_ats_queue_depth(struct pci_dev *dev);
*/
static inline int pci_ats_enabled(struct pci_dev *dev)
{
- return dev->ats && dev->ats->is_enabled;
+ return dev->ats_cap && dev->ats_enabled;
}
#else /* CONFIG_PCI_ATS */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1817819..8bc16b5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -343,6 +343,7 @@ struct pci_dev {
unsigned int msi_enabled:1;
unsigned int msix_enabled:1;
unsigned int ari_enabled:1; /* ARI forwarding */
+ unsigned int ats_enabled:1; /* Address Translation Service */
unsigned int is_managed:1;
unsigned int needs_freset:1; /* Dev requires fundamental reset */
unsigned int state_saved:1;
@@ -375,7 +376,10 @@ struct pci_dev {
struct pci_sriov *sriov; /* SR-IOV capability related */
struct pci_dev *physfn; /* the PF this VF is associated with */
};
- struct pci_ats *ats; /* Address Translation Service */
+ int ats_cap; /* ATS Capability offset */
+ int ats_stu; /* ATS Smallest Translation Unit */
+ int ats_qdep; /* ATS Invalidate Queue Depth */
+ atomic_t ats_ref_cnt; /* number of VFs with ATS enabled */
#endif
phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
size_t romlen; /* Length of ROM if it's not from the BAR */
@@ -1297,10 +1301,8 @@ void ht_destroy_irq(unsigned int irq);
#ifdef CONFIG_PCI_ATS
/* Address Translation Service */
void pci_ats_init(struct pci_dev *dev);
-void pci_ats_free(struct pci_dev *dev);
#else
static inline void pci_ats_init(struct pci_dev *dev) { }
-static inline void pci_ats_free(struct pci_dev *dev) { }
#endif
void pci_cfg_access_lock(struct pci_dev *dev);
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 04/11] PCI: Reduce size of ATS structure elements
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
` (2 preceding siblings ...)
2015-08-11 15:51 ` [PATCH v3 03/11] PCI: Embed ATS info directly into struct pci_dev Bjorn Helgaas
@ 2015-08-11 15:51 ` Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 05/11] PCI: Rationalize pci_ats_queue_depth() error checking Bjorn Helgaas
` (7 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:51 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
The extended capabilities list is linked with 12-bit pointers, and the ATS
Smallest Translation Unit and Invalidate Queue Depth fields are both 5
bits.
Use u16 and u8 to hold the extended capability address and the stu and qdep
values. No functional change.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Joerg Roedel <jroedel@suse.de>
---
include/linux/pci.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 8bc16b5..238b77e 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -376,9 +376,9 @@ struct pci_dev {
struct pci_sriov *sriov; /* SR-IOV capability related */
struct pci_dev *physfn; /* the PF this VF is associated with */
};
- int ats_cap; /* ATS Capability offset */
- int ats_stu; /* ATS Smallest Translation Unit */
- int ats_qdep; /* ATS Invalidate Queue Depth */
+ u16 ats_cap; /* ATS Capability offset */
+ u8 ats_stu; /* ATS Smallest Translation Unit */
+ u8 ats_qdep; /* ATS Invalidate Queue Depth */
atomic_t ats_ref_cnt; /* number of VFs with ATS enabled */
#endif
phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 05/11] PCI: Rationalize pci_ats_queue_depth() error checking
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
` (3 preceding siblings ...)
2015-08-11 15:51 ` [PATCH v3 04/11] PCI: Reduce size of ATS structure elements Bjorn Helgaas
@ 2015-08-11 15:51 ` Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 06/11] PCI: Inline the ATS setup code into pci_ats_init() Bjorn Helgaas
` (6 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:51 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
We previously returned -ENODEV for devices that don't support ATS (except
that we always returned 0 for VFs, whether or not they support ATS).
For consistency, always return -EINVAL (not -ENODEV) if the device doesn't
support ATS. Return zero for VFs that support ATS.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Joerg Roedel <jroedel@suse.de>
---
drivers/pci/ats.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 690ae6e..9a98b3a 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -136,13 +136,13 @@ EXPORT_SYMBOL_GPL(pci_restore_ats_state);
*/
int pci_ats_queue_depth(struct pci_dev *dev)
{
+ if (!dev->ats_cap)
+ return -EINVAL;
+
if (dev->is_virtfn)
return 0;
- if (dev->ats_cap)
- return dev->ats_qdep;
-
- return -ENODEV;
+ return dev->ats_qdep;
}
EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 06/11] PCI: Inline the ATS setup code into pci_ats_init()
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
` (4 preceding siblings ...)
2015-08-11 15:51 ` [PATCH v3 05/11] PCI: Rationalize pci_ats_queue_depth() error checking Bjorn Helgaas
@ 2015-08-11 15:51 ` Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 07/11] PCI: Use pci_physfn() rather than looking up physfn by hand Bjorn Helgaas
` (5 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:51 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
The ATS setup code in ats_alloc_one() is only used by pci_ats_init(), so
inline it there. No functional change.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Joerg Roedel <jroedel@suse.de>
---
drivers/pci/ats.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 9a98b3a..95905f3 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -17,7 +17,7 @@
#include "pci.h"
-static void ats_alloc_one(struct pci_dev *dev)
+void pci_ats_init(struct pci_dev *dev)
{
int pos;
u16 cap;
@@ -32,11 +32,6 @@ static void ats_alloc_one(struct pci_dev *dev)
PCI_ATS_MAX_QDEP;
}
-void pci_ats_init(struct pci_dev *dev)
-{
- ats_alloc_one(dev);
-}
-
/**
* pci_enable_ats - enable the ATS capability
* @dev: the PCI device
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 07/11] PCI: Use pci_physfn() rather than looking up physfn by hand
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
` (5 preceding siblings ...)
2015-08-11 15:51 ` [PATCH v3 06/11] PCI: Inline the ATS setup code into pci_ats_init() Bjorn Helgaas
@ 2015-08-11 15:51 ` Bjorn Helgaas
2015-08-11 15:52 ` [PATCH v3 08/11] PCI: Clean up ATS error handling Bjorn Helgaas
` (4 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:51 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
Use the pci_physfn() helper rather than looking up physfn by hand.
No functional change.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Joerg Roedel <jroedel@suse.de>
---
drivers/pci/ats.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 95905f3..0b5b0ed 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -42,6 +42,7 @@ void pci_ats_init(struct pci_dev *dev)
int pci_enable_ats(struct pci_dev *dev, int ps)
{
u16 ctrl;
+ struct pci_dev *pdev;
BUG_ON(dev->ats_cap && dev->ats_enabled);
@@ -57,8 +58,7 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
*/
ctrl = PCI_ATS_CTRL_ENABLE;
if (dev->is_virtfn) {
- struct pci_dev *pdev = dev->physfn;
-
+ pdev = pci_physfn(dev);
if (pdev->ats_stu != ps)
return -EINVAL;
@@ -80,6 +80,7 @@ EXPORT_SYMBOL_GPL(pci_enable_ats);
*/
void pci_disable_ats(struct pci_dev *dev)
{
+ struct pci_dev *pdev;
u16 ctrl;
BUG_ON(!dev->ats_cap || !dev->ats_enabled);
@@ -88,8 +89,7 @@ void pci_disable_ats(struct pci_dev *dev)
return; /* VFs still enabled */
if (dev->is_virtfn) {
- struct pci_dev *pdev = dev->physfn;
-
+ pdev = pci_physfn(dev);
atomic_dec(&pdev->ats_ref_cnt);
}
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 08/11] PCI: Clean up ATS error handling
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
` (6 preceding siblings ...)
2015-08-11 15:51 ` [PATCH v3 07/11] PCI: Use pci_physfn() rather than looking up physfn by hand Bjorn Helgaas
@ 2015-08-11 15:52 ` Bjorn Helgaas
2015-08-13 7:57 ` Joerg Roedel
2015-08-11 15:52 ` [PATCH v3 09/11] PCI: Move ATS declarations to linux/pci.h so they're all together Bjorn Helgaas
` (3 subsequent siblings)
11 siblings, 1 reply; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:52 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
There's no need to BUG() if we enable ATS when it's already enabled. We
don't need to BUG() when disabling ATS on a device that doesn't support ATS
or if it's already disabled. If ATS is enabled, certainly we found an ATS
capability in the past, so it should still be there now.
Clean up these error paths.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
---
drivers/pci/ats.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 0b5b0ed..0f05274 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -44,11 +44,13 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
u16 ctrl;
struct pci_dev *pdev;
- BUG_ON(dev->ats_cap && dev->ats_enabled);
-
if (!dev->ats_cap)
return -EINVAL;
+ WARN_ON(pci_ats_enabled(dev));
+ if (pci_ats_enabled(dev))
+ return -EBUSY;
+
if (ps < PCI_ATS_MIN_STU)
return -EINVAL;
@@ -83,7 +85,8 @@ void pci_disable_ats(struct pci_dev *dev)
struct pci_dev *pdev;
u16 ctrl;
- BUG_ON(!dev->ats_cap || !dev->ats_enabled);
+ if (!pci_ats_enabled(dev))
+ return;
if (atomic_read(&dev->ats_ref_cnt))
return; /* VFs still enabled */
@@ -107,8 +110,6 @@ void pci_restore_ats_state(struct pci_dev *dev)
if (!pci_ats_enabled(dev))
return;
- if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS))
- BUG();
ctrl = PCI_ATS_CTRL_ENABLE;
if (!dev->is_virtfn)
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 09/11] PCI: Move ATS declarations to linux/pci.h so they're all together
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
` (7 preceding siblings ...)
2015-08-11 15:52 ` [PATCH v3 08/11] PCI: Clean up ATS error handling Bjorn Helgaas
@ 2015-08-11 15:52 ` Bjorn Helgaas
2015-08-11 15:52 ` [PATCH v3 10/11] PCI: Stop caching ATS Invalidate Queue Depth Bjorn Helgaas
` (2 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:52 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
Move ATS declarations to linux/pci.h so they're all in one place.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Joerg Roedel <jroedel@suse.de>
---
include/linux/pci-ats.h | 41 -----------------------------------------
include/linux/pci.h | 10 +++++++++-
2 files changed, 9 insertions(+), 42 deletions(-)
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index 5d81d47..57e0b82 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -3,47 +3,6 @@
#include <linux/pci.h>
-/* Address Translation Service */
-#ifdef CONFIG_PCI_ATS
-
-int pci_enable_ats(struct pci_dev *dev, int ps);
-void pci_disable_ats(struct pci_dev *dev);
-int pci_ats_queue_depth(struct pci_dev *dev);
-
-/**
- * pci_ats_enabled - query the ATS status
- * @dev: the PCI device
- *
- * Returns 1 if ATS capability is enabled, or 0 if not.
- */
-static inline int pci_ats_enabled(struct pci_dev *dev)
-{
- return dev->ats_cap && dev->ats_enabled;
-}
-
-#else /* CONFIG_PCI_ATS */
-
-static inline int pci_enable_ats(struct pci_dev *dev, int ps)
-{
- return -ENODEV;
-}
-
-static inline void pci_disable_ats(struct pci_dev *dev)
-{
-}
-
-static inline int pci_ats_queue_depth(struct pci_dev *dev)
-{
- return -ENODEV;
-}
-
-static inline int pci_ats_enabled(struct pci_dev *dev)
-{
- return 0;
-}
-
-#endif /* CONFIG_PCI_ATS */
-
#ifdef CONFIG_PCI_PRI
int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 238b77e..307f96a 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1301,8 +1301,16 @@ void ht_destroy_irq(unsigned int irq);
#ifdef CONFIG_PCI_ATS
/* Address Translation Service */
void pci_ats_init(struct pci_dev *dev);
+int pci_enable_ats(struct pci_dev *dev, int ps);
+void pci_disable_ats(struct pci_dev *dev);
+int pci_ats_queue_depth(struct pci_dev *dev);
+static inline int pci_ats_enabled(struct pci_dev *dev) { return dev->ats_cap && dev->ats_enabled; }
#else
-static inline void pci_ats_init(struct pci_dev *dev) { }
+static inline void pci_ats_init(struct pci_dev *d) { }
+static inline int pci_enable_ats(struct pci_dev *d, int ps) { return -ENODEV; }
+static inline void pci_disable_ats(struct pci_dev *d) { }
+static inline int pci_ats_queue_depth(struct pci_dev *d) { return -ENODEV; }
+static inline int pci_ats_enabled(struct pci_dev *d) { return 0; }
#endif
void pci_cfg_access_lock(struct pci_dev *dev);
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 10/11] PCI: Stop caching ATS Invalidate Queue Depth
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
` (8 preceding siblings ...)
2015-08-11 15:52 ` [PATCH v3 09/11] PCI: Move ATS declarations to linux/pci.h so they're all together Bjorn Helgaas
@ 2015-08-11 15:52 ` Bjorn Helgaas
2015-08-11 15:52 ` [PATCH v3 11/11] PCI: Remove pci_ats_enabled() Bjorn Helgaas
2015-08-14 14:40 ` [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:52 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
Stop caching the Invalidate Queue Depth in struct pci_dev.
pci_ats_queue_depth() is typically called only once per device, and it
returns a fixed value per-device, so callers who need the value frequently
can cache it themselves.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Joerg Roedel <jroedel@suse.de>
---
drivers/pci/ats.c | 9 ++++-----
include/linux/pci.h | 1 -
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 0f05274..4b17cf5 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -20,16 +20,12 @@
void pci_ats_init(struct pci_dev *dev)
{
int pos;
- u16 cap;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
if (!pos)
return;
dev->ats_cap = pos;
- pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap);
- dev->ats_qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
- PCI_ATS_MAX_QDEP;
}
/**
@@ -132,13 +128,16 @@ EXPORT_SYMBOL_GPL(pci_restore_ats_state);
*/
int pci_ats_queue_depth(struct pci_dev *dev)
{
+ u16 cap;
+
if (!dev->ats_cap)
return -EINVAL;
if (dev->is_virtfn)
return 0;
- return dev->ats_qdep;
+ pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap);
+ return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : PCI_ATS_MAX_QDEP;
}
EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 307f96a..4b484fd 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -378,7 +378,6 @@ struct pci_dev {
};
u16 ats_cap; /* ATS Capability offset */
u8 ats_stu; /* ATS Smallest Translation Unit */
- u8 ats_qdep; /* ATS Invalidate Queue Depth */
atomic_t ats_ref_cnt; /* number of VFs with ATS enabled */
#endif
phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3 11/11] PCI: Remove pci_ats_enabled()
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
` (9 preceding siblings ...)
2015-08-11 15:52 ` [PATCH v3 10/11] PCI: Stop caching ATS Invalidate Queue Depth Bjorn Helgaas
@ 2015-08-11 15:52 ` Bjorn Helgaas
2015-08-14 14:40 ` [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-11 15:52 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
Remove pci_ats_enabled(). There are no callers outside the ATS code
itself. We don't need to check ats_cap, because if we don't find an ATS
capability, we'll never set ats_enabled.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Joerg Roedel <jroedel@suse.de>
---
drivers/pci/ats.c | 8 ++++----
include/linux/pci.h | 2 --
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index 4b17cf5..94976b4 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -43,8 +43,8 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
if (!dev->ats_cap)
return -EINVAL;
- WARN_ON(pci_ats_enabled(dev));
- if (pci_ats_enabled(dev))
+ WARN_ON(dev->ats_enabled);
+ if (dev->ats_enabled)
return -EBUSY;
if (ps < PCI_ATS_MIN_STU)
@@ -81,7 +81,7 @@ void pci_disable_ats(struct pci_dev *dev)
struct pci_dev *pdev;
u16 ctrl;
- if (!pci_ats_enabled(dev))
+ if (!dev->ats_enabled)
return;
if (atomic_read(&dev->ats_ref_cnt))
@@ -104,7 +104,7 @@ void pci_restore_ats_state(struct pci_dev *dev)
{
u16 ctrl;
- if (!pci_ats_enabled(dev))
+ if (!dev->ats_enabled)
return;
ctrl = PCI_ATS_CTRL_ENABLE;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4b484fd..806da76 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1303,13 +1303,11 @@ void pci_ats_init(struct pci_dev *dev);
int pci_enable_ats(struct pci_dev *dev, int ps);
void pci_disable_ats(struct pci_dev *dev);
int pci_ats_queue_depth(struct pci_dev *dev);
-static inline int pci_ats_enabled(struct pci_dev *dev) { return dev->ats_cap && dev->ats_enabled; }
#else
static inline void pci_ats_init(struct pci_dev *d) { }
static inline int pci_enable_ats(struct pci_dev *d, int ps) { return -ENODEV; }
static inline void pci_disable_ats(struct pci_dev *d) { }
static inline int pci_ats_queue_depth(struct pci_dev *d) { return -ENODEV; }
-static inline int pci_ats_enabled(struct pci_dev *d) { return 0; }
#endif
void pci_cfg_access_lock(struct pci_dev *dev);
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v3 01/11] iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth
2015-08-11 15:51 ` [PATCH v3 01/11] iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth Bjorn Helgaas
@ 2015-08-13 7:53 ` Joerg Roedel
0 siblings, 0 replies; 15+ messages in thread
From: Joerg Roedel @ 2015-08-13 7:53 UTC (permalink / raw)
To: Bjorn Helgaas; +Cc: linux-pci, David Woodhouse, Gregor Dick, iommu, Yinghai Lu
On Tue, Aug 11, 2015 at 10:51:07AM -0500, Bjorn Helgaas wrote:
> We check the ATS state (enabled/disabled) and fetch the PCI ATS Invalidate
> Queue Depth in performance-sensitive paths. It's easy to cache these,
> which removes dependencies on PCI.
>
> Remember the ATS enabled state. When enabling, read the queue depth once
> and cache it in the device_domain_info struct. This is similar to what
> amd_iommu.c does.
>
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/iommu/intel-iommu.c | 28 ++++++++++++++++++----------
> 1 file changed, 18 insertions(+), 10 deletions(-)
Reviewed-by: Joerg Roedel <jroedel@suse.de>
Acked-by: Joerg Roedel <jroedel@suse.de>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 08/11] PCI: Clean up ATS error handling
2015-08-11 15:52 ` [PATCH v3 08/11] PCI: Clean up ATS error handling Bjorn Helgaas
@ 2015-08-13 7:57 ` Joerg Roedel
0 siblings, 0 replies; 15+ messages in thread
From: Joerg Roedel @ 2015-08-13 7:57 UTC (permalink / raw)
To: Bjorn Helgaas; +Cc: linux-pci, David Woodhouse, Gregor Dick, iommu, Yinghai Lu
Hi Bjoern,
On Tue, Aug 11, 2015 at 10:52:02AM -0500, Bjorn Helgaas wrote:
> There's no need to BUG() if we enable ATS when it's already enabled. We
> don't need to BUG() when disabling ATS on a device that doesn't support ATS
> or if it's already disabled. If ATS is enabled, certainly we found an ATS
> capability in the past, so it should still be there now.
>
> Clean up these error paths.
>
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Two comments inline. With these changes:
Reviewed-by: Joerg Roedel <jroedel@suse.de>
> ---
> drivers/pci/ats.c | 11 ++++++-----
> 1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
> index 0b5b0ed..0f05274 100644
> --- a/drivers/pci/ats.c
> +++ b/drivers/pci/ats.c
> @@ -44,11 +44,13 @@ int pci_enable_ats(struct pci_dev *dev, int ps)
> u16 ctrl;
> struct pci_dev *pdev;
>
> - BUG_ON(dev->ats_cap && dev->ats_enabled);
> -
> if (!dev->ats_cap)
> return -EINVAL;
>
> + WARN_ON(pci_ats_enabled(dev));
> + if (pci_ats_enabled(dev))
> + return -EBUSY;
> +
Could be written as
if (WARN_ON(pci_ats_enabled(dev)))
return -EBUSY;
> if (ps < PCI_ATS_MIN_STU)
> return -EINVAL;
>
> @@ -83,7 +85,8 @@ void pci_disable_ats(struct pci_dev *dev)
> struct pci_dev *pdev;
> u16 ctrl;
>
> - BUG_ON(!dev->ats_cap || !dev->ats_enabled);
> + if (!pci_ats_enabled(dev))
> + return;
Probably also:
if (WARN_ON(!pci_ats_enabled(dev)))
?
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 00/11] PCI: Fix ATS deadlock
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
` (10 preceding siblings ...)
2015-08-11 15:52 ` [PATCH v3 11/11] PCI: Remove pci_ats_enabled() Bjorn Helgaas
@ 2015-08-14 14:40 ` Bjorn Helgaas
11 siblings, 0 replies; 15+ messages in thread
From: Bjorn Helgaas @ 2015-08-14 14:40 UTC (permalink / raw)
To: linux-pci, Joerg Roedel, David Woodhouse; +Cc: Gregor Dick, iommu, Yinghai Lu
On Tue, Aug 11, 2015 at 10:50:59AM -0500, Bjorn Helgaas wrote:
> Gregor reported a deadlock [1] when enabling a VF that supports ATS.
> This series is intended to fix that. The second patch should be enough to
> fix the deadlock; the rest are simplification and cleanup.
>
> These are based on v4.2-rc2.
>
> [1] http://permalink.gmane.org/gmane.linux.kernel.iommu/9433
>
> Changes between v2 and v3:
> - Initialize info->ats.enabled, qdep in intel-iommu.c (Yinghai)
> - Use "u8 enabled:1", not "int enabled:1" in intel-iommu.c state
> - WARN_ON() if enabling ATS when already enabled (Joerg)
> - Return -EBUSY, not -EINVAL if enabling ATS when already enabled
> - Added Reviewed-by from Joerg
>
> Changes between v1 and v2:
> - Remove use of pci_ats_enabled() (intel-iommu.c)
> - Call pci_ats_queue_depth() only once per device and cache result
> (intel-iommu.c)
> - Remove pci_ats_enabled() interface
> - Stop caching queue depth in pci_dev to save space
> - Add PF refcount of how many associated VFs have ATS enabled
> - Add comment that ATS must be enabled on PF before on VFs
> - Require ATS to be disabled on all VFs and PF before changing STU
>
> ---
>
> Bjorn Helgaas (11):
> iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth
> PCI: Allocate ATS struct during enumeration
> PCI: Embed ATS info directly into struct pci_dev
> PCI: Reduce size of ATS structure elements
> PCI: Rationalize pci_ats_queue_depth() error checking
> PCI: Inline the ATS setup code into pci_ats_init()
> PCI: Use pci_physfn() rather than looking up physfn by hand
> PCI: Clean up ATS error handling
> PCI: Move ATS declarations to linux/pci.h so they're all together
> PCI: Stop caching ATS Invalidate Queue Depth
> PCI: Remove pci_ats_enabled()
>
>
> drivers/iommu/intel-iommu.c | 28 ++++++---
> drivers/pci/ats.c | 132 +++++++++++++++----------------------------
> drivers/pci/probe.c | 3 +
> include/linux/pci-ats.h | 49 ----------------
> include/linux/pci.h | 18 ++++++
> 5 files changed, 85 insertions(+), 145 deletions(-)
Applied with the tweaks Joerg suggested and his Ack/Reviewed-by to
pci/iommu for v4.3. Thanks for all your reviewing and testing!
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2015-08-14 14:41 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-11 15:50 [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 01/11] iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth Bjorn Helgaas
2015-08-13 7:53 ` Joerg Roedel
2015-08-11 15:51 ` [PATCH v3 02/11] PCI: Allocate ATS struct during enumeration Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 03/11] PCI: Embed ATS info directly into struct pci_dev Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 04/11] PCI: Reduce size of ATS structure elements Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 05/11] PCI: Rationalize pci_ats_queue_depth() error checking Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 06/11] PCI: Inline the ATS setup code into pci_ats_init() Bjorn Helgaas
2015-08-11 15:51 ` [PATCH v3 07/11] PCI: Use pci_physfn() rather than looking up physfn by hand Bjorn Helgaas
2015-08-11 15:52 ` [PATCH v3 08/11] PCI: Clean up ATS error handling Bjorn Helgaas
2015-08-13 7:57 ` Joerg Roedel
2015-08-11 15:52 ` [PATCH v3 09/11] PCI: Move ATS declarations to linux/pci.h so they're all together Bjorn Helgaas
2015-08-11 15:52 ` [PATCH v3 10/11] PCI: Stop caching ATS Invalidate Queue Depth Bjorn Helgaas
2015-08-11 15:52 ` [PATCH v3 11/11] PCI: Remove pci_ats_enabled() Bjorn Helgaas
2015-08-14 14:40 ` [PATCH v3 00/11] PCI: Fix ATS deadlock Bjorn Helgaas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).