Skip to content

Commit a868e6b

Browse files
Jiang Liujoergroedel
authored andcommitted
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+ coolya#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>
1 parent b5f36d9 commit a868e6b

4 files changed

Lines changed: 43 additions & 31 deletions

File tree

drivers/iommu/dmar.c

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct acpi_table_header * __initdata dmar_tbl;
5353
static acpi_size dmar_tbl_size;
5454

5555
static int alloc_iommu(struct dmar_drhd_unit *drhd);
56+
static void free_iommu(struct intel_iommu *iommu);
5657

5758
static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
5859
{
@@ -205,25 +206,28 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
205206
return 0;
206207
}
207208

209+
static 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+
208218
static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
209219
{
210220
struct acpi_dmar_hardware_unit *drhd;
211-
int ret = 0;
212221

213222
drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr;
214223

215224
if (dmaru->include_all)
216225
return 0;
217226

218-
ret = dmar_parse_dev_scope((void *)(drhd + 1),
219-
((void *)drhd) + drhd->header.length,
220-
&dmaru->devices_cnt, &dmaru->devices,
221-
drhd->segment);
222-
if (ret) {
223-
list_del(&dmaru->list);
224-
kfree(dmaru);
225-
}
226-
return ret;
227+
return dmar_parse_dev_scope((void *)(drhd + 1),
228+
((void *)drhd) + drhd->header.length,
229+
&dmaru->devices_cnt, &dmaru->devices,
230+
drhd->segment);
227231
}
228232

229233
#ifdef CONFIG_ACPI_NUMA
@@ -435,7 +439,7 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
435439
int __init dmar_dev_scope_init(void)
436440
{
437441
static int dmar_dev_scope_initialized;
438-
struct dmar_drhd_unit *drhd, *drhd_n;
442+
struct dmar_drhd_unit *drhd;
439443
int ret = -ENODEV;
440444

441445
if (dmar_dev_scope_initialized)
@@ -444,7 +448,7 @@ int __init dmar_dev_scope_init(void)
444448
if (list_empty(&dmar_drhd_units))
445449
goto fail;
446450

447-
list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) {
451+
list_for_each_entry(drhd, &dmar_drhd_units, list) {
448452
ret = dmar_parse_dev(drhd);
449453
if (ret)
450454
goto fail;
@@ -725,12 +729,13 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
725729
return err;
726730
}
727731

728-
void free_iommu(struct intel_iommu *iommu)
732+
static void free_iommu(struct intel_iommu *iommu)
729733
{
730-
if (!iommu)
731-
return;
732-
733-
free_dmar_iommu(iommu);
734+
if (iommu->irq) {
735+
free_irq(iommu->irq, iommu);
736+
irq_set_handler_data(iommu->irq, NULL);
737+
destroy_irq(iommu->irq);
738+
}
734739

735740
if (iommu->reg)
736741
unmap_iommu(iommu);
@@ -1368,4 +1373,21 @@ int __init dmar_ir_support(void)
13681373
return dmar->flags & 0x1;
13691374
}
13701375

1376+
static 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+
1392+
late_initcall(dmar_free_unused_resources);
13711393
IOMMU_INIT_POST(detect_intel_iommu);

drivers/iommu/intel-iommu.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,7 @@ static int iommu_init_domains(struct intel_iommu *iommu)
12651265
static void domain_exit(struct dmar_domain *domain);
12661266
static void vm_domain_exit(struct dmar_domain *domain);
12671267

1268-
void free_dmar_iommu(struct intel_iommu *iommu)
1268+
static void free_dmar_iommu(struct intel_iommu *iommu)
12691269
{
12701270
struct dmar_domain *domain;
12711271
int i;
@@ -1290,15 +1290,10 @@ void free_dmar_iommu(struct intel_iommu *iommu)
12901290
if (iommu->gcmd & DMA_GCMD_TE)
12911291
iommu_disable_translation(iommu);
12921292

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-
13001293
kfree(iommu->domains);
13011294
kfree(iommu->domain_ids);
1295+
iommu->domains = NULL;
1296+
iommu->domain_ids = NULL;
13021297

13031298
g_iommus[iommu->seq_id] = NULL;
13041299

@@ -2627,7 +2622,7 @@ static int __init init_dmars(void)
26272622
return 0;
26282623
error:
26292624
for_each_active_iommu(iommu, drhd)
2630-
free_iommu(iommu);
2625+
free_dmar_iommu(iommu);
26312626
kfree(g_iommus);
26322627
return ret;
26332628
}

include/linux/dma_remapping.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ struct root_entry;
2727

2828

2929
#ifdef CONFIG_INTEL_IOMMU
30-
extern void free_dmar_iommu(struct intel_iommu *iommu);
3130
extern int iommu_calculate_agaw(struct intel_iommu *iommu);
3231
extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu);
3332
extern int dmar_disabled;
@@ -41,9 +40,6 @@ static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
4140
{
4241
return 0;
4342
}
44-
static inline void free_dmar_iommu(struct intel_iommu *iommu)
45-
{
46-
}
4743
#define dmar_disabled (1)
4844
#define intel_iommu_enabled (0)
4945
#endif

include/linux/intel-iommu.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,6 @@ static inline void __iommu_flush_cache(
348348
extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
349349
extern int dmar_find_matched_atsr_unit(struct pci_dev *dev);
350350

351-
extern void free_iommu(struct intel_iommu *iommu);
352351
extern int dmar_enable_qi(struct intel_iommu *iommu);
353352
extern void dmar_disable_qi(struct intel_iommu *iommu);
354353
extern int dmar_reenable_qi(struct intel_iommu *iommu);

0 commit comments

Comments
 (0)