Hi Joerg,
This includes patches queued for v6.2. It includes:
- Add blocking domain support
- Cleanups
The whole series is also available at:
https://github.com/LuBaolu/intel-iommu/commits/vtd-update-for-v6.2
Please consider them for next.
Best regards,
Baolu
Lu Baolu (7):
iommu/vt-d: Allocate pasid table in device probe path
iommu/vt-d: Add device_block_translation() helper
iommu/vt-d: Add blocking domain support
iommu/vt-d: Rename iommu_disable_dev_iotlb()
iommu/vt-d: Rename domain_add_dev_info()
iommu/vt-d: Remove unnecessary domain_context_mapped()
iommu/vt-d: Use real field for indication of first level
drivers/iommu/intel/iommu.h | 15 ++--
drivers/iommu/intel/iommu.c | 169 ++++++++++++++++++------------------
2 files changed, 90 insertions(+), 94 deletions(-)
--
2.34.1
dmar_domain_attach_device() is more meaningful according to what this
helper does.
Signed-off-by: Lu Baolu <[email protected]>
Reviewed-by: Kevin Tian <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
drivers/iommu/intel/iommu.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index e814ddb84bbf..4484da88f917 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2453,7 +2453,8 @@ static int __init si_domain_init(int hw)
return 0;
}
-static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
+static int dmar_domain_attach_device(struct dmar_domain *domain,
+ struct device *dev)
{
struct device_domain_info *info = dev_iommu_priv_get(dev);
struct intel_iommu *iommu;
@@ -4286,7 +4287,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
if (ret)
return ret;
- return domain_add_dev_info(to_dmar_domain(domain), dev);
+ return dmar_domain_attach_device(to_dmar_domain(domain), dev);
}
static int intel_iommu_map(struct iommu_domain *domain,
--
2.34.1
If domain attaching to device fails, the IOMMU driver should bring the
device to blocking DMA state. The upper layer is expected to recover it
by attaching a new domain. Use device_block_translation() in the error
path of dev_attach to make the behavior specific.
The difference between device_block_translation() and the previous
dmar_remove_one_dev_info() is that, in the scalable mode, it is the
RID2PASID entry instead of context entry being cleared. As a result,
enabling PCI capabilities is moved up.
Signed-off-by: Lu Baolu <[email protected]>
Reviewed-by: Kevin Tian <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
drivers/iommu/intel/iommu.c | 44 ++++++++++++++++++++++++++++++++-----
1 file changed, 38 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index dea0190acc86..1c1a52d1a818 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -277,7 +277,7 @@ static LIST_HEAD(dmar_satc_units);
#define for_each_rmrr_units(rmrr) \
list_for_each_entry(rmrr, &dmar_rmrr_units, list)
-static void dmar_remove_one_dev_info(struct device *dev);
+static void device_block_translation(struct device *dev);
int dmar_disabled = !IS_ENABLED(CONFIG_INTEL_IOMMU_DEFAULT_ON);
int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON);
@@ -1400,7 +1400,7 @@ static void iommu_enable_pci_caps(struct device_domain_info *info)
{
struct pci_dev *pdev;
- if (!info || !dev_is_pci(info->dev))
+ if (!dev_is_pci(info->dev))
return;
pdev = to_pci_dev(info->dev);
@@ -2045,7 +2045,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
} else {
iommu_flush_write_buffer(iommu);
}
- iommu_enable_pci_caps(info);
ret = 0;
@@ -2487,7 +2486,7 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
dev, PASID_RID2PASID);
if (ret) {
dev_err(dev, "Setup RID2PASID failed\n");
- dmar_remove_one_dev_info(dev);
+ device_block_translation(dev);
return ret;
}
}
@@ -2495,10 +2494,12 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
ret = domain_context_mapping(domain, dev);
if (ret) {
dev_err(dev, "Domain context map failed\n");
- dmar_remove_one_dev_info(dev);
+ device_block_translation(dev);
return ret;
}
+ iommu_enable_pci_caps(info);
+
return 0;
}
@@ -4109,6 +4110,37 @@ static void dmar_remove_one_dev_info(struct device *dev)
info->domain = NULL;
}
+/*
+ * Clear the page table pointer in context or pasid table entries so that
+ * all DMA requests without PASID from the device are blocked. If the page
+ * table has been set, clean up the data structures.
+ */
+static void device_block_translation(struct device *dev)
+{
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
+ struct intel_iommu *iommu = info->iommu;
+ unsigned long flags;
+
+ iommu_disable_dev_iotlb(info);
+ if (!dev_is_real_dma_subdevice(dev)) {
+ if (sm_supported(iommu))
+ intel_pasid_tear_down_entry(iommu, dev,
+ PASID_RID2PASID, false);
+ else
+ domain_context_clear(info);
+ }
+
+ if (!info->domain)
+ return;
+
+ spin_lock_irqsave(&info->domain->lock, flags);
+ list_del(&info->link);
+ spin_unlock_irqrestore(&info->domain->lock, flags);
+
+ domain_detach_iommu(info->domain, iommu);
+ info->domain = NULL;
+}
+
static int md_domain_init(struct dmar_domain *domain, int guest_width)
{
int adjust_width;
@@ -4230,7 +4262,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
struct device_domain_info *info = dev_iommu_priv_get(dev);
if (info->domain)
- dmar_remove_one_dev_info(dev);
+ device_block_translation(dev);
}
ret = prepare_domain_attach_device(domain, dev);
--
2.34.1
Whether or not a domain is attached to the device, the pasid table should
always be valid as long as it has been probed. This moves the pasid table
allocation from the domain attaching device path to device probe path and
frees it in the device release path.
Signed-off-by: Lu Baolu <[email protected]>
Reviewed-by: Kevin Tian <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
drivers/iommu/intel/iommu.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index a122f5b84ad4..dea0190acc86 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2475,13 +2475,6 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)
/* PASID table is mandatory for a PCI device in scalable mode. */
if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
- ret = intel_pasid_alloc_table(dev);
- if (ret) {
- dev_err(dev, "PASID table allocation failed\n");
- dmar_remove_one_dev_info(dev);
- return ret;
- }
-
/* Setup the PASID entry for requests without PASID: */
if (hw_pass_through && domain_type_is_si(domain))
ret = intel_pasid_setup_pass_through(iommu, domain,
@@ -4106,7 +4099,6 @@ static void dmar_remove_one_dev_info(struct device *dev)
iommu_disable_dev_iotlb(info);
domain_context_clear(info);
- intel_pasid_free_table(info->dev);
}
spin_lock_irqsave(&domain->lock, flags);
@@ -4464,6 +4456,7 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
struct device_domain_info *info;
struct intel_iommu *iommu;
u8 bus, devfn;
+ int ret;
iommu = device_to_iommu(dev, &bus, &devfn);
if (!iommu || !iommu->iommu.ops)
@@ -4507,6 +4500,16 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
dev_iommu_priv_set(dev, info);
+ if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
+ ret = intel_pasid_alloc_table(dev);
+ if (ret) {
+ dev_err(dev, "PASID table allocation failed\n");
+ dev_iommu_priv_set(dev, NULL);
+ kfree(info);
+ return ERR_PTR(ret);
+ }
+ }
+
return &iommu->iommu;
}
@@ -4515,6 +4518,7 @@ static void intel_iommu_release_device(struct device *dev)
struct device_domain_info *info = dev_iommu_priv_get(dev);
dmar_remove_one_dev_info(dev);
+ intel_pasid_free_table(dev);
dev_iommu_priv_set(dev, NULL);
kfree(info);
set_dma_ops(dev, NULL);
--
2.34.1
Hi Joerg,
On 2022/11/22 17:06, Joerg Roedel wrote:
> Hi Baolu,
>
> On Tue, Nov 22, 2022 at 08:29:42AM +0800, Lu Baolu wrote:
>> Lu Baolu (7):
>> iommu/vt-d: Allocate pasid table in device probe path
>> iommu/vt-d: Add device_block_translation() helper
>> iommu/vt-d: Add blocking domain support
>> iommu/vt-d: Rename iommu_disable_dev_iotlb()
>> iommu/vt-d: Rename domain_add_dev_info()
>> iommu/vt-d: Remove unnecessary domain_context_mapped()
>> iommu/vt-d: Use real field for indication of first level
>
> Applied the first 6 patches. The last one has conflicts and doesn't
> apply on top of my x86/vt-d branch. Could you please have a look please?
I guess the last patch conflicts with below commit:
242b0aaeabbe ("iommu/vt-d: Preset Access bit for IOVA in FL non-leaf
paging entries")
which was merged in v6.1-rc6. Can you please bring the x86/vt-d branch
to v6.1-rc6, or do you want me to rebase that patch on the existing top
of the branch?
Best regards,
baolu
Hi Baolu,
On Tue, Nov 22, 2022 at 08:29:42AM +0800, Lu Baolu wrote:
> Lu Baolu (7):
> iommu/vt-d: Allocate pasid table in device probe path
> iommu/vt-d: Add device_block_translation() helper
> iommu/vt-d: Add blocking domain support
> iommu/vt-d: Rename iommu_disable_dev_iotlb()
> iommu/vt-d: Rename domain_add_dev_info()
> iommu/vt-d: Remove unnecessary domain_context_mapped()
> iommu/vt-d: Use real field for indication of first level
Applied the first 6 patches. The last one has conflicts and doesn't
apply on top of my x86/vt-d branch. Could you please have a look please?
Thanks,
Joerg
On Tue, Nov 22, 2022 at 05:41:19PM +0800, Baolu Lu wrote:
> which was merged in v6.1-rc6. Can you please bring the x86/vt-d branch
> to v6.1-rc6, or do you want me to rebase that patch on the existing top
> of the branch?
Okay, moved the vt-d branch to be based on rc6 and applied these
changes. Thanks, Baolu!