|
12 | 12 | #define pr_fmt(fmt) "DMAR: " fmt
|
13 | 13 |
|
14 | 14 | #include <linux/iommu.h>
|
| 15 | +#include <linux/pci.h> |
| 16 | +#include <linux/pci-ats.h> |
15 | 17 |
|
16 | 18 | #include "iommu.h"
|
| 19 | +#include "pasid.h" |
| 20 | + |
| 21 | +static int intel_nested_attach_dev(struct iommu_domain *domain, |
| 22 | + struct device *dev) |
| 23 | +{ |
| 24 | + struct device_domain_info *info = dev_iommu_priv_get(dev); |
| 25 | + struct dmar_domain *dmar_domain = to_dmar_domain(domain); |
| 26 | + struct intel_iommu *iommu = info->iommu; |
| 27 | + unsigned long flags; |
| 28 | + int ret = 0; |
| 29 | + |
| 30 | + if (info->domain) |
| 31 | + device_block_translation(dev); |
| 32 | + |
| 33 | + if (iommu->agaw < dmar_domain->s2_domain->agaw) { |
| 34 | + dev_err_ratelimited(dev, "Adjusted guest address width not compatible\n"); |
| 35 | + return -ENODEV; |
| 36 | + } |
| 37 | + |
| 38 | + /* |
| 39 | + * Stage-1 domain cannot work alone, it is nested on a s2_domain. |
| 40 | + * The s2_domain will be used in nested translation, hence needs |
| 41 | + * to ensure the s2_domain is compatible with this IOMMU. |
| 42 | + */ |
| 43 | + ret = prepare_domain_attach_device(&dmar_domain->s2_domain->domain, dev); |
| 44 | + if (ret) { |
| 45 | + dev_err_ratelimited(dev, "s2 domain is not compatible\n"); |
| 46 | + return ret; |
| 47 | + } |
| 48 | + |
| 49 | + ret = domain_attach_iommu(dmar_domain, iommu); |
| 50 | + if (ret) { |
| 51 | + dev_err_ratelimited(dev, "Failed to attach domain to iommu\n"); |
| 52 | + return ret; |
| 53 | + } |
| 54 | + |
| 55 | + ret = intel_pasid_setup_nested(iommu, dev, |
| 56 | + IOMMU_NO_PASID, dmar_domain); |
| 57 | + if (ret) { |
| 58 | + domain_detach_iommu(dmar_domain, iommu); |
| 59 | + dev_err_ratelimited(dev, "Failed to setup pasid entry\n"); |
| 60 | + return ret; |
| 61 | + } |
| 62 | + |
| 63 | + info->domain = dmar_domain; |
| 64 | + spin_lock_irqsave(&dmar_domain->lock, flags); |
| 65 | + list_add(&info->link, &dmar_domain->devices); |
| 66 | + spin_unlock_irqrestore(&dmar_domain->lock, flags); |
| 67 | + |
| 68 | + return 0; |
| 69 | +} |
17 | 70 |
|
18 | 71 | static void intel_nested_domain_free(struct iommu_domain *domain)
|
19 | 72 | {
|
20 | 73 | kfree(to_dmar_domain(domain));
|
21 | 74 | }
|
22 | 75 |
|
23 | 76 | static const struct iommu_domain_ops intel_nested_domain_ops = {
|
| 77 | + .attach_dev = intel_nested_attach_dev, |
24 | 78 | .free = intel_nested_domain_free,
|
25 | 79 | };
|
26 | 80 |
|
|
0 commit comments