aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2014-02-19 01:07:35 -0500
committerJoerg Roedel <joro@8bytes.org>2014-03-04 11:51:06 -0500
commit59ce0515cdaf3b7d47893d12f61e51d691863788 (patch)
tree0ba8b7a85b98fdca4fce02a5ed5a7129730f7a6c
parent0e242612d9cdb46e878ed1f126c78fe68492af00 (diff)
iommu/vt-d: Update DRHD/RMRR/ATSR device scope caches when PCI hotplug happens
Current Intel DMAR/IOMMU driver assumes that all PCI devices associated with DMAR/RMRR/ATSR device scope arrays are created at boot time and won't change at runtime, so it caches pointers of associated PCI device object. That assumption may be wrong now due to: 1) introduction of PCI host bridge hotplug 2) PCI device hotplug through sysfs interfaces. Wang Yijing has tried to solve this issue by caching <bus, dev, func> tupple instead of the PCI device object pointer, but that's still unreliable because PCI bus number may change in case of hotplug. Please refer to http://lkml.org/lkml/2013/11/5/64 Message from Yingjing's mail: after remove and rescan a pci device [ 611.857095] dmar: DRHD: handling fault status reg 2 [ 611.857109] dmar: DMAR:[DMA Read] Request device [86:00.3] fault addr ffff7000 [ 611.857109] DMAR:[fault reason 02] Present bit in context entry is clear [ 611.857524] dmar: DRHD: handling fault status reg 102 [ 611.857534] dmar: DMAR:[DMA Read] Request device [86:00.3] fault addr ffff6000 [ 611.857534] DMAR:[fault reason 02] Present bit in context entry is clear [ 611.857936] dmar: DRHD: handling fault status reg 202 [ 611.857947] dmar: DMAR:[DMA Read] Request device [86:00.3] fault addr ffff5000 [ 611.857947] DMAR:[fault reason 02] Present bit in context entry is clear [ 611.858351] dmar: DRHD: handling fault status reg 302 [ 611.858362] dmar: DMAR:[DMA Read] Request device [86:00.3] fault addr ffff4000 [ 611.858362] DMAR:[fault reason 02] Present bit in context entry is clear [ 611.860819] IPv6: ADDRCONF(NETDEV_UP): eth3: link is not ready [ 611.860983] dmar: DRHD: handling fault status reg 402 [ 611.860995] dmar: INTR-REMAP: Request device [[86:00.3] fault index a4 [ 611.860995] INTR-REMAP:[fault reason 34] Present field in the IRTE entry is clear This patch introduces a new mechanism to update the DRHD/RMRR/ATSR device scope caches by hooking PCI bus notification. Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Signed-off-by: Joerg Roedel <joro@8bytes.org>
-rw-r--r--drivers/iommu/dmar.c207
-rw-r--r--drivers/iommu/intel-iommu.c54
-rw-r--r--include/linux/dmar.h24
3 files changed, 283 insertions, 2 deletions
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 6e4d851991f1..bf6bfd1f69aa 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -194,6 +194,209 @@ void dmar_free_dev_scope(struct pci_dev __rcu ***devices, int *cnt)
194 *cnt = 0; 194 *cnt = 0;
195} 195}
196 196
197/* Optimize out kzalloc()/kfree() for normal cases */
198static char dmar_pci_notify_info_buf[64];
199
200static struct dmar_pci_notify_info *
201dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event)
202{
203 int level = 0;
204 size_t size;
205 struct pci_dev *tmp;
206 struct dmar_pci_notify_info *info;
207
208 BUG_ON(dev->is_virtfn);
209
210 /* Only generate path[] for device addition event */
211 if (event == BUS_NOTIFY_ADD_DEVICE)
212 for (tmp = dev; tmp; tmp = tmp->bus->self)
213 level++;
214
215 size = sizeof(*info) + level * sizeof(struct acpi_dmar_pci_path);
216 if (size <= sizeof(dmar_pci_notify_info_buf)) {
217 info = (struct dmar_pci_notify_info *)dmar_pci_notify_info_buf;
218 } else {
219 info = kzalloc(size, GFP_KERNEL);
220 if (!info) {
221 pr_warn("Out of memory when allocating notify_info "
222 "for %s.\n", pci_name(dev));
223 return NULL;
224 }
225 }
226
227 info->event = event;
228 info->dev = dev;
229 info->seg = pci_domain_nr(dev->bus);
230 info->level = level;
231 if (event == BUS_NOTIFY_ADD_DEVICE) {
232 for (tmp = dev, level--; tmp; tmp = tmp->bus->self) {
233 info->path[level].device = PCI_SLOT(tmp->devfn);
234 info->path[level].function = PCI_FUNC(tmp->devfn);
235 if (pci_is_root_bus(tmp->bus))
236 info->bus = tmp->bus->number;
237 }
238 }
239
240 return info;
241}
242
243static inline void dmar_free_pci_notify_info(struct dmar_pci_notify_info *info)
244{
245 if ((void *)info != dmar_pci_notify_info_buf)
246 kfree(info);
247}
248
249static bool dmar_match_pci_path(struct dmar_pci_notify_info *info, int bus,
250 struct acpi_dmar_pci_path *path, int count)
251{
252 int i;
253
254 if (info->bus != bus)
255 return false;
256 if (info->level != count)
257 return false;
258
259 for (i = 0; i < count; i++) {
260 if (path[i].device != info->path[i].device ||
261 path[i].function != info->path[i].function)
262 return false;
263 }
264
265 return true;
266}
267
268/* Return: > 0 if match found, 0 if no match found, < 0 if error happens */
269int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
270 void *start, void*end, u16 segment,
271 struct pci_dev __rcu **devices, int devices_cnt)
272{
273 int i, level;
274 struct pci_dev *tmp, *dev = info->dev;
275 struct acpi_dmar_device_scope *scope;
276 struct acpi_dmar_pci_path *path;
277
278 if (segment != info->seg)
279 return 0;
280
281 for (; start < end; start += scope->length) {
282 scope = start;
283 if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_ENDPOINT &&
284 scope->entry_type != ACPI_DMAR_SCOPE_TYPE_BRIDGE)
285 continue;
286
287 path = (struct acpi_dmar_pci_path *)(scope + 1);
288 level = (scope->length - sizeof(*scope)) / sizeof(*path);
289 if (!dmar_match_pci_path(info, scope->bus, path, level))
290 continue;
291
292 if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT) ^
293 (dev->hdr_type == PCI_HEADER_TYPE_NORMAL)) {
294 pr_warn("Device scope type does not match for %s\n",
295 pci_name(dev));
296 return -EINVAL;
297 }
298
299 for_each_dev_scope(devices, devices_cnt, i, tmp)
300 if (tmp == NULL) {
301 rcu_assign_pointer(devices[i],
302 pci_dev_get(dev));
303 return 1;
304 }
305 BUG_ON(i >= devices_cnt);
306 }
307
308 return 0;
309}
310
311int dmar_remove_dev_scope(struct dmar_pci_notify_info *info, u16 segment,
312 struct pci_dev __rcu **devices, int count)
313{
314 int index;
315 struct pci_dev *tmp;
316
317 if (info->seg != segment)
318 return 0;
319
320 for_each_active_dev_scope(devices, count, index, tmp)
321 if (tmp == info->dev) {
322 rcu_assign_pointer(devices[index], NULL);
323 synchronize_rcu();
324 pci_dev_put(tmp);
325 return 1;
326 }
327
328 return 0;
329}
330
331static int dmar_pci_bus_add_dev(struct dmar_pci_notify_info *info)
332{
333 int ret = 0;
334 struct dmar_drhd_unit *dmaru;
335 struct acpi_dmar_hardware_unit *drhd;
336
337 for_each_drhd_unit(dmaru) {
338 if (dmaru->include_all)
339 continue;
340
341 drhd = container_of(dmaru->hdr,
342 struct acpi_dmar_hardware_unit, header);
343 ret = dmar_insert_dev_scope(info, (void *)(drhd + 1),
344 ((void *)drhd) + drhd->header.length,
345 dmaru->segment,
346 dmaru->devices, dmaru->devices_cnt);
347 if (ret != 0)
348 break;
349 }
350 if (ret >= 0)
351 ret = dmar_iommu_notify_scope_dev(info);
352
353 return ret;
354}
355
356static void dmar_pci_bus_del_dev(struct dmar_pci_notify_info *info)
357{
358 struct dmar_drhd_unit *dmaru;
359
360 for_each_drhd_unit(dmaru)
361 if (dmar_remove_dev_scope(info, dmaru->segment,
362 dmaru->devices, dmaru->devices_cnt))
363 break;
364 dmar_iommu_notify_scope_dev(info);
365}
366
367static int dmar_pci_bus_notifier(struct notifier_block *nb,
368 unsigned long action, void *data)
369{
370 struct pci_dev *pdev = to_pci_dev(data);
371 struct dmar_pci_notify_info *info;
372
373 /* Only care about add/remove events for physical functions */
374 if (pdev->is_virtfn)
375 return NOTIFY_DONE;
376 if (action != BUS_NOTIFY_ADD_DEVICE && action != BUS_NOTIFY_DEL_DEVICE)
377 return NOTIFY_DONE;
378
379 info = dmar_alloc_pci_notify_info(pdev, action);
380 if (!info)
381 return NOTIFY_DONE;
382
383 down_write(&dmar_global_lock);
384 if (action == BUS_NOTIFY_ADD_DEVICE)
385 dmar_pci_bus_add_dev(info);
386 else if (action == BUS_NOTIFY_DEL_DEVICE)
387 dmar_pci_bus_del_dev(info);
388 up_write(&dmar_global_lock);
389
390 dmar_free_pci_notify_info(info);
391
392 return NOTIFY_OK;
393}
394
395static struct notifier_block dmar_pci_bus_nb = {
396 .notifier_call = dmar_pci_bus_notifier,
397 .priority = INT_MIN,
398};
399
197/** 400/**
198 * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition 401 * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition
199 * structure which uniquely represent one DMA remapping hardware unit 402 * structure which uniquely represent one DMA remapping hardware unit
@@ -482,6 +685,8 @@ int __init dmar_dev_scope_init(void)
482 if (ret) 685 if (ret)
483 goto fail; 686 goto fail;
484 687
688 bus_register_notifier(&pci_bus_type, &dmar_pci_bus_nb);
689
485 dmar_dev_scope_initialized = 1; 690 dmar_dev_scope_initialized = 1;
486 return 0; 691 return 0;
487 692
@@ -1412,6 +1617,8 @@ static int __init dmar_free_unused_resources(void)
1412 if (irq_remapping_enabled || intel_iommu_enabled) 1617 if (irq_remapping_enabled || intel_iommu_enabled)
1413 return 0; 1618 return 0;
1414 1619
1620 bus_unregister_notifier(&pci_bus_type, &dmar_pci_bus_nb);
1621
1415 down_write(&dmar_global_lock); 1622 down_write(&dmar_global_lock);
1416 list_for_each_entry_safe(dmaru, dmaru_n, &dmar_drhd_units, list) { 1623 list_for_each_entry_safe(dmaru, dmaru_n, &dmar_drhd_units, list) {
1417 list_del(&dmaru->list); 1624 list_del(&dmaru->list);
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index e1679a6fe468..d9c0dc5a5d35 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3625,6 +3625,60 @@ int __init dmar_parse_rmrr_atsr_dev(void)
3625 return 0; 3625 return 0;
3626} 3626}
3627 3627
3628int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
3629{
3630 int ret = 0;
3631 struct dmar_rmrr_unit *rmrru;
3632 struct dmar_atsr_unit *atsru;
3633 struct acpi_dmar_atsr *atsr;
3634 struct acpi_dmar_reserved_memory *rmrr;
3635
3636 if (!intel_iommu_enabled && system_state != SYSTEM_BOOTING)
3637 return 0;
3638
3639 list_for_each_entry(rmrru, &dmar_rmrr_units, list) {
3640 rmrr = container_of(rmrru->hdr,
3641 struct acpi_dmar_reserved_memory, header);
3642 if (info->event == BUS_NOTIFY_ADD_DEVICE) {
3643 ret = dmar_insert_dev_scope(info, (void *)(rmrr + 1),
3644 ((void *)rmrr) + rmrr->header.length,
3645 rmrr->segment, rmrru->devices,
3646 rmrru->devices_cnt);
3647 if (ret > 0)
3648 break;
3649 else if(ret < 0)
3650 return ret;
3651 } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
3652 if (dmar_remove_dev_scope(info, rmrr->segment,
3653 rmrru->devices, rmrru->devices_cnt))
3654 break;
3655 }
3656 }
3657
3658 list_for_each_entry(atsru, &dmar_atsr_units, list) {
3659 if (atsru->include_all)
3660 continue;
3661
3662 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3663 if (info->event == BUS_NOTIFY_ADD_DEVICE) {
3664 ret = dmar_insert_dev_scope(info, (void *)(atsr + 1),
3665 (void *)atsr + atsr->header.length,
3666 atsr->segment, atsru->devices,
3667 atsru->devices_cnt);
3668 if (ret > 0)
3669 break;
3670 else if(ret < 0)
3671 return ret;
3672 } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
3673 if (dmar_remove_dev_scope(info, atsr->segment,
3674 atsru->devices, atsru->devices_cnt))
3675 break;
3676 }
3677 }
3678
3679 return 0;
3680}
3681
3628/* 3682/*
3629 * Here we only respond to action of unbound device from driver. 3683 * Here we only respond to action of unbound device from driver.
3630 * 3684 *
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index bedebab934b4..4e196430f1b2 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -50,6 +50,15 @@ struct dmar_drhd_unit {
50 struct intel_iommu *iommu; 50 struct intel_iommu *iommu;
51}; 51};
52 52
53struct dmar_pci_notify_info {
54 struct pci_dev *dev;
55 unsigned long event;
56 int bus;
57 u16 seg;
58 u16 level;
59 struct acpi_dmar_pci_path path[];
60} __attribute__((packed));
61
53extern struct rw_semaphore dmar_global_lock; 62extern struct rw_semaphore dmar_global_lock;
54extern struct list_head dmar_drhd_units; 63extern struct list_head dmar_drhd_units;
55 64
@@ -89,12 +98,18 @@ extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
89 struct pci_dev ***devices, u16 segment); 98 struct pci_dev ***devices, u16 segment);
90extern void *dmar_alloc_dev_scope(void *start, void *end, int *cnt); 99extern void *dmar_alloc_dev_scope(void *start, void *end, int *cnt);
91extern void dmar_free_dev_scope(struct pci_dev __rcu ***devices, int *cnt); 100extern void dmar_free_dev_scope(struct pci_dev __rcu ***devices, int *cnt);
92extern void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt); 101extern int dmar_insert_dev_scope(struct dmar_pci_notify_info *info,
93 102 void *start, void*end, u16 segment,
103 struct pci_dev __rcu **devices,
104 int devices_cnt);
105extern int dmar_remove_dev_scope(struct dmar_pci_notify_info *info,
106 u16 segment, struct pci_dev __rcu **devices,
107 int count);
94/* Intel IOMMU detection */ 108/* Intel IOMMU detection */
95extern int detect_intel_iommu(void); 109extern int detect_intel_iommu(void);
96extern int enable_drhd_fault_handling(void); 110extern int enable_drhd_fault_handling(void);
97#else 111#else
112struct dmar_pci_notify_info;
98static inline int detect_intel_iommu(void) 113static inline int detect_intel_iommu(void)
99{ 114{
100 return -ENODEV; 115 return -ENODEV;
@@ -161,6 +176,7 @@ extern int iommu_detected, no_iommu;
161extern int dmar_parse_rmrr_atsr_dev(void); 176extern int dmar_parse_rmrr_atsr_dev(void);
162extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header); 177extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
163extern int dmar_parse_one_atsr(struct acpi_dmar_header *header); 178extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
179extern int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info);
164extern int intel_iommu_init(void); 180extern int intel_iommu_init(void);
165#else /* !CONFIG_INTEL_IOMMU: */ 181#else /* !CONFIG_INTEL_IOMMU: */
166static inline int intel_iommu_init(void) { return -ENODEV; } 182static inline int intel_iommu_init(void) { return -ENODEV; }
@@ -176,6 +192,10 @@ static inline int dmar_parse_rmrr_atsr_dev(void)
176{ 192{
177 return 0; 193 return 0;
178} 194}
195static inline int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
196{
197 return 0;
198}
179#endif /* CONFIG_INTEL_IOMMU */ 199#endif /* CONFIG_INTEL_IOMMU */
180 200
181#endif /* __DMAR_H__ */ 201#endif /* __DMAR_H__ */