aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2014-01-06 01:18:20 -0500
committerJoerg Roedel <joro@8bytes.org>2014-01-09 06:43:40 -0500
commita868e6b7b661c3d3e7e681a16d0b205971987c99 (patch)
tree574ee2bcb16845f467f5892c9ac23805c0efa35c /drivers/iommu
parentb5f36d9e614135470da452f820f161c443d3c83c (diff)
iommu/vt-d: keep shared resources when failed to initialize iommu devices
Data structure drhd->iommu is shared between DMA remapping driver and interrupt remapping driver, so DMA remapping driver shouldn't release drhd->iommu when it failed to initialize IOMMU devices. Otherwise it may cause invalid memory access to the interrupt remapping driver. Sample stack dump: [ 13.315090] BUG: unable to handle kernel paging request at ffffc9000605a088 [ 13.323221] IP: [<ffffffff81461bac>] qi_submit_sync+0x15c/0x400 [ 13.330107] PGD 82f81e067 PUD c2f81e067 PMD 82e846067 PTE 0 [ 13.336818] Oops: 0002 [#1] SMP [ 13.340757] Modules linked in: [ 13.344422] CPU: 0 PID: 4 Comm: kworker/0:0 Not tainted 3.13.0-rc1-gerry+ #7 [ 13.352474] Hardware name: Intel Corporation LH Pass ........../SVRBD-ROW_T, BIOS SE5C600.86B.99.99.x059.091020121352 09/10/2012 [ 13.365659] Workqueue: events work_for_cpu_fn [ 13.370774] task: ffff88042ddf00d0 ti: ffff88042ddee000 task.ti: ffff88042dde e000 [ 13.379389] RIP: 0010:[<ffffffff81461bac>] [<ffffffff81461bac>] qi_submit_sy nc+0x15c/0x400 [ 13.389055] RSP: 0000:ffff88042ddef940 EFLAGS: 00010002 [ 13.395151] RAX: 00000000000005e0 RBX: 0000000000000082 RCX: 0000000200000025 [ 13.403308] RDX: ffffc9000605a000 RSI: 0000000000000010 RDI: ffff88042ddb8610 [ 13.411446] RBP: ffff88042ddef9a0 R08: 00000000000005d0 R09: 0000000000000001 [ 13.419599] R10: 0000000000000000 R11: 000000000000005d R12: 000000000000005c [ 13.427742] R13: ffff88102d84d300 R14: 0000000000000174 R15: ffff88042ddb4800 [ 13.435877] FS: 0000000000000000(0000) GS:ffff88043de00000(0000) knlGS:00000 00000000000 [ 13.445168] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 13.451749] CR2: ffffc9000605a088 CR3: 0000000001a0b000 CR4: 00000000000407f0 [ 13.459895] Stack: [ 13.462297] ffff88042ddb85d0 000000000000005d ffff88042ddef9b0 0000000000000 5d0 [ 13.471147] 00000000000005c0 ffff88042ddb8000 000000000000005c 0000000000000 015 [ 13.480001] ffff88042ddb4800 0000000000000282 ffff88042ddefa40 ffff88042ddef ac0 [ 13.488855] Call Trace: [ 13.491771] [<ffffffff8146848d>] modify_irte+0x9d/0xd0 [ 13.497778] [<ffffffff8146886d>] intel_setup_ioapic_entry+0x10d/0x290 [ 13.505250] [<ffffffff810a92a6>] ? trace_hardirqs_on_caller+0x16/0x1e0 [ 13.512824] [<ffffffff810346b0>] ? default_init_apic_ldr+0x60/0x60 [ 13.519998] [<ffffffff81468be0>] setup_ioapic_remapped_entry+0x20/0x30 [ 13.527566] [<ffffffff8103683a>] io_apic_setup_irq_pin+0x12a/0x2c0 [ 13.534742] [<ffffffff8136673b>] ? acpi_pci_irq_find_prt_entry+0x2b9/0x2d8 [ 13.544102] [<ffffffff81037fd5>] io_apic_setup_irq_pin_once+0x85/0xa0 [ 13.551568] [<ffffffff8103816f>] ? mp_find_ioapic_pin+0x8f/0xf0 [ 13.558434] [<ffffffff81038044>] io_apic_set_pci_routing+0x34/0x70 [ 13.565621] [<ffffffff8102f4cf>] mp_register_gsi+0xaf/0x1c0 [ 13.572111] [<ffffffff8102f5ee>] acpi_register_gsi_ioapic+0xe/0x10 [ 13.579286] [<ffffffff8102f33f>] acpi_register_gsi+0xf/0x20 [ 13.585779] [<ffffffff81366b86>] acpi_pci_irq_enable+0x171/0x1e3 [ 13.592764] [<ffffffff8146d771>] pcibios_enable_device+0x31/0x40 [ 13.599744] [<ffffffff81320e9b>] do_pci_enable_device+0x3b/0x60 [ 13.606633] [<ffffffff81322248>] pci_enable_device_flags+0xc8/0x120 [ 13.613887] [<ffffffff813222f3>] pci_enable_device+0x13/0x20 [ 13.620484] [<ffffffff8132fa7e>] pcie_port_device_register+0x1e/0x510 [ 13.627947] [<ffffffff810a92a6>] ? trace_hardirqs_on_caller+0x16/0x1e0 [ 13.635510] [<ffffffff810a947d>] ? trace_hardirqs_on+0xd/0x10 [ 13.642189] [<ffffffff813302b8>] pcie_portdrv_probe+0x58/0xc0 [ 13.648877] [<ffffffff81323ba5>] local_pci_probe+0x45/0xa0 [ 13.655266] [<ffffffff8106bc44>] work_for_cpu_fn+0x14/0x20 [ 13.661656] [<ffffffff8106fa79>] process_one_work+0x369/0x710 [ 13.668334] [<ffffffff8106fa02>] ? process_one_work+0x2f2/0x710 [ 13.675215] [<ffffffff81071d56>] ? worker_thread+0x46/0x690 [ 13.681714] [<ffffffff81072194>] worker_thread+0x484/0x690 [ 13.688109] [<ffffffff81071d10>] ? cancel_delayed_work_sync+0x20/0x20 [ 13.695576] [<ffffffff81079c60>] kthread+0xf0/0x110 [ 13.701300] [<ffffffff8108e7bf>] ? local_clock+0x3f/0x50 [ 13.707492] [<ffffffff81079b70>] ? kthread_create_on_node+0x250/0x250 [ 13.714959] [<ffffffff81574d2c>] ret_from_fork+0x7c/0xb0 [ 13.721152] [<ffffffff81079b70>] ? kthread_create_on_node+0x250/0x250 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.c56
-rw-r--r--drivers/iommu/intel-iommu.c13
2 files changed, 43 insertions, 26 deletions
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index ee4cb1906e45..b0df78f9cd28 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -53,6 +53,7 @@ struct acpi_table_header * __initdata dmar_tbl;
53static acpi_size dmar_tbl_size; 53static acpi_size dmar_tbl_size;
54 54
55static int alloc_iommu(struct dmar_drhd_unit *drhd); 55static int alloc_iommu(struct dmar_drhd_unit *drhd);
56static void free_iommu(struct intel_iommu *iommu);
56 57
57static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) 58static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
58{ 59{
@@ -205,25 +206,28 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
205 return 0; 206 return 0;
206} 207}
207 208
209static void dmar_free_drhd(struct dmar_drhd_unit *dmaru)
210{
211 if (dmaru->devices && dmaru->devices_cnt)
212 dmar_free_dev_scope(&dmaru->devices, &dmaru->devices_cnt);
213 if (dmaru->iommu)
214 free_iommu(dmaru->iommu);
215 kfree(dmaru);
216}
217
208static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru) 218static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
209{ 219{
210 struct acpi_dmar_hardware_unit *drhd; 220 struct acpi_dmar_hardware_unit *drhd;
211 int ret = 0;
212 221
213 drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr; 222 drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr;
214 223
215 if (dmaru->include_all) 224 if (dmaru->include_all)
216 return 0; 225 return 0;
217 226
218 ret = dmar_parse_dev_scope((void *)(drhd + 1), 227 return dmar_parse_dev_scope((void *)(drhd + 1),
219 ((void *)drhd) + drhd->header.length, 228 ((void *)drhd) + drhd->header.length,
220 &dmaru->devices_cnt, &dmaru->devices, 229 &dmaru->devices_cnt, &dmaru->devices,
221 drhd->segment); 230 drhd->segment);
222 if (ret) {
223 list_del(&dmaru->list);
224 kfree(dmaru);
225 }
226 return ret;
227} 231}
228 232
229#ifdef CONFIG_ACPI_NUMA 233#ifdef CONFIG_ACPI_NUMA
@@ -435,7 +439,7 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
435int __init dmar_dev_scope_init(void) 439int __init dmar_dev_scope_init(void)
436{ 440{
437 static int dmar_dev_scope_initialized; 441 static int dmar_dev_scope_initialized;
438 struct dmar_drhd_unit *drhd, *drhd_n; 442 struct dmar_drhd_unit *drhd;
439 int ret = -ENODEV; 443 int ret = -ENODEV;
440 444
441 if (dmar_dev_scope_initialized) 445 if (dmar_dev_scope_initialized)
@@ -444,7 +448,7 @@ int __init dmar_dev_scope_init(void)
444 if (list_empty(&dmar_drhd_units)) 448 if (list_empty(&dmar_drhd_units))
445 goto fail; 449 goto fail;
446 450
447 list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) { 451 list_for_each_entry(drhd, &dmar_drhd_units, list) {
448 ret = dmar_parse_dev(drhd); 452 ret = dmar_parse_dev(drhd);
449 if (ret) 453 if (ret)
450 goto fail; 454 goto fail;
@@ -725,12 +729,13 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
725 return err; 729 return err;
726} 730}
727 731
728void free_iommu(struct intel_iommu *iommu) 732static void free_iommu(struct intel_iommu *iommu)
729{ 733{
730 if (!iommu) 734 if (iommu->irq) {
731 return; 735 free_irq(iommu->irq, iommu);
732 736 irq_set_handler_data(iommu->irq, NULL);
733 free_dmar_iommu(iommu); 737 destroy_irq(iommu->irq);
738 }
734 739
735 if (iommu->reg) 740 if (iommu->reg)
736 unmap_iommu(iommu); 741 unmap_iommu(iommu);
@@ -1368,4 +1373,21 @@ int __init dmar_ir_support(void)
1368 return dmar->flags & 0x1; 1373 return dmar->flags & 0x1;
1369} 1374}
1370 1375
1376static int __init dmar_free_unused_resources(void)
1377{
1378 struct dmar_drhd_unit *dmaru, *dmaru_n;
1379
1380 /* DMAR units are in use */
1381 if (irq_remapping_enabled || intel_iommu_enabled)
1382 return 0;
1383
1384 list_for_each_entry_safe(dmaru, dmaru_n, &dmar_drhd_units, list) {
1385 list_del(&dmaru->list);
1386 dmar_free_drhd(dmaru);
1387 }
1388
1389 return 0;
1390}
1391
1392late_initcall(dmar_free_unused_resources);
1371IOMMU_INIT_POST(detect_intel_iommu); 1393IOMMU_INIT_POST(detect_intel_iommu);
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 7a0984d1c8d5..fd9e369a8cf7 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1265,7 +1265,7 @@ static int iommu_init_domains(struct intel_iommu *iommu)
1265static void domain_exit(struct dmar_domain *domain); 1265static void domain_exit(struct dmar_domain *domain);
1266static void vm_domain_exit(struct dmar_domain *domain); 1266static void vm_domain_exit(struct dmar_domain *domain);
1267 1267
1268void free_dmar_iommu(struct intel_iommu *iommu) 1268static void free_dmar_iommu(struct intel_iommu *iommu)
1269{ 1269{
1270 struct dmar_domain *domain; 1270 struct dmar_domain *domain;
1271 int i; 1271 int i;
@@ -1290,15 +1290,10 @@ void free_dmar_iommu(struct intel_iommu *iommu)
1290 if (iommu->gcmd & DMA_GCMD_TE) 1290 if (iommu->gcmd & DMA_GCMD_TE)
1291 iommu_disable_translation(iommu); 1291 iommu_disable_translation(iommu);
1292 1292
1293 if (iommu->irq) {
1294 /* This will mask the irq */
1295 free_irq(iommu->irq, iommu);
1296 irq_set_handler_data(iommu->irq, NULL);
1297 destroy_irq(iommu->irq);
1298 }
1299
1300 kfree(iommu->domains); 1293 kfree(iommu->domains);
1301 kfree(iommu->domain_ids); 1294 kfree(iommu->domain_ids);
1295 iommu->domains = NULL;
1296 iommu->domain_ids = NULL;
1302 1297
1303 g_iommus[iommu->seq_id] = NULL; 1298 g_iommus[iommu->seq_id] = NULL;
1304 1299
@@ -2627,7 +2622,7 @@ static int __init init_dmars(void)
2627 return 0; 2622 return 0;
2628error: 2623error:
2629 for_each_active_iommu(iommu, drhd) 2624 for_each_active_iommu(iommu, drhd)
2630 free_iommu(iommu); 2625 free_dmar_iommu(iommu);
2631 kfree(g_iommus); 2626 kfree(g_iommus);
2632 return ret; 2627 return ret;
2633} 2628}