Skip to content

Commit 87caaba

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Move PRI enablement in probe path
Update PRI enablement to use the new method, similar to the amd iommu driver. Enable PRI in the device probe path and disable it when the device is released. PRI is enabled throughout the device's iommu lifecycle. The infrastructure for the iommu subsystem to handle iopf requests is created during iopf enablement and released during iopf disablement. All invalid page requests from the device are automatically handled by the iommu subsystem if iopf is not enabled. Add iopf_refcount to track the iopf enablement. Convert the return type of intel_iommu_disable_iopf() to void, as there is no way to handle a failure when disabling this feature. Make intel_iommu_enable/disable_iopf() helpers global, as they will be used beyond the current file in the subsequent patch. The iopf_refcount is not protected by any lock. This is acceptable, as there is no concurrent access to it in the current code. The following patch will address this by moving it to the domain attach/detach paths, which are protected by the iommu group mutex. Signed-off-by: Lu Baolu <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Tested-by: Zhangfei Gao <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 5518f23 commit 87caaba

File tree

4 files changed

+55
-90
lines changed

4 files changed

+55
-90
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 48 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,37 @@ static void iommu_disable_pci_ats(struct device_domain_info *info)
11971197
info->ats_enabled = 0;
11981198
}
11991199

1200+
static void iommu_enable_pci_pri(struct device_domain_info *info)
1201+
{
1202+
struct pci_dev *pdev;
1203+
1204+
if (!info->ats_enabled || !info->pri_supported)
1205+
return;
1206+
1207+
pdev = to_pci_dev(info->dev);
1208+
/* PASID is required in PRG Response Message. */
1209+
if (info->pasid_enabled && !pci_prg_resp_pasid_required(pdev))
1210+
return;
1211+
1212+
if (pci_reset_pri(pdev))
1213+
return;
1214+
1215+
if (!pci_enable_pri(pdev, PRQ_DEPTH))
1216+
info->pri_enabled = 1;
1217+
}
1218+
1219+
static void iommu_disable_pci_pri(struct device_domain_info *info)
1220+
{
1221+
if (!info->pri_enabled)
1222+
return;
1223+
1224+
if (WARN_ON(info->iopf_refcount))
1225+
iopf_queue_remove_device(info->iommu->iopf_queue, info->dev);
1226+
1227+
pci_disable_pri(to_pci_dev(info->dev));
1228+
info->pri_enabled = 0;
1229+
}
1230+
12001231
static void intel_flush_iotlb_all(struct iommu_domain *domain)
12011232
{
12021233
cache_tag_flush_all(to_dmar_domain(domain));
@@ -3756,6 +3787,7 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
37563787

37573788
if (sm_supported(iommu))
37583789
iommu_enable_pci_ats(info);
3790+
iommu_enable_pci_pri(info);
37593791

37603792
return &iommu->iommu;
37613793
free_table:
@@ -3773,6 +3805,7 @@ static void intel_iommu_release_device(struct device *dev)
37733805
struct device_domain_info *info = dev_iommu_priv_get(dev);
37743806
struct intel_iommu *iommu = info->iommu;
37753807

3808+
iommu_disable_pci_pri(info);
37763809
iommu_disable_pci_ats(info);
37773810

37783811
if (info->pasid_enabled) {
@@ -3861,116 +3894,41 @@ static struct iommu_group *intel_iommu_device_group(struct device *dev)
38613894
return generic_device_group(dev);
38623895
}
38633896

3864-
static int context_flip_pri(struct device_domain_info *info, bool enable)
3865-
{
3866-
struct intel_iommu *iommu = info->iommu;
3867-
u8 bus = info->bus, devfn = info->devfn;
3868-
struct context_entry *context;
3869-
u16 did;
3870-
3871-
spin_lock(&iommu->lock);
3872-
if (context_copied(iommu, bus, devfn)) {
3873-
spin_unlock(&iommu->lock);
3874-
return -EINVAL;
3875-
}
3876-
3877-
context = iommu_context_addr(iommu, bus, devfn, false);
3878-
if (!context || !context_present(context)) {
3879-
spin_unlock(&iommu->lock);
3880-
return -ENODEV;
3881-
}
3882-
did = context_domain_id(context);
3883-
3884-
if (enable)
3885-
context_set_sm_pre(context);
3886-
else
3887-
context_clear_sm_pre(context);
3888-
3889-
if (!ecap_coherent(iommu->ecap))
3890-
clflush_cache_range(context, sizeof(*context));
3891-
intel_context_flush_present(info, context, did, true);
3892-
spin_unlock(&iommu->lock);
3893-
3894-
return 0;
3895-
}
3896-
3897-
static int intel_iommu_enable_iopf(struct device *dev)
3897+
int intel_iommu_enable_iopf(struct device *dev)
38983898
{
3899-
struct pci_dev *pdev = dev_is_pci(dev) ? to_pci_dev(dev) : NULL;
39003899
struct device_domain_info *info = dev_iommu_priv_get(dev);
3901-
struct intel_iommu *iommu;
3900+
struct intel_iommu *iommu = info->iommu;
39023901
int ret;
39033902

3904-
if (!pdev || !info || !info->ats_enabled || !info->pri_supported)
3903+
if (!info->pri_enabled)
39053904
return -ENODEV;
39063905

3907-
if (info->pri_enabled)
3908-
return -EBUSY;
3909-
3910-
iommu = info->iommu;
3911-
if (!iommu)
3912-
return -EINVAL;
3913-
3914-
/* PASID is required in PRG Response Message. */
3915-
if (info->pasid_enabled && !pci_prg_resp_pasid_required(pdev))
3916-
return -EINVAL;
3917-
3918-
ret = pci_reset_pri(pdev);
3919-
if (ret)
3920-
return ret;
3906+
if (info->iopf_refcount) {
3907+
info->iopf_refcount++;
3908+
return 0;
3909+
}
39213910

39223911
ret = iopf_queue_add_device(iommu->iopf_queue, dev);
39233912
if (ret)
39243913
return ret;
39253914

3926-
ret = context_flip_pri(info, true);
3927-
if (ret)
3928-
goto err_remove_device;
3929-
3930-
ret = pci_enable_pri(pdev, PRQ_DEPTH);
3931-
if (ret)
3932-
goto err_clear_pri;
3933-
3934-
info->pri_enabled = 1;
3915+
info->iopf_refcount = 1;
39353916

39363917
return 0;
3937-
err_clear_pri:
3938-
context_flip_pri(info, false);
3939-
err_remove_device:
3940-
iopf_queue_remove_device(iommu->iopf_queue, dev);
3941-
3942-
return ret;
39433918
}
39443919

3945-
static int intel_iommu_disable_iopf(struct device *dev)
3920+
void intel_iommu_disable_iopf(struct device *dev)
39463921
{
39473922
struct device_domain_info *info = dev_iommu_priv_get(dev);
39483923
struct intel_iommu *iommu = info->iommu;
39493924

3950-
if (!info->pri_enabled)
3951-
return -EINVAL;
3925+
if (WARN_ON(!info->pri_enabled || !info->iopf_refcount))
3926+
return;
39523927

3953-
/* Disable new PRI reception: */
3954-
context_flip_pri(info, false);
3928+
if (--info->iopf_refcount)
3929+
return;
39553930

3956-
/*
3957-
* Remove device from fault queue and acknowledge all outstanding
3958-
* PRQs to the device:
3959-
*/
39603931
iopf_queue_remove_device(iommu->iopf_queue, dev);
3961-
3962-
/*
3963-
* PCIe spec states that by clearing PRI enable bit, the Page
3964-
* Request Interface will not issue new page requests, but has
3965-
* outstanding page requests that have been transmitted or are
3966-
* queued for transmission. This is supposed to be called after
3967-
* the device driver has stopped DMA, all PASIDs have been
3968-
* unbound and the outstanding PRQs have been drained.
3969-
*/
3970-
pci_disable_pri(to_pci_dev(dev));
3971-
info->pri_enabled = 0;
3972-
3973-
return 0;
39743932
}
39753933

39763934
static int
@@ -3993,7 +3951,8 @@ intel_iommu_dev_disable_feat(struct device *dev, enum iommu_dev_features feat)
39933951
{
39943952
switch (feat) {
39953953
case IOMMU_DEV_FEAT_IOPF:
3996-
return intel_iommu_disable_iopf(dev);
3954+
intel_iommu_disable_iopf(dev);
3955+
return 0;
39973956

39983957
case IOMMU_DEV_FEAT_SVA:
39993958
return 0;

drivers/iommu/intel/iommu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ struct device_domain_info {
774774
u8 ats_enabled:1;
775775
u8 dtlb_extra_inval:1; /* Quirk for devices need extra flush */
776776
u8 ats_qdep;
777+
unsigned int iopf_refcount;
777778
struct device *dev; /* it's NULL for PCIe-to-PCI bridge */
778779
struct intel_iommu *iommu; /* IOMMU used by this device */
779780
struct dmar_domain *domain; /* pointer to domain */
@@ -1295,6 +1296,9 @@ void intel_iommu_page_response(struct device *dev, struct iopf_fault *evt,
12951296
struct iommu_page_response *msg);
12961297
void intel_iommu_drain_pasid_prq(struct device *dev, u32 pasid);
12971298

1299+
int intel_iommu_enable_iopf(struct device *dev);
1300+
void intel_iommu_disable_iopf(struct device *dev);
1301+
12981302
#ifdef CONFIG_INTEL_IOMMU_SVM
12991303
void intel_svm_check(struct intel_iommu *iommu);
13001304
struct iommu_domain *intel_svm_domain_alloc(struct device *dev,

drivers/iommu/intel/pasid.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,8 @@ static int context_entry_set_pasid_table(struct context_entry *context,
992992
context_set_sm_dte(context);
993993
if (info->pasid_supported)
994994
context_set_pasid(context);
995+
if (info->pri_supported)
996+
context_set_sm_pre(context);
995997

996998
context_set_fault_enable(context);
997999
context_set_present(context);

drivers/iommu/intel/prq.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void intel_iommu_drain_pasid_prq(struct device *dev, u32 pasid)
6767
u16 sid, did;
6868

6969
info = dev_iommu_priv_get(dev);
70-
if (!info->pri_enabled)
70+
if (!info->iopf_refcount)
7171
return;
7272

7373
iommu = info->iommu;

0 commit comments

Comments
 (0)