1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright © 2015 Intel Corporation. |
4 | * |
5 | * Authors: David Woodhouse <dwmw2@infradead.org> |
6 | */ |
7 | |
8 | #include <linux/mmu_notifier.h> |
9 | #include <linux/sched.h> |
10 | #include <linux/sched/mm.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/rculist.h> |
13 | #include <linux/pci.h> |
14 | #include <linux/pci-ats.h> |
15 | #include <linux/dmar.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/mm_types.h> |
18 | #include <linux/xarray.h> |
19 | #include <asm/page.h> |
20 | #include <asm/fpu/api.h> |
21 | |
22 | #include "iommu.h" |
23 | #include "pasid.h" |
24 | #include "perf.h" |
25 | #include "../iommu-pages.h" |
26 | #include "trace.h" |
27 | |
28 | void intel_svm_check(struct intel_iommu *iommu) |
29 | { |
30 | if (!pasid_supported(iommu)) |
31 | return; |
32 | |
33 | if (cpu_feature_enabled(X86_FEATURE_GBPAGES) && |
34 | !cap_fl1gp_support(iommu->cap)) { |
35 | pr_err("%s SVM disabled, incompatible 1GB page capability\n" , |
36 | iommu->name); |
37 | return; |
38 | } |
39 | |
40 | if (cpu_feature_enabled(X86_FEATURE_LA57) && |
41 | !cap_fl5lp_support(iommu->cap)) { |
42 | pr_err("%s SVM disabled, incompatible paging mode\n" , |
43 | iommu->name); |
44 | return; |
45 | } |
46 | |
47 | iommu->flags |= VTD_FLAG_SVM_CAPABLE; |
48 | } |
49 | |
50 | /* Pages have been freed at this point */ |
51 | static void intel_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn, |
52 | struct mm_struct *mm, |
53 | unsigned long start, unsigned long end) |
54 | { |
55 | struct dmar_domain *domain = container_of(mn, struct dmar_domain, notifier); |
56 | |
57 | if (start == 0 && end == ULONG_MAX) { |
58 | cache_tag_flush_all(domain); |
59 | return; |
60 | } |
61 | |
62 | /* |
63 | * The mm_types defines vm_end as the first byte after the end address, |
64 | * different from IOMMU subsystem using the last address of an address |
65 | * range. |
66 | */ |
67 | cache_tag_flush_range(domain, start, end: end - 1, ih: 0); |
68 | } |
69 | |
70 | static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm) |
71 | { |
72 | struct dmar_domain *domain = container_of(mn, struct dmar_domain, notifier); |
73 | struct dev_pasid_info *dev_pasid; |
74 | struct device_domain_info *info; |
75 | unsigned long flags; |
76 | |
77 | /* This might end up being called from exit_mmap(), *before* the page |
78 | * tables are cleared. And __mmu_notifier_release() will delete us from |
79 | * the list of notifiers so that our invalidate_range() callback doesn't |
80 | * get called when the page tables are cleared. So we need to protect |
81 | * against hardware accessing those page tables. |
82 | * |
83 | * We do it by clearing the entry in the PASID table and then flushing |
84 | * the IOTLB and the PASID table caches. This might upset hardware; |
85 | * perhaps we'll want to point the PASID to a dummy PGD (like the zero |
86 | * page) so that we end up taking a fault that the hardware really |
87 | * *has* to handle gracefully without affecting other processes. |
88 | */ |
89 | spin_lock_irqsave(&domain->lock, flags); |
90 | list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) { |
91 | info = dev_iommu_priv_get(dev: dev_pasid->dev); |
92 | intel_pasid_tear_down_entry(iommu: info->iommu, dev: dev_pasid->dev, |
93 | pasid: dev_pasid->pasid, fault_ignore: true); |
94 | } |
95 | spin_unlock_irqrestore(lock: &domain->lock, flags); |
96 | |
97 | } |
98 | |
99 | static void intel_mm_free_notifier(struct mmu_notifier *mn) |
100 | { |
101 | struct dmar_domain *domain = container_of(mn, struct dmar_domain, notifier); |
102 | |
103 | kfree(objp: domain->qi_batch); |
104 | kfree(objp: domain); |
105 | } |
106 | |
107 | static const struct mmu_notifier_ops intel_mmuops = { |
108 | .release = intel_mm_release, |
109 | .arch_invalidate_secondary_tlbs = intel_arch_invalidate_secondary_tlbs, |
110 | .free_notifier = intel_mm_free_notifier, |
111 | }; |
112 | |
113 | static int intel_iommu_sva_supported(struct device *dev) |
114 | { |
115 | struct device_domain_info *info = dev_iommu_priv_get(dev); |
116 | struct intel_iommu *iommu; |
117 | |
118 | if (!info || dmar_disabled) |
119 | return -EINVAL; |
120 | |
121 | iommu = info->iommu; |
122 | if (!iommu) |
123 | return -EINVAL; |
124 | |
125 | if (!(iommu->flags & VTD_FLAG_SVM_CAPABLE)) |
126 | return -ENODEV; |
127 | |
128 | if (!info->pasid_enabled || !info->ats_enabled) |
129 | return -EINVAL; |
130 | |
131 | /* |
132 | * Devices having device-specific I/O fault handling should not |
133 | * support PCI/PRI. The IOMMU side has no means to check the |
134 | * capability of device-specific IOPF. Therefore, IOMMU can only |
135 | * default that if the device driver enables SVA on a non-PRI |
136 | * device, it will handle IOPF in its own way. |
137 | */ |
138 | if (!info->pri_supported) |
139 | return 0; |
140 | |
141 | /* Devices supporting PRI should have it enabled. */ |
142 | if (!info->pri_enabled) |
143 | return -EINVAL; |
144 | |
145 | return 0; |
146 | } |
147 | |
148 | static int intel_svm_set_dev_pasid(struct iommu_domain *domain, |
149 | struct device *dev, ioasid_t pasid, |
150 | struct iommu_domain *old) |
151 | { |
152 | struct device_domain_info *info = dev_iommu_priv_get(dev); |
153 | struct intel_iommu *iommu = info->iommu; |
154 | struct mm_struct *mm = domain->mm; |
155 | struct dev_pasid_info *dev_pasid; |
156 | unsigned long sflags; |
157 | int ret = 0; |
158 | |
159 | ret = intel_iommu_sva_supported(dev); |
160 | if (ret) |
161 | return ret; |
162 | |
163 | dev_pasid = domain_add_dev_pasid(domain, dev, pasid); |
164 | if (IS_ERR(ptr: dev_pasid)) |
165 | return PTR_ERR(ptr: dev_pasid); |
166 | |
167 | ret = iopf_for_domain_replace(new: domain, old, dev); |
168 | if (ret) |
169 | goto out_remove_dev_pasid; |
170 | |
171 | /* Setup the pasid table: */ |
172 | sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0; |
173 | ret = __domain_setup_first_level(iommu, dev, pasid, |
174 | FLPT_DEFAULT_DID, pgd: mm->pgd, |
175 | flags: sflags, old); |
176 | if (ret) |
177 | goto out_unwind_iopf; |
178 | |
179 | domain_remove_dev_pasid(domain: old, dev, pasid); |
180 | |
181 | return 0; |
182 | out_unwind_iopf: |
183 | iopf_for_domain_replace(new: old, old: domain, dev); |
184 | out_remove_dev_pasid: |
185 | domain_remove_dev_pasid(domain, dev, pasid); |
186 | return ret; |
187 | } |
188 | |
189 | static void intel_svm_domain_free(struct iommu_domain *domain) |
190 | { |
191 | struct dmar_domain *dmar_domain = to_dmar_domain(dom: domain); |
192 | |
193 | /* dmar_domain free is deferred to the mmu free_notifier callback. */ |
194 | mmu_notifier_put(subscription: &dmar_domain->notifier); |
195 | } |
196 | |
197 | static const struct iommu_domain_ops intel_svm_domain_ops = { |
198 | .set_dev_pasid = intel_svm_set_dev_pasid, |
199 | .free = intel_svm_domain_free |
200 | }; |
201 | |
202 | struct iommu_domain *intel_svm_domain_alloc(struct device *dev, |
203 | struct mm_struct *mm) |
204 | { |
205 | struct dmar_domain *domain; |
206 | int ret; |
207 | |
208 | ret = intel_iommu_sva_supported(dev); |
209 | if (ret) |
210 | return ERR_PTR(error: ret); |
211 | |
212 | domain = kzalloc(sizeof(*domain), GFP_KERNEL); |
213 | if (!domain) |
214 | return ERR_PTR(error: -ENOMEM); |
215 | |
216 | domain->domain.ops = &intel_svm_domain_ops; |
217 | domain->use_first_level = true; |
218 | INIT_LIST_HEAD(list: &domain->dev_pasids); |
219 | INIT_LIST_HEAD(list: &domain->cache_tags); |
220 | spin_lock_init(&domain->cache_lock); |
221 | spin_lock_init(&domain->lock); |
222 | |
223 | domain->notifier.ops = &intel_mmuops; |
224 | ret = mmu_notifier_register(subscription: &domain->notifier, mm); |
225 | if (ret) { |
226 | kfree(objp: domain); |
227 | return ERR_PTR(error: ret); |
228 | } |
229 | |
230 | return &domain->domain; |
231 | } |
232 | |