From 21004dcd3ba25163d620eddc703185cd50c89a93 Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Wed, 18 Dec 2013 12:01:46 +0530 Subject: iommu/vt-d: Mark functions as static in dmar.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark the functions check_zero_address() and dmar_get_fault_reason() as static in dmar.c because they are not used outside this file. This eliminates the following warnings in dmar.c: drivers/iommu/dmar.c:491:12: warning: no previous prototype for ‘check_zero_address’ [-Wmissing-prototypes] drivers/iommu/dmar.c:1116:13: warning: no previous prototype for ‘dmar_get_fault_reason’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iommu/dmar.c') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 8b452c9676d9..fb35d1bd19e1 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -488,7 +488,7 @@ static void warn_invalid_dmar(u64 addr, const char *message) dmi_get_system_info(DMI_PRODUCT_VERSION)); } -int __init check_zero_address(void) +static int __init check_zero_address(void) { struct acpi_table_dmar *dmar; struct acpi_dmar_header *entry_header; @@ -1113,7 +1113,7 @@ static const char *irq_remap_fault_reasons[] = #define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1) -const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) +static const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) { if (fault_reason >= 0x20 && (fault_reason - 0x20 < ARRAY_SIZE(irq_remap_fault_reasons))) { -- cgit From ada4d4b2a32e9f63d4dcb9f69578473408f4622c Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 6 Jan 2014 14:18:09 +0800 Subject: iommu/vt-d: fix PCI device reference leakage on error recovery path Function dmar_parse_dev_scope() should release the PCI device reference count gained in function dmar_parse_one_dev_scope() on error recovery, otherwise it will cause PCI device object leakage. This patch also introduces dmar_free_dev_scope(), which will be used to support DMAR device hotplug. Reviewed-by: Yijing Wang Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/iommu/dmar.c') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index fb35d1bd19e1..28d93b68ff02 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -100,7 +100,6 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope, if (!pdev) { pr_warn("Device scope device [%04x:%02x:%02x.%02x] not found\n", segment, scope->bus, path->device, path->function); - *dev = NULL; return 0; } if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \ @@ -151,7 +150,7 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, ret = dmar_parse_one_dev_scope(scope, &(*devices)[index], segment); if (ret) { - kfree(*devices); + dmar_free_dev_scope(devices, cnt); return ret; } index ++; @@ -162,6 +161,17 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt, return 0; } +void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt) +{ + if (*devices && *cnt) { + while (--*cnt >= 0) + pci_dev_put((*devices)[*cnt]); + kfree(*devices); + *devices = NULL; + *cnt = 0; + } +} + /** * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition * structure which uniquely represent one DMA remapping hardware unit -- cgit From b977e73a837963ad73d24db4ca7b71040791868c Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 6 Jan 2014 14:18:14 +0800 Subject: iommu/vt-d, trivial: check suitable flag in function detect_intel_iommu() Flag irq_remapping_enabled is only set by intel_enable_irq_remapping(), which is called after detect_intel_iommu(). So moving pr_info() from detect_intel_iommu() to intel_enable_irq_remapping(), which also slightly simplifies implementation. Reviewed-by: Yijing Wang Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/iommu/dmar.c') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 28d93b68ff02..e4c3ea022428 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -556,14 +556,6 @@ int __init detect_intel_iommu(void) if (ret) ret = check_zero_address(); { - struct acpi_table_dmar *dmar; - - dmar = (struct acpi_table_dmar *) dmar_tbl; - - if (ret && irq_remapping_enabled && cpu_has_x2apic && - dmar->flags & 0x1) - pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); - if (ret && !no_iommu && !iommu_detected && !dmar_disabled) { iommu_detected = 1; /* Make sure ACS will be enabled */ -- cgit From b8a2d2881e6682464f6a832eea4c9be298d70c41 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 6 Jan 2014 14:18:15 +0800 Subject: iommu/vt-d, trivial: clean up unused code Remove dead code from VT-d related files. Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel Conflicts: drivers/iommu/dmar.c --- drivers/iommu/dmar.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/iommu/dmar.c') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index e4c3ea022428..5a4e9afad3af 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1113,8 +1113,6 @@ static const char *irq_remap_fault_reasons[] = "Blocked an interrupt request due to source-id verification failure", }; -#define MAX_FAULT_REASON_IDX (ARRAY_SIZE(fault_reason_strings) - 1) - static const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) { if (fault_reason >= 0x20 && (fault_reason - 0x20 < -- cgit From 694835dc227ad203886457aa447025d09b2f7523 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 6 Jan 2014 14:18:16 +0800 Subject: iommu/vt-d: mark internal functions as static Functions alloc_iommu() and parse_ioapics_under_ir() are only used internally, so mark them as static. [Joerg: Made detect_intel_iommu() non-static again for IA64] Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/iommu/dmar.c') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 5a4e9afad3af..e3c03bb7c374 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -52,6 +52,8 @@ LIST_HEAD(dmar_drhd_units); struct acpi_table_header * __initdata dmar_tbl; static acpi_size dmar_tbl_size; +static int alloc_iommu(struct dmar_drhd_unit *drhd); + static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) { /* @@ -649,7 +651,7 @@ out: return err; } -int alloc_iommu(struct dmar_drhd_unit *drhd) +static int alloc_iommu(struct dmar_drhd_unit *drhd) { struct intel_iommu *iommu; u32 ver, sts; @@ -1366,4 +1368,5 @@ int __init dmar_ir_support(void) return 0; return dmar->flags & 0x1; } + IOMMU_INIT_POST(detect_intel_iommu); -- cgit From 7c9197791a0cbbbb0f74aade3339f8e5890fbd15 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 6 Jan 2014 14:18:18 +0800 Subject: iommu/vt-d, trivial: simplify code with existing macros Simplify vt-d related code with existing macros and introduce a new macro for_each_active_drhd_unit() to enumerate all active DRHD unit. Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/iommu/dmar.c') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index e3c03bb7c374..ee4cb1906e45 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1305,15 +1305,14 @@ int dmar_set_interrupt(struct intel_iommu *iommu) int __init enable_drhd_fault_handling(void) { struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; /* * Enable fault control interrupt. */ - for_each_drhd_unit(drhd) { - int ret; - struct intel_iommu *iommu = drhd->iommu; + for_each_iommu(iommu, drhd) { u32 fault_status; - ret = dmar_set_interrupt(iommu); + int ret = dmar_set_interrupt(iommu); if (ret) { pr_err("DRHD %Lx: failed to enable fault, interrupt, ret %d\n", -- cgit From a868e6b7b661c3d3e7e681a16d0b205971987c99 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 6 Jan 2014 14:18:20 +0800 Subject: 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: [] 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:[] [] 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] [] modify_irte+0x9d/0xd0 [ 13.497778] [] intel_setup_ioapic_entry+0x10d/0x290 [ 13.505250] [] ? trace_hardirqs_on_caller+0x16/0x1e0 [ 13.512824] [] ? default_init_apic_ldr+0x60/0x60 [ 13.519998] [] setup_ioapic_remapped_entry+0x20/0x30 [ 13.527566] [] io_apic_setup_irq_pin+0x12a/0x2c0 [ 13.534742] [] ? acpi_pci_irq_find_prt_entry+0x2b9/0x2d8 [ 13.544102] [] io_apic_setup_irq_pin_once+0x85/0xa0 [ 13.551568] [] ? mp_find_ioapic_pin+0x8f/0xf0 [ 13.558434] [] io_apic_set_pci_routing+0x34/0x70 [ 13.565621] [] mp_register_gsi+0xaf/0x1c0 [ 13.572111] [] acpi_register_gsi_ioapic+0xe/0x10 [ 13.579286] [] acpi_register_gsi+0xf/0x20 [ 13.585779] [] acpi_pci_irq_enable+0x171/0x1e3 [ 13.592764] [] pcibios_enable_device+0x31/0x40 [ 13.599744] [] do_pci_enable_device+0x3b/0x60 [ 13.606633] [] pci_enable_device_flags+0xc8/0x120 [ 13.613887] [] pci_enable_device+0x13/0x20 [ 13.620484] [] pcie_port_device_register+0x1e/0x510 [ 13.627947] [] ? trace_hardirqs_on_caller+0x16/0x1e0 [ 13.635510] [] ? trace_hardirqs_on+0xd/0x10 [ 13.642189] [] pcie_portdrv_probe+0x58/0xc0 [ 13.648877] [] local_pci_probe+0x45/0xa0 [ 13.655266] [] work_for_cpu_fn+0x14/0x20 [ 13.661656] [] process_one_work+0x369/0x710 [ 13.668334] [] ? process_one_work+0x2f2/0x710 [ 13.675215] [] ? worker_thread+0x46/0x690 [ 13.681714] [] worker_thread+0x484/0x690 [ 13.688109] [] ? cancel_delayed_work_sync+0x20/0x20 [ 13.695576] [] kthread+0xf0/0x110 [ 13.701300] [] ? local_clock+0x3f/0x50 [ 13.707492] [] ? kthread_create_on_node+0x250/0x250 [ 13.714959] [] ret_from_fork+0x7c/0xb0 [ 13.721152] [] ? kthread_create_on_node+0x250/0x250 Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 56 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 17 deletions(-) (limited to 'drivers/iommu/dmar.c') 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; static acpi_size dmar_tbl_size; static int alloc_iommu(struct dmar_drhd_unit *drhd); +static void free_iommu(struct intel_iommu *iommu); static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) { @@ -205,25 +206,28 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header) return 0; } +static void dmar_free_drhd(struct dmar_drhd_unit *dmaru) +{ + if (dmaru->devices && dmaru->devices_cnt) + dmar_free_dev_scope(&dmaru->devices, &dmaru->devices_cnt); + if (dmaru->iommu) + free_iommu(dmaru->iommu); + kfree(dmaru); +} + static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru) { struct acpi_dmar_hardware_unit *drhd; - int ret = 0; drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr; if (dmaru->include_all) return 0; - ret = dmar_parse_dev_scope((void *)(drhd + 1), - ((void *)drhd) + drhd->header.length, - &dmaru->devices_cnt, &dmaru->devices, - drhd->segment); - if (ret) { - list_del(&dmaru->list); - kfree(dmaru); - } - return ret; + return dmar_parse_dev_scope((void *)(drhd + 1), + ((void *)drhd) + drhd->header.length, + &dmaru->devices_cnt, &dmaru->devices, + drhd->segment); } #ifdef CONFIG_ACPI_NUMA @@ -435,7 +439,7 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev) int __init dmar_dev_scope_init(void) { static int dmar_dev_scope_initialized; - struct dmar_drhd_unit *drhd, *drhd_n; + struct dmar_drhd_unit *drhd; int ret = -ENODEV; if (dmar_dev_scope_initialized) @@ -444,7 +448,7 @@ int __init dmar_dev_scope_init(void) if (list_empty(&dmar_drhd_units)) goto fail; - list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) { + list_for_each_entry(drhd, &dmar_drhd_units, list) { ret = dmar_parse_dev(drhd); if (ret) goto fail; @@ -725,12 +729,13 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd) return err; } -void free_iommu(struct intel_iommu *iommu) +static void free_iommu(struct intel_iommu *iommu) { - if (!iommu) - return; - - free_dmar_iommu(iommu); + if (iommu->irq) { + free_irq(iommu->irq, iommu); + irq_set_handler_data(iommu->irq, NULL); + destroy_irq(iommu->irq); + } if (iommu->reg) unmap_iommu(iommu); @@ -1368,4 +1373,21 @@ int __init dmar_ir_support(void) return dmar->flags & 0x1; } +static int __init dmar_free_unused_resources(void) +{ + struct dmar_drhd_unit *dmaru, *dmaru_n; + + /* DMAR units are in use */ + if (irq_remapping_enabled || intel_iommu_enabled) + return 0; + + list_for_each_entry_safe(dmaru, dmaru_n, &dmar_drhd_units, list) { + list_del(&dmaru->list); + dmar_free_drhd(dmaru); + } + + return 0; +} + +late_initcall(dmar_free_unused_resources); IOMMU_INIT_POST(detect_intel_iommu); -- cgit From a84da70b7ba0c5236fccf25115acefc235ed65f9 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 6 Jan 2014 14:18:23 +0800 Subject: iommu/vt-d: release invalidation queue when destroying IOMMU unit Release associated invalidation queue when destroying IOMMU unit to avoid memory leak. Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/iommu/dmar.c') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index b0df78f9cd28..726cfe296d99 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -737,6 +737,12 @@ static void free_iommu(struct intel_iommu *iommu) destroy_irq(iommu->irq); } + if (iommu->qi) { + free_page((unsigned long)iommu->qi->desc); + kfree(iommu->qi->desc_status); + kfree(iommu->qi); + } + if (iommu->reg) unmap_iommu(iommu); -- cgit From cc05301fd54f3e166aedf24e39f6731c4dec0451 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 6 Jan 2014 14:18:24 +0800 Subject: iommu/vt-d: fix wrong return value of dmar_table_init() If dmar_table_init() fails to detect DMAR table on the first call, it will return wrong result on following calls because it always sets dmar_table_initialized no matter if succeeds or fails to detect DMAR table. Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers/iommu/dmar.c') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 726cfe296d99..753c7ecf66a8 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -472,24 +472,23 @@ int __init dmar_table_init(void) static int dmar_table_initialized; int ret; - if (dmar_table_initialized) - return 0; - - dmar_table_initialized = 1; - - ret = parse_dmar_table(); - if (ret) { - if (ret != -ENODEV) - pr_info("parse DMAR table failure.\n"); - return ret; - } + if (dmar_table_initialized == 0) { + ret = parse_dmar_table(); + if (ret < 0) { + if (ret != -ENODEV) + pr_info("parse DMAR table failure.\n"); + } else if (list_empty(&dmar_drhd_units)) { + pr_info("No DMAR devices found\n"); + ret = -ENODEV; + } - if (list_empty(&dmar_drhd_units)) { - pr_info("No DMAR devices found\n"); - return -ENODEV; + if (ret < 0) + dmar_table_initialized = ret; + else + dmar_table_initialized = 1; } - return 0; + return dmar_table_initialized < 0 ? dmar_table_initialized : 0; } static void warn_invalid_dmar(u64 addr, const char *message) -- cgit From b707cb027edf5b7ff1b8637c184b9a58d74e5159 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 6 Jan 2014 14:18:26 +0800 Subject: iommu/vt-d, trivial: clean sparse warnings Clean up most sparse warnings in Intel DMA and interrupt remapping drivers. Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/iommu/dmar.c') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 753c7ecf66a8..158156543410 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -572,7 +572,7 @@ int __init detect_intel_iommu(void) x86_init.iommu.iommu_init = intel_iommu_init; #endif } - early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size); + early_acpi_os_unmap_memory((void __iomem *)dmar_tbl, dmar_tbl_size); dmar_tbl = NULL; return ret ? 1 : -ENODEV; @@ -1064,7 +1064,7 @@ int dmar_enable_qi(struct intel_iommu *iommu) desc_page = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, 0); if (!desc_page) { kfree(qi); - iommu->qi = 0; + iommu->qi = NULL; return -ENOMEM; } @@ -1074,7 +1074,7 @@ int dmar_enable_qi(struct intel_iommu *iommu) if (!qi->desc_status) { free_page((unsigned long) qi->desc); kfree(qi); - iommu->qi = 0; + iommu->qi = NULL; return -ENOMEM; } -- cgit