aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2014-02-19 01:07:34 -0500
committerJoerg Roedel <joro@8bytes.org>2014-03-04 11:51:05 -0500
commit0e242612d9cdb46e878ed1f126c78fe68492af00 (patch)
treeab7c73c8ebb07c94ac42d93de529f9905569ab09 /drivers/iommu
parent3a5670e8ac932c10a3e50d9dc0ab1da4cc3041d7 (diff)
iommu/vt-d: Use RCU to protect global resources in interrupt context
Global DMA and interrupt remapping resources may be accessed in interrupt context, so use RCU instead of rwsem to protect them in such cases. Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Signed-off-by: Joerg Roedel <joro@8bytes.org>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/dmar.c33
-rw-r--r--drivers/iommu/intel-iommu.c20
2 files changed, 36 insertions, 17 deletions
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index c9aca8841fa0..6e4d851991f1 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -71,13 +71,13 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
71 * the very end. 71 * the very end.
72 */ 72 */
73 if (drhd->include_all) 73 if (drhd->include_all)
74 list_add_tail(&drhd->list, &dmar_drhd_units); 74 list_add_tail_rcu(&drhd->list, &dmar_drhd_units);
75 else 75 else
76 list_add(&drhd->list, &dmar_drhd_units); 76 list_add_rcu(&drhd->list, &dmar_drhd_units);
77} 77}
78 78
79static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, 79static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
80 struct pci_dev **dev, u16 segment) 80 struct pci_dev __rcu **dev, u16 segment)
81{ 81{
82 struct pci_bus *bus; 82 struct pci_bus *bus;
83 struct pci_dev *pdev = NULL; 83 struct pci_dev *pdev = NULL;
@@ -122,7 +122,9 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
122 pci_name(pdev)); 122 pci_name(pdev));
123 return -EINVAL; 123 return -EINVAL;
124 } 124 }
125 *dev = pdev; 125
126 rcu_assign_pointer(*dev, pdev);
127
126 return 0; 128 return 0;
127} 129}
128 130
@@ -149,7 +151,7 @@ void *dmar_alloc_dev_scope(void *start, void *end, int *cnt)
149} 151}
150 152
151int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, 153int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
152 struct pci_dev ***devices, u16 segment) 154 struct pci_dev __rcu ***devices, u16 segment)
153{ 155{
154 struct acpi_dmar_device_scope *scope; 156 struct acpi_dmar_device_scope *scope;
155 int index, ret; 157 int index, ret;
@@ -177,7 +179,7 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
177 return 0; 179 return 0;
178} 180}
179 181
180void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt) 182void dmar_free_dev_scope(struct pci_dev __rcu ***devices, int *cnt)
181{ 183{
182 int i; 184 int i;
183 struct pci_dev *tmp_dev; 185 struct pci_dev *tmp_dev;
@@ -186,9 +188,10 @@ void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt)
186 for_each_active_dev_scope(*devices, *cnt, i, tmp_dev) 188 for_each_active_dev_scope(*devices, *cnt, i, tmp_dev)
187 pci_dev_put(tmp_dev); 189 pci_dev_put(tmp_dev);
188 kfree(*devices); 190 kfree(*devices);
189 *devices = NULL;
190 *cnt = 0;
191 } 191 }
192
193 *devices = NULL;
194 *cnt = 0;
192} 195}
193 196
194/** 197/**
@@ -410,7 +413,7 @@ parse_dmar_table(void)
410 return ret; 413 return ret;
411} 414}
412 415
413static int dmar_pci_device_match(struct pci_dev *devices[], int cnt, 416static int dmar_pci_device_match(struct pci_dev __rcu *devices[], int cnt,
414 struct pci_dev *dev) 417 struct pci_dev *dev)
415{ 418{
416 int index; 419 int index;
@@ -431,11 +434,12 @@ static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
431struct dmar_drhd_unit * 434struct dmar_drhd_unit *
432dmar_find_matched_drhd_unit(struct pci_dev *dev) 435dmar_find_matched_drhd_unit(struct pci_dev *dev)
433{ 436{
434 struct dmar_drhd_unit *dmaru = NULL; 437 struct dmar_drhd_unit *dmaru;
435 struct acpi_dmar_hardware_unit *drhd; 438 struct acpi_dmar_hardware_unit *drhd;
436 439
437 dev = pci_physfn(dev); 440 dev = pci_physfn(dev);
438 441
442 rcu_read_lock();
439 for_each_drhd_unit(dmaru) { 443 for_each_drhd_unit(dmaru) {
440 drhd = container_of(dmaru->hdr, 444 drhd = container_of(dmaru->hdr,
441 struct acpi_dmar_hardware_unit, 445 struct acpi_dmar_hardware_unit,
@@ -443,14 +447,17 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
443 447
444 if (dmaru->include_all && 448 if (dmaru->include_all &&
445 drhd->segment == pci_domain_nr(dev->bus)) 449 drhd->segment == pci_domain_nr(dev->bus))
446 return dmaru; 450 goto out;
447 451
448 if (dmar_pci_device_match(dmaru->devices, 452 if (dmar_pci_device_match(dmaru->devices,
449 dmaru->devices_cnt, dev)) 453 dmaru->devices_cnt, dev))
450 return dmaru; 454 goto out;
451 } 455 }
456 dmaru = NULL;
457out:
458 rcu_read_unlock();
452 459
453 return NULL; 460 return dmaru;
454} 461}
455 462
456int __init dmar_dev_scope_init(void) 463int __init dmar_dev_scope_init(void)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 50d639a2df88..e1679a6fe468 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -385,14 +385,14 @@ struct dmar_rmrr_unit {
385 struct acpi_dmar_header *hdr; /* ACPI header */ 385 struct acpi_dmar_header *hdr; /* ACPI header */
386 u64 base_address; /* reserved base address*/ 386 u64 base_address; /* reserved base address*/
387 u64 end_address; /* reserved end address */ 387 u64 end_address; /* reserved end address */
388 struct pci_dev **devices; /* target devices */ 388 struct pci_dev __rcu **devices; /* target devices */
389 int devices_cnt; /* target device count */ 389 int devices_cnt; /* target device count */
390}; 390};
391 391
392struct dmar_atsr_unit { 392struct dmar_atsr_unit {
393 struct list_head list; /* list of ATSR units */ 393 struct list_head list; /* list of ATSR units */
394 struct acpi_dmar_header *hdr; /* ACPI header */ 394 struct acpi_dmar_header *hdr; /* ACPI header */
395 struct pci_dev **devices; /* target devices */ 395 struct pci_dev __rcu **devices; /* target devices */
396 int devices_cnt; /* target device count */ 396 int devices_cnt; /* target device count */
397 u8 include_all:1; /* include all ports */ 397 u8 include_all:1; /* include all ports */
398}; 398};
@@ -634,12 +634,15 @@ static void domain_update_iommu_superpage(struct dmar_domain *domain)
634 } 634 }
635 635
636 /* set iommu_superpage to the smallest common denominator */ 636 /* set iommu_superpage to the smallest common denominator */
637 rcu_read_lock();
637 for_each_active_iommu(iommu, drhd) { 638 for_each_active_iommu(iommu, drhd) {
638 mask &= cap_super_page_val(iommu->cap); 639 mask &= cap_super_page_val(iommu->cap);
639 if (!mask) { 640 if (!mask) {
640 break; 641 break;
641 } 642 }
642 } 643 }
644 rcu_read_unlock();
645
643 domain->iommu_superpage = fls(mask); 646 domain->iommu_superpage = fls(mask);
644} 647}
645 648
@@ -658,6 +661,7 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
658 struct pci_dev *dev; 661 struct pci_dev *dev;
659 int i; 662 int i;
660 663
664 rcu_read_lock();
661 for_each_active_iommu(iommu, drhd) { 665 for_each_active_iommu(iommu, drhd) {
662 if (segment != drhd->segment) 666 if (segment != drhd->segment)
663 continue; 667 continue;
@@ -677,6 +681,7 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
677 } 681 }
678 iommu = NULL; 682 iommu = NULL;
679out: 683out:
684 rcu_read_unlock();
680 685
681 return iommu; 686 return iommu;
682} 687}
@@ -1535,10 +1540,12 @@ static void domain_exit(struct dmar_domain *domain)
1535 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw)); 1540 dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
1536 1541
1537 /* clear attached or cached domains */ 1542 /* clear attached or cached domains */
1543 rcu_read_lock();
1538 for_each_active_iommu(iommu, drhd) 1544 for_each_active_iommu(iommu, drhd)
1539 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE || 1545 if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE ||
1540 test_bit(iommu->seq_id, domain->iommu_bmp)) 1546 test_bit(iommu->seq_id, domain->iommu_bmp))
1541 iommu_detach_domain(domain, iommu); 1547 iommu_detach_domain(domain, iommu);
1548 rcu_read_unlock();
1542 1549
1543 free_domain_mem(domain); 1550 free_domain_mem(domain);
1544} 1551}
@@ -2338,6 +2345,7 @@ static bool device_has_rmrr(struct pci_dev *dev)
2338 struct pci_dev *tmp; 2345 struct pci_dev *tmp;
2339 int i; 2346 int i;
2340 2347
2348 rcu_read_lock();
2341 for_each_rmrr_units(rmrr) { 2349 for_each_rmrr_units(rmrr) {
2342 /* 2350 /*
2343 * Return TRUE if this RMRR contains the device that 2351 * Return TRUE if this RMRR contains the device that
@@ -2346,9 +2354,11 @@ static bool device_has_rmrr(struct pci_dev *dev)
2346 for_each_active_dev_scope(rmrr->devices, 2354 for_each_active_dev_scope(rmrr->devices,
2347 rmrr->devices_cnt, i, tmp) 2355 rmrr->devices_cnt, i, tmp)
2348 if (tmp == dev) { 2356 if (tmp == dev) {
2357 rcu_read_unlock();
2349 return true; 2358 return true;
2350 } 2359 }
2351 } 2360 }
2361 rcu_read_unlock();
2352 return false; 2362 return false;
2353} 2363}
2354 2364
@@ -3512,7 +3522,7 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3512 atsru->hdr = hdr; 3522 atsru->hdr = hdr;
3513 atsru->include_all = atsr->flags & 0x1; 3523 atsru->include_all = atsr->flags & 0x1;
3514 3524
3515 list_add(&atsru->list, &dmar_atsr_units); 3525 list_add_rcu(&atsru->list, &dmar_atsr_units);
3516 3526
3517 return 0; 3527 return 0;
3518} 3528}
@@ -3574,6 +3584,7 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3574 if (!bridge) 3584 if (!bridge)
3575 return 0; 3585 return 0;
3576 3586
3587 rcu_read_lock();
3577 list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) { 3588 list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) {
3578 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); 3589 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3579 if (atsr->segment != pci_domain_nr(dev->bus)) 3590 if (atsr->segment != pci_domain_nr(dev->bus))
@@ -3588,6 +3599,7 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
3588 } 3599 }
3589 ret = 0; 3600 ret = 0;
3590out: 3601out:
3602 rcu_read_unlock();
3591 3603
3592 return ret; 3604 return ret;
3593} 3605}
@@ -3604,7 +3616,7 @@ int __init dmar_parse_rmrr_atsr_dev(void)
3604 return ret; 3616 return ret;
3605 } 3617 }
3606 3618
3607 list_for_each_entry(atsr, &dmar_atsr_units, list) { 3619 list_for_each_entry_rcu(atsr, &dmar_atsr_units, list) {
3608 ret = atsr_parse_dev(atsr); 3620 ret = atsr_parse_dev(atsr);
3609 if (ret) 3621 if (ret)
3610 return ret; 3622 return ret;