aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2014-02-19 01:07:36 -0500
committerJoerg Roedel <joro@8bytes.org>2014-03-04 11:51:06 -0500
commit2e45528930388658603ea24d49cf52867b928d3e (patch)
tree751171aa8f2f9a00f080adb6201cf9d9acd02f94 /drivers/iommu
parent59ce0515cdaf3b7d47893d12f61e51d691863788 (diff)
iommu/vt-d: Unify the way to process DMAR device scope array
Now we have a PCI bus notification based mechanism to update DMAR device scope array, we could extend the mechanism to support boot time initialization too, which will help to unify and simplify the implementation. 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.c163
-rw-r--r--drivers/iommu/intel-iommu.c71
2 files changed, 61 insertions, 173 deletions
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index bf6bfd1f69aa..b19f9f4c3584 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -60,6 +60,7 @@ LIST_HEAD(dmar_drhd_units);
60 60
61struct acpi_table_header * __initdata dmar_tbl; 61struct acpi_table_header * __initdata dmar_tbl;
62static acpi_size dmar_tbl_size; 62static acpi_size dmar_tbl_size;
63static int dmar_dev_scope_status = 1;
63 64
64static int alloc_iommu(struct dmar_drhd_unit *drhd); 65static int alloc_iommu(struct dmar_drhd_unit *drhd);
65static void free_iommu(struct intel_iommu *iommu); 66static void free_iommu(struct intel_iommu *iommu);
@@ -76,58 +77,6 @@ static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
76 list_add_rcu(&drhd->list, &dmar_drhd_units); 77 list_add_rcu(&drhd->list, &dmar_drhd_units);
77} 78}
78 79
79static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
80 struct pci_dev __rcu **dev, u16 segment)
81{
82 struct pci_bus *bus;
83 struct pci_dev *pdev = NULL;
84 struct acpi_dmar_pci_path *path;
85 int count;
86
87 bus = pci_find_bus(segment, scope->bus);
88 path = (struct acpi_dmar_pci_path *)(scope + 1);
89 count = (scope->length - sizeof(struct acpi_dmar_device_scope))
90 / sizeof(struct acpi_dmar_pci_path);
91
92 while (count) {
93 if (pdev)
94 pci_dev_put(pdev);
95 /*
96 * Some BIOSes list non-exist devices in DMAR table, just
97 * ignore it
98 */
99 if (!bus) {
100 pr_warn("Device scope bus [%d] not found\n", scope->bus);
101 break;
102 }
103 pdev = pci_get_slot(bus, PCI_DEVFN(path->device, path->function));
104 if (!pdev) {
105 /* warning will be printed below */
106 break;
107 }
108 path ++;
109 count --;
110 bus = pdev->subordinate;
111 }
112 if (!pdev) {
113 pr_warn("Device scope device [%04x:%02x:%02x.%02x] not found\n",
114 segment, scope->bus, path->device, path->function);
115 return 0;
116 }
117 if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \
118 pdev->subordinate) || (scope->entry_type == \
119 ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) {
120 pci_dev_put(pdev);
121 pr_warn("Device scope type does not match for %s\n",
122 pci_name(pdev));
123 return -EINVAL;
124 }
125
126 rcu_assign_pointer(*dev, pdev);
127
128 return 0;
129}
130
131void *dmar_alloc_dev_scope(void *start, void *end, int *cnt) 80void *dmar_alloc_dev_scope(void *start, void *end, int *cnt)
132{ 81{
133 struct acpi_dmar_device_scope *scope; 82 struct acpi_dmar_device_scope *scope;
@@ -150,35 +99,6 @@ void *dmar_alloc_dev_scope(void *start, void *end, int *cnt)
150 return kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL); 99 return kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL);
151} 100}
152 101
153int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
154 struct pci_dev __rcu ***devices, u16 segment)
155{
156 struct acpi_dmar_device_scope *scope;
157 int index, ret;
158
159 *devices = dmar_alloc_dev_scope(start, end, cnt);
160 if (*cnt == 0)
161 return 0;
162 else if (!*devices)
163 return -ENOMEM;
164
165 for (index = 0; start < end; start += scope->length) {
166 scope = start;
167 if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
168 scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) {
169 ret = dmar_parse_one_dev_scope(scope,
170 &(*devices)[index], segment);
171 if (ret) {
172 dmar_free_dev_scope(devices, cnt);
173 return ret;
174 }
175 index ++;
176 }
177 }
178
179 return 0;
180}
181
182void dmar_free_dev_scope(struct pci_dev __rcu ***devices, int *cnt) 102void dmar_free_dev_scope(struct pci_dev __rcu ***devices, int *cnt)
183{ 103{
184 int i; 104 int i;
@@ -220,6 +140,8 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event)
220 if (!info) { 140 if (!info) {
221 pr_warn("Out of memory when allocating notify_info " 141 pr_warn("Out of memory when allocating notify_info "
222 "for %s.\n", pci_name(dev)); 142 "for %s.\n", pci_name(dev));
143 if (dmar_dev_scope_status == 0)
144 dmar_dev_scope_status = -ENOMEM;
223 return NULL; 145 return NULL;
224 } 146 }
225 } 147 }
@@ -349,6 +271,8 @@ static int dmar_pci_bus_add_dev(struct dmar_pci_notify_info *info)
349 } 271 }
350 if (ret >= 0) 272 if (ret >= 0)
351 ret = dmar_iommu_notify_scope_dev(info); 273 ret = dmar_iommu_notify_scope_dev(info);
274 if (ret < 0 && dmar_dev_scope_status == 0)
275 dmar_dev_scope_status = ret;
352 276
353 return ret; 277 return ret;
354} 278}
@@ -418,9 +342,21 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
418 dmaru->reg_base_addr = drhd->address; 342 dmaru->reg_base_addr = drhd->address;
419 dmaru->segment = drhd->segment; 343 dmaru->segment = drhd->segment;
420 dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */ 344 dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
345 if (!dmaru->include_all) {
346 dmaru->devices = dmar_alloc_dev_scope((void *)(drhd + 1),
347 ((void *)drhd) + drhd->header.length,
348 &dmaru->devices_cnt);
349 if (dmaru->devices_cnt && dmaru->devices == NULL) {
350 kfree(dmaru);
351 return -ENOMEM;
352 }
353 }
421 354
422 ret = alloc_iommu(dmaru); 355 ret = alloc_iommu(dmaru);
423 if (ret) { 356 if (ret) {
357 if (!dmaru->include_all)
358 dmar_free_dev_scope(&dmaru->devices,
359 &dmaru->devices_cnt);
424 kfree(dmaru); 360 kfree(dmaru);
425 return ret; 361 return ret;
426 } 362 }
@@ -437,21 +373,6 @@ static void dmar_free_drhd(struct dmar_drhd_unit *dmaru)
437 kfree(dmaru); 373 kfree(dmaru);
438} 374}
439 375
440static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
441{
442 struct acpi_dmar_hardware_unit *drhd;
443
444 drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr;
445
446 if (dmaru->include_all)
447 return 0;
448
449 return dmar_parse_dev_scope((void *)(drhd + 1),
450 ((void *)drhd) + drhd->header.length,
451 &dmaru->devices_cnt, &dmaru->devices,
452 drhd->segment);
453}
454
455#ifdef CONFIG_ACPI_NUMA 376#ifdef CONFIG_ACPI_NUMA
456static int __init 377static int __init
457dmar_parse_one_rhsa(struct acpi_dmar_header *header) 378dmar_parse_one_rhsa(struct acpi_dmar_header *header)
@@ -665,34 +586,35 @@ out:
665 586
666int __init dmar_dev_scope_init(void) 587int __init dmar_dev_scope_init(void)
667{ 588{
668 static int dmar_dev_scope_initialized; 589 struct pci_dev *dev = NULL;
669 struct dmar_drhd_unit *drhd; 590 struct dmar_pci_notify_info *info;
670 int ret = -ENODEV;
671 591
672 if (dmar_dev_scope_initialized) 592 if (dmar_dev_scope_status != 1)
673 return dmar_dev_scope_initialized; 593 return dmar_dev_scope_status;
674 594
675 if (list_empty(&dmar_drhd_units)) 595 if (list_empty(&dmar_drhd_units)) {
676 goto fail; 596 dmar_dev_scope_status = -ENODEV;
597 } else {
598 dmar_dev_scope_status = 0;
599
600 for_each_pci_dev(dev) {
601 if (dev->is_virtfn)
602 continue;
603
604 info = dmar_alloc_pci_notify_info(dev,
605 BUS_NOTIFY_ADD_DEVICE);
606 if (!info) {
607 return dmar_dev_scope_status;
608 } else {
609 dmar_pci_bus_add_dev(info);
610 dmar_free_pci_notify_info(info);
611 }
612 }
677 613
678 for_each_drhd_unit(drhd) { 614 bus_register_notifier(&pci_bus_type, &dmar_pci_bus_nb);
679 ret = dmar_parse_dev(drhd);
680 if (ret)
681 goto fail;
682 } 615 }
683 616
684 ret = dmar_parse_rmrr_atsr_dev(); 617 return dmar_dev_scope_status;
685 if (ret)
686 goto fail;
687
688 bus_register_notifier(&pci_bus_type, &dmar_pci_bus_nb);
689
690 dmar_dev_scope_initialized = 1;
691 return 0;
692
693fail:
694 dmar_dev_scope_initialized = ret;
695 return ret;
696} 618}
697 619
698 620
@@ -1617,7 +1539,8 @@ static int __init dmar_free_unused_resources(void)
1617 if (irq_remapping_enabled || intel_iommu_enabled) 1539 if (irq_remapping_enabled || intel_iommu_enabled)
1618 return 0; 1540 return 0;
1619 1541
1620 bus_unregister_notifier(&pci_bus_type, &dmar_pci_bus_nb); 1542 if (dmar_dev_scope_status != 1 && !list_empty(&dmar_drhd_units))
1543 bus_unregister_notifier(&pci_bus_type, &dmar_pci_bus_nb);
1621 1544
1622 down_write(&dmar_global_lock); 1545 down_write(&dmar_global_lock);
1623 list_for_each_entry_safe(dmaru, dmaru_n, &dmar_drhd_units, list) { 1546 list_for_each_entry_safe(dmaru, dmaru_n, &dmar_drhd_units, list) {
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index d9c0dc5a5d35..dd576c067d0d 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3473,11 +3473,6 @@ static void __init init_iommu_pm_ops(void)
3473static inline void init_iommu_pm_ops(void) {} 3473static inline void init_iommu_pm_ops(void) {}
3474#endif /* CONFIG_PM */ 3474#endif /* CONFIG_PM */
3475 3475
3476static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
3477{
3478 list_add(&rmrr->list, &dmar_rmrr_units);
3479}
3480
3481 3476
3482int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header) 3477int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3483{ 3478{
@@ -3492,21 +3487,17 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header)
3492 rmrr = (struct acpi_dmar_reserved_memory *)header; 3487 rmrr = (struct acpi_dmar_reserved_memory *)header;
3493 rmrru->base_address = rmrr->base_address; 3488 rmrru->base_address = rmrr->base_address;
3494 rmrru->end_address = rmrr->end_address; 3489 rmrru->end_address = rmrr->end_address;
3490 rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
3491 ((void *)rmrr) + rmrr->header.length,
3492 &rmrru->devices_cnt);
3493 if (rmrru->devices_cnt && rmrru->devices == NULL) {
3494 kfree(rmrru);
3495 return -ENOMEM;
3496 }
3495 3497
3496 dmar_register_rmrr_unit(rmrru); 3498 list_add(&rmrru->list, &dmar_rmrr_units);
3497 return 0;
3498}
3499 3499
3500static int __init 3500 return 0;
3501rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
3502{
3503 struct acpi_dmar_reserved_memory *rmrr;
3504
3505 rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
3506 return dmar_parse_dev_scope((void *)(rmrr + 1),
3507 ((void *)rmrr) + rmrr->header.length,
3508 &rmrru->devices_cnt, &rmrru->devices,
3509 rmrr->segment);
3510} 3501}
3511 3502
3512int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr) 3503int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
@@ -3521,26 +3512,21 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
3521 3512
3522 atsru->hdr = hdr; 3513 atsru->hdr = hdr;
3523 atsru->include_all = atsr->flags & 0x1; 3514 atsru->include_all = atsr->flags & 0x1;
3515 if (!atsru->include_all) {
3516 atsru->devices = dmar_alloc_dev_scope((void *)(atsr + 1),
3517 (void *)atsr + atsr->header.length,
3518 &atsru->devices_cnt);
3519 if (atsru->devices_cnt && atsru->devices == NULL) {
3520 kfree(atsru);
3521 return -ENOMEM;
3522 }
3523 }
3524 3524
3525 list_add_rcu(&atsru->list, &dmar_atsr_units); 3525 list_add_rcu(&atsru->list, &dmar_atsr_units);
3526 3526
3527 return 0; 3527 return 0;
3528} 3528}
3529 3529
3530static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
3531{
3532 struct acpi_dmar_atsr *atsr;
3533
3534 if (atsru->include_all)
3535 return 0;
3536
3537 atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
3538 return dmar_parse_dev_scope((void *)(atsr + 1),
3539 (void *)atsr + atsr->header.length,
3540 &atsru->devices_cnt, &atsru->devices,
3541 atsr->segment);
3542}
3543
3544static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru) 3530static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
3545{ 3531{
3546 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt); 3532 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
@@ -3604,27 +3590,6 @@ out:
3604 return ret; 3590 return ret;
3605} 3591}
3606 3592
3607int __init dmar_parse_rmrr_atsr_dev(void)
3608{
3609 struct dmar_rmrr_unit *rmrr;
3610 struct dmar_atsr_unit *atsr;
3611 int ret;
3612
3613 list_for_each_entry(rmrr, &dmar_rmrr_units, list) {
3614 ret = rmrr_parse_dev(rmrr);
3615 if (ret)
3616 return ret;
3617 }
3618
3619 list_for_each_entry_rcu(atsr, &dmar_atsr_units, list) {
3620 ret = atsr_parse_dev(atsr);
3621 if (ret)
3622 return ret;
3623 }
3624
3625 return 0;
3626}
3627
3628int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info) 3593int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
3629{ 3594{
3630 int ret = 0; 3595 int ret = 0;