Skip to content

Commit 058c59a

Browse files
jpbruckerwilldeacon
authored andcommitted
iommu/arm-smmu-v3: Add support for PCI PASID
Enable PASID for PCI devices that support it. Initialize PASID early in add_device() because it must be enabled before ATS. Tested-by: Zhangfei Gao <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: Jean-Philippe Brucker <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent 7682ce2 commit 058c59a

File tree

1 file changed

+61
-1
lines changed

1 file changed

+61
-1
lines changed

drivers/iommu/arm-smmu-v3.c

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2628,6 +2628,53 @@ static void arm_smmu_disable_ats(struct arm_smmu_master *master)
26282628
atomic_dec(&smmu_domain->nr_ats_masters);
26292629
}
26302630

2631+
static int arm_smmu_enable_pasid(struct arm_smmu_master *master)
2632+
{
2633+
int ret;
2634+
int features;
2635+
int num_pasids;
2636+
struct pci_dev *pdev;
2637+
2638+
if (!dev_is_pci(master->dev))
2639+
return -ENODEV;
2640+
2641+
pdev = to_pci_dev(master->dev);
2642+
2643+
features = pci_pasid_features(pdev);
2644+
if (features < 0)
2645+
return features;
2646+
2647+
num_pasids = pci_max_pasids(pdev);
2648+
if (num_pasids <= 0)
2649+
return num_pasids;
2650+
2651+
ret = pci_enable_pasid(pdev, features);
2652+
if (ret) {
2653+
dev_err(&pdev->dev, "Failed to enable PASID\n");
2654+
return ret;
2655+
}
2656+
2657+
master->ssid_bits = min_t(u8, ilog2(num_pasids),
2658+
master->smmu->ssid_bits);
2659+
return 0;
2660+
}
2661+
2662+
static void arm_smmu_disable_pasid(struct arm_smmu_master *master)
2663+
{
2664+
struct pci_dev *pdev;
2665+
2666+
if (!dev_is_pci(master->dev))
2667+
return;
2668+
2669+
pdev = to_pci_dev(master->dev);
2670+
2671+
if (!pdev->pasid_enabled)
2672+
return;
2673+
2674+
master->ssid_bits = 0;
2675+
pci_disable_pasid(pdev);
2676+
}
2677+
26312678
static void arm_smmu_detach_dev(struct arm_smmu_master *master)
26322679
{
26332680
unsigned long flags;
@@ -2831,13 +2878,23 @@ static int arm_smmu_add_device(struct device *dev)
28312878

28322879
master->ssid_bits = min(smmu->ssid_bits, fwspec->num_pasid_bits);
28332880

2881+
/*
2882+
* Note that PASID must be enabled before, and disabled after ATS:
2883+
* PCI Express Base 4.0r1.0 - 10.5.1.3 ATS Control Register
2884+
*
2885+
* Behavior is undefined if this bit is Set and the value of the PASID
2886+
* Enable, Execute Requested Enable, or Privileged Mode Requested bits
2887+
* are changed.
2888+
*/
2889+
arm_smmu_enable_pasid(master);
2890+
28342891
if (!(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB))
28352892
master->ssid_bits = min_t(u8, master->ssid_bits,
28362893
CTXDESC_LINEAR_CDMAX);
28372894

28382895
ret = iommu_device_link(&smmu->iommu, dev);
28392896
if (ret)
2840-
goto err_free_master;
2897+
goto err_disable_pasid;
28412898

28422899
group = iommu_group_get_for_dev(dev);
28432900
if (IS_ERR(group)) {
@@ -2850,6 +2907,8 @@ static int arm_smmu_add_device(struct device *dev)
28502907

28512908
err_unlink:
28522909
iommu_device_unlink(&smmu->iommu, dev);
2910+
err_disable_pasid:
2911+
arm_smmu_disable_pasid(master);
28532912
err_free_master:
28542913
kfree(master);
28552914
fwspec->iommu_priv = NULL;
@@ -2870,6 +2929,7 @@ static void arm_smmu_remove_device(struct device *dev)
28702929
arm_smmu_detach_dev(master);
28712930
iommu_group_remove_device(dev);
28722931
iommu_device_unlink(&smmu->iommu, dev);
2932+
arm_smmu_disable_pasid(master);
28732933
kfree(master);
28742934
iommu_fwspec_free(dev);
28752935
}

0 commit comments

Comments
 (0)