linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers
@ 2014-01-06  6:18 Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 01/20] iommu/vt-d: use dedicated bitmap to track remapping entry allocation status Jiang Liu
                   ` (20 more replies)
  0 siblings, 21 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

This patchset includes several bugfixes and code improvements for
Intel DMA remapping and interrupt remapping drivers. It's also a
preparation for Intel IOMMU device hotplug.

It applies to the latest mainstream kernel on top of
	commit 7e3528c3660a2e8602abc7858b0994d611f74bc3

It has been tested on Intel SandyBridge and Romley-4S platforms.

Thanks!

V2->V3:
1) address review comments of last round

Jiang Liu (20):
  iommu/vt-d: use dedicated bitmap to track remapping entry allocation
    status
  iommu/vt-d: fix PCI device reference leakage on error recovery path
  iommu/vt-d: fix a race window in allocating domain ID for virtual
    machines
  iommu/vt-d: fix resource leakage on error recovery path in
    iommu_init_domains()
  iommu/vt-d, trivial: refine support of 64bit guest address
  iommu/vt-d, trivial: print correct domain id of static identity
    domain
  iommu/vt-d, trivial: check suitable flag in function
    detect_intel_iommu()
  iommu/vt-d, trivial: clean up unused code
  iommu/vt-d: mark internal functions as static
  iommu/vt-d, trivial: use defined macro instead of hardcoding
  iommu/vt-d, trivial: simplify code with existing macros
  iommu/vt-d: fix invalid memory access when freeing DMAR irq
  iommu/vt-d: keep shared resources when failed to initialize iommu
    devices
  iommu/vt-d: avoid double free in error recovery path
  iommu/vt-d: fix access after free issue in function free_dmar_iommu()
  iommu/vt-d: release invalidation queue when destroying IOMMU unit
  iommu/vt-d: fix wrong return value of dmar_table_init()
  iommu/vt-d, PCI, trivial: use dev_is_pci() instead of hardcoding
  iommu/vt-d, trivial: clean sparse warnings
  iommu/vt-d: free all resources if failed to initialize DMARs

 drivers/iommu/dmar.c                |  137 +++++++++++++--------
 drivers/iommu/intel-iommu.c         |  232 ++++++++++++++---------------------
 drivers/iommu/intel_irq_remapping.c |   98 +++++++--------
 drivers/iommu/irq_remapping.c       |    6 +-
 include/linux/dma_remapping.h       |    4 -
 include/linux/dmar.h                |   17 +--
 include/linux/intel-iommu.h         |    3 +-
 7 files changed, 229 insertions(+), 268 deletions(-)

-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 01/20] iommu/vt-d: use dedicated bitmap to track remapping entry allocation status
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 02/20] iommu/vt-d: fix PCI device reference leakage on error recovery path Jiang Liu
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Currently Intel interrupt remapping drivers uses the "present" flag bit
in remapping entry to track whether an entry is allocated or not.
It works as follow:
1) allocate a remapping entry and set its "present" flag bit to 1
2) compose other fields for the entry
3) update the remapping entry with the composed value

The remapping hardware may access the entry between step 1 and step 3,
which then observers an entry with the "present" flag set but random
values in all other fields.

This patch introduces a dedicated bitmap to track remapping entry
allocation status instead of sharing the "present" flag with hardware,
thus eliminate the race window. It also simplifies the implementation.

Tested-and-reviewed-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel_irq_remapping.c |   55 +++++++++++++++++------------------
 include/linux/intel-iommu.h         |    1 +
 2 files changed, 27 insertions(+), 29 deletions(-)

diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index bab10b1..deef3d4 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -72,7 +72,6 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
 	u16 index, start_index;
 	unsigned int mask = 0;
 	unsigned long flags;
-	int i;
 
 	if (!count || !irq_iommu)
 		return -1;
@@ -96,32 +95,17 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
 	}
 
 	raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
-	do {
-		for (i = index; i < index + count; i++)
-			if  (table->base[i].present)
-				break;
-		/* empty index found */
-		if (i == index + count)
-			break;
-
-		index = (index + count) % INTR_REMAP_TABLE_ENTRIES;
-
-		if (index == start_index) {
-			raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-			printk(KERN_ERR "can't allocate an IRTE\n");
-			return -1;
-		}
-	} while (1);
-
-	for (i = index; i < index + count; i++)
-		table->base[i].present = 1;
-
-	cfg->remapped = 1;
-	irq_iommu->iommu = iommu;
-	irq_iommu->irte_index =  index;
-	irq_iommu->sub_handle = 0;
-	irq_iommu->irte_mask = mask;
-
+	index = bitmap_find_free_region(table->bitmap,
+					INTR_REMAP_TABLE_ENTRIES, mask);
+	if (index < 0) {
+		pr_warn("IR%d: can't allocate an IRTE\n", iommu->seq_id);
+	} else {
+		cfg->remapped = 1;
+		irq_iommu->iommu = iommu;
+		irq_iommu->irte_index =  index;
+		irq_iommu->sub_handle = 0;
+		irq_iommu->irte_mask = mask;
+	}
 	raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 
 	return index;
@@ -254,6 +238,8 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
 		set_64bit(&entry->low, 0);
 		set_64bit(&entry->high, 0);
 	}
+	bitmap_release_region(iommu->ir_table->bitmap, index,
+			      irq_iommu->irte_mask);
 
 	return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
 }
@@ -453,6 +439,7 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu, int mode)
 {
 	struct ir_table *ir_table;
 	struct page *pages;
+	unsigned long *bitmap;
 
 	ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table),
 					     GFP_ATOMIC);
@@ -464,13 +451,23 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu, int mode)
 				 INTR_REMAP_PAGE_ORDER);
 
 	if (!pages) {
-		printk(KERN_ERR "failed to allocate pages of order %d\n",
-		       INTR_REMAP_PAGE_ORDER);
+		pr_err("IR%d: failed to allocate pages of order %d\n",
+		       iommu->seq_id, INTR_REMAP_PAGE_ORDER);
 		kfree(iommu->ir_table);
 		return -ENOMEM;
 	}
 
+	bitmap = kcalloc(BITS_TO_LONGS(INTR_REMAP_TABLE_ENTRIES),
+			 sizeof(long), GFP_ATOMIC);
+	if (bitmap == NULL) {
+		pr_err("IR%d: failed to allocate bitmap\n", iommu->seq_id);
+		__free_pages(pages, INTR_REMAP_PAGE_ORDER);
+		kfree(ir_table);
+		return -ENOMEM;
+	}
+
 	ir_table->base = page_address(pages);
+	ir_table->bitmap = bitmap;
 
 	iommu_set_irq_remapping(iommu, mode);
 	return 0;
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index d380c5e..de1e5e9 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -288,6 +288,7 @@ struct q_inval {
 
 struct ir_table {
 	struct irte *base;
+	unsigned long *bitmap;
 };
 #endif
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 02/20] iommu/vt-d: fix PCI device reference leakage on error recovery path
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 01/20] iommu/vt-d: use dedicated bitmap to track remapping entry allocation status Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-08  8:53   ` [PATCH] iommu/vt-d: fix compilation error when CONFIG_INTEL_IOMMU is unset Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 03/20] iommu/vt-d: fix a race window in allocating domain ID for virtual machines Jiang Liu
                   ` (18 subsequent siblings)
  20 siblings, 1 reply; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

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 <wangyijing@huawei.com>
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/dmar.c |   14 ++++++++++++--
 include/linux/dmar.h |    1 +
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 8b452c9..c17dbf7 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
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index b029d1a..8adfce0 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -159,6 +159,7 @@ extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
 extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
 extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
 				struct pci_dev ***devices, u16 segment);
+extern void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt);
 extern int intel_iommu_init(void);
 #else /* !CONFIG_INTEL_IOMMU: */
 static inline int intel_iommu_init(void) { return -ENODEV; }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 03/20] iommu/vt-d: fix a race window in allocating domain ID for virtual machines
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 01/20] iommu/vt-d: use dedicated bitmap to track remapping entry allocation status Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 02/20] iommu/vt-d: fix PCI device reference leakage on error recovery path Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 04/20] iommu/vt-d: fix resource leakage on error recovery path in iommu_init_domains() Jiang Liu
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine, Alex Williamson

Function intel_iommu_domain_init() may be concurrently called by upper
layer without serialization, so use atomic_t to protect domain id
allocation.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Cc: Alex Williamson <alex.williamson@redhat.com>
---
 drivers/iommu/intel-iommu.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 43b9bfe..b8e3b48 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3877,7 +3877,7 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
 }
 
 /* domain id for virtual machine, it won't be set in context */
-static unsigned long vm_domid;
+static atomic_t vm_domid = ATOMIC_INIT(0);
 
 static struct dmar_domain *iommu_alloc_vm_domain(void)
 {
@@ -3887,7 +3887,7 @@ static struct dmar_domain *iommu_alloc_vm_domain(void)
 	if (!domain)
 		return NULL;
 
-	domain->id = vm_domid++;
+	domain->id = atomic_inc_return(&vm_domid);
 	domain->nid = -1;
 	memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
 	domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 04/20] iommu/vt-d: fix resource leakage on error recovery path in iommu_init_domains()
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (2 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 03/20] iommu/vt-d: fix a race window in allocating domain ID for virtual machines Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 05/20] iommu/vt-d, trivial: refine support of 64bit guest address Jiang Liu
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Release allocated resources on error recovery path in function
iommu_init_domains().

Also improve printk messages in iommu_init_domains().

Acked-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel-iommu.c |   12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index b8e3b48..e32d815 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1255,8 +1255,8 @@ static int iommu_init_domains(struct intel_iommu *iommu)
 	unsigned long nlongs;
 
 	ndomains = cap_ndoms(iommu->cap);
-	pr_debug("IOMMU %d: Number of Domains supported <%ld>\n", iommu->seq_id,
-			ndomains);
+	pr_debug("IOMMU%d: Number of Domains supported <%ld>\n",
+		 iommu->seq_id, ndomains);
 	nlongs = BITS_TO_LONGS(ndomains);
 
 	spin_lock_init(&iommu->lock);
@@ -1266,13 +1266,17 @@ static int iommu_init_domains(struct intel_iommu *iommu)
 	 */
 	iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
 	if (!iommu->domain_ids) {
-		printk(KERN_ERR "Allocating domain id array failed\n");
+		pr_err("IOMMU%d: allocating domain id array failed\n",
+		       iommu->seq_id);
 		return -ENOMEM;
 	}
 	iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
 			GFP_KERNEL);
 	if (!iommu->domains) {
-		printk(KERN_ERR "Allocating domain array failed\n");
+		pr_err("IOMMU%d: allocating domain array failed\n",
+		       iommu->seq_id);
+		kfree(iommu->domain_ids);
+		iommu->domain_ids = NULL;
 		return -ENOMEM;
 	}
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 05/20] iommu/vt-d, trivial: refine support of 64bit guest address
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (3 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 04/20] iommu/vt-d: fix resource leakage on error recovery path in iommu_init_domains() Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 06/20] iommu/vt-d, trivial: print correct domain id of static identity domain Jiang Liu
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams,
	Vinod Koul, Jiri Kosina
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

In Intel IOMMU driver, it calculate page table level from adjusted guest
address width as 'level = (agaw - 30) / 9', which assumes (agaw -30)
could be divided by 9. On the other hand, 64bit is a valid agaw and
(64 - 30) can't be divided by 9, so it needs special handling.

This patch enhances Intel IOMMU driver to correctly handle 64bit agaw.
It's mainly for code readability because there's no hardware supporting
64bit agaw yet.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel-iommu.c |   11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index e32d815..b2e73c2 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -63,6 +63,7 @@
 #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
 
 #define MAX_AGAW_WIDTH 64
+#define MAX_AGAW_PFN_WIDTH	(MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
 
 #define __DOMAIN_MAX_PFN(gaw)  ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
 #define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
@@ -106,12 +107,12 @@ static inline int agaw_to_level(int agaw)
 
 static inline int agaw_to_width(int agaw)
 {
-	return 30 + agaw * LEVEL_STRIDE;
+	return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
 }
 
 static inline int width_to_agaw(int width)
 {
-	return (width - 30) / LEVEL_STRIDE;
+	return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
 }
 
 static inline unsigned int level_to_offset_bits(int level)
@@ -141,7 +142,7 @@ static inline unsigned long align_to_level(unsigned long pfn, int level)
 
 static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
 {
-	return  1 << ((lvl - 1) * LEVEL_STRIDE);
+	return  1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
 }
 
 /* VT-d pages must always be _smaller_ than MM pages. Otherwise things
@@ -865,7 +866,6 @@ static int dma_pte_clear_range(struct dmar_domain *domain,
 	int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
 	unsigned int large_page = 1;
 	struct dma_pte *first_pte, *pte;
-	int order;
 
 	BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
 	BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
@@ -890,8 +890,7 @@ static int dma_pte_clear_range(struct dmar_domain *domain,
 
 	} while (start_pfn && start_pfn <= last_pfn);
 
-	order = (large_page - 1) * 9;
-	return order;
+	return min_t(int, (large_page - 1) * 9, MAX_AGAW_PFN_WIDTH);
 }
 
 static void dma_pte_free_level(struct dmar_domain *domain, int level,
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 06/20] iommu/vt-d, trivial: print correct domain id of static identity domain
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (4 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 05/20] iommu/vt-d, trivial: refine support of 64bit guest address Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 07/20] iommu/vt-d, trivial: check suitable flag in function detect_intel_iommu() Jiang Liu
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams,
	Vinod Koul, Jiri Kosina
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Field si_domain->id is set by iommu_attach_domain(), so we should only
print domain id for static identity domain after calling
iommu_attach_domain(si_domain, iommu), otherwise it's always zero.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel-iommu.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index b2e73c2..3a0cf5d 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2248,8 +2248,6 @@ static int __init si_domain_init(int hw)
 	if (!si_domain)
 		return -EFAULT;
 
-	pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
-
 	for_each_active_iommu(iommu, drhd) {
 		ret = iommu_attach_domain(si_domain, iommu);
 		if (ret) {
@@ -2264,6 +2262,8 @@ static int __init si_domain_init(int hw)
 	}
 
 	si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
+	pr_debug("IOMMU: identity mapping domain is domain %d\n",
+		 si_domain->id);
 
 	if (hw)
 		return 0;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 07/20] iommu/vt-d, trivial: check suitable flag in function detect_intel_iommu()
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (5 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 06/20] iommu/vt-d, trivial: print correct domain id of static identity domain Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 08/20] iommu/vt-d, trivial: clean up unused code Jiang Liu
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams,
	Vinod Koul, Jiri Kosina
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

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 <wangyijing@huawei.com>
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/dmar.c                |    8 --------
 drivers/iommu/intel_irq_remapping.c |    2 ++
 2 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index c17dbf7..5e7ba3b 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 */
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index deef3d4..2616e8a 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -561,6 +561,8 @@ static int __init intel_enable_irq_remapping(void)
 	}
 
 	if (x2apic_present) {
+		pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
+
 		eim = !dmar_x2apic_optout();
 		if (!eim)
 			printk(KERN_WARNING
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 08/20] iommu/vt-d, trivial: clean up unused code
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (6 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 07/20] iommu/vt-d, trivial: check suitable flag in function detect_intel_iommu() Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 09/20] iommu/vt-d: mark internal functions as static Jiang Liu
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams,
	Vinod Koul, Jiri Kosina
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Remove dead code from VT-d related files.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/dmar.c        |    2 --
 drivers/iommu/intel-iommu.c |   25 -------------------------
 2 files changed, 27 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 5e7ba3b..f5f7b7d 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)
-
 const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
 {
 	if (fault_reason >= 0x20 && (fault_reason - 0x20 <
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 3a0cf5d..751db33 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -289,26 +289,6 @@ static inline void dma_clear_pte(struct dma_pte *pte)
 	pte->val = 0;
 }
 
-static inline void dma_set_pte_readable(struct dma_pte *pte)
-{
-	pte->val |= DMA_PTE_READ;
-}
-
-static inline void dma_set_pte_writable(struct dma_pte *pte)
-{
-	pte->val |= DMA_PTE_WRITE;
-}
-
-static inline void dma_set_pte_snp(struct dma_pte *pte)
-{
-	pte->val |= DMA_PTE_SNP;
-}
-
-static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
-{
-	pte->val = (pte->val & ~3) | (prot & 3);
-}
-
 static inline u64 dma_pte_addr(struct dma_pte *pte)
 {
 #ifdef CONFIG_64BIT
@@ -319,11 +299,6 @@ static inline u64 dma_pte_addr(struct dma_pte *pte)
 #endif
 }
 
-static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
-{
-	pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
-}
-
 static inline bool dma_pte_present(struct dma_pte *pte)
 {
 	return (pte->val & 3) != 0;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 09/20] iommu/vt-d: mark internal functions as static
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (7 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 08/20] iommu/vt-d, trivial: clean up unused code Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-07 15:25   ` Joerg Roedel
  2014-01-06  6:18 ` [Patch Part1 V3 10/20] iommu/vt-d, trivial: use defined macro instead of hardcoding Jiang Liu
                   ` (11 subsequent siblings)
  20 siblings, 1 reply; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Function detect_intel_iommu()/alloc_iommu()/parse_ioapics_under_ir()
are only used internally, so mark them as static.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/dmar.c                |    9 ++++++---
 drivers/iommu/intel_irq_remapping.c |    4 +++-
 include/linux/dmar.h                |   12 +-----------
 include/linux/intel-iommu.h         |    1 -
 4 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index f5f7b7d..f02a4fd 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)
 {
 	/*
@@ -498,7 +500,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;
@@ -548,7 +550,7 @@ failed:
 	return 0;
 }
 
-int __init detect_intel_iommu(void)
+static int __init detect_intel_iommu(void)
 {
 	int ret;
 
@@ -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);
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 2616e8a..6712f1e 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -40,6 +40,8 @@ static int ir_ioapic_num, ir_hpet_num;
 
 static DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
 
+static int __init parse_ioapics_under_ir(void);
+
 static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
 {
 	struct irq_cfg *cfg = irq_get_chip_data(irq);
@@ -773,7 +775,7 @@ static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
  * Finds the assocaition between IOAPIC's and its Interrupt-remapping
  * hardware unit.
  */
-int __init parse_ioapics_under_ir(void)
+static int __init parse_ioapics_under_ir(void)
 {
 	struct dmar_drhd_unit *drhd;
 	int ir_supported = 0;
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 8adfce0..f614357 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -33,6 +33,7 @@ struct acpi_dmar_header;
 #define DMAR_X2APIC_OPT_OUT	0x2
 
 struct intel_iommu;
+
 #ifdef CONFIG_DMAR_TABLE
 extern struct acpi_table_header *dmar_tbl;
 struct dmar_drhd_unit {
@@ -62,19 +63,8 @@ extern struct list_head dmar_drhd_units;
 
 extern int dmar_table_init(void);
 extern int dmar_dev_scope_init(void);
-
-/* Intel IOMMU detection */
-extern int detect_intel_iommu(void);
 extern int enable_drhd_fault_handling(void);
-
-extern int parse_ioapics_under_ir(void);
-extern int alloc_iommu(struct dmar_drhd_unit *);
 #else
-static inline int detect_intel_iommu(void)
-{
-	return -ENODEV;
-}
-
 static inline int dmar_table_init(void)
 {
 	return -ENODEV;
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index de1e5e9..f2c4114 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -348,7 +348,6 @@ static inline void __iommu_flush_cache(
 extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
 extern int dmar_find_matched_atsr_unit(struct pci_dev *dev);
 
-extern int alloc_iommu(struct dmar_drhd_unit *drhd);
 extern void free_iommu(struct intel_iommu *iommu);
 extern int dmar_enable_qi(struct intel_iommu *iommu);
 extern void dmar_disable_qi(struct intel_iommu *iommu);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 10/20] iommu/vt-d, trivial: use defined macro instead of hardcoding
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (8 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 09/20] iommu/vt-d: mark internal functions as static Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 11/20] iommu/vt-d, trivial: simplify code with existing macros Jiang Liu
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams,
	Vinod Koul, Jiri Kosina
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Use defined macro instead of hardcoding in function set_ioapic_sid()
for readability.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel_irq_remapping.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 6712f1e..451c7f1 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -324,7 +324,7 @@ static int set_ioapic_sid(struct irte *irte, int apic)
 		return -1;
 	}
 
-	set_irte_sid(irte, 1, 0, sid);
+	set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, sid);
 
 	return 0;
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 11/20] iommu/vt-d, trivial: simplify code with existing macros
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (9 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 10/20] iommu/vt-d, trivial: use defined macro instead of hardcoding Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 12/20] iommu/vt-d: fix invalid memory access when freeing DMAR irq Jiang Liu
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams,
	Vinod Koul, Jiri Kosina
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

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 <jiang.liu@linux.intel.com>
---
 drivers/iommu/dmar.c                |    7 ++---
 drivers/iommu/intel-iommu.c         |   55 ++++++++---------------------------
 drivers/iommu/intel_irq_remapping.c |   31 +++++++-------------
 include/linux/dmar.h                |    4 +++
 4 files changed, 29 insertions(+), 68 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index f02a4fd..7ecc7b8 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",
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 751db33..9e67954 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -628,9 +628,7 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
 	struct dmar_drhd_unit *drhd = NULL;
 	int i;
 
-	for_each_drhd_unit(drhd) {
-		if (drhd->ignored)
-			continue;
+	for_each_active_drhd_unit(drhd) {
 		if (segment != drhd->segment)
 			continue;
 
@@ -2470,11 +2468,7 @@ static int __init init_dmars(void)
 		goto error;
 	}
 
-	for_each_drhd_unit(drhd) {
-		if (drhd->ignored)
-			continue;
-
-		iommu = drhd->iommu;
+	for_each_active_iommu(iommu, drhd) {
 		g_iommus[iommu->seq_id] = iommu;
 
 		ret = iommu_init_domains(iommu);
@@ -2498,12 +2492,7 @@ static int __init init_dmars(void)
 	/*
 	 * Start from the sane iommu hardware state.
 	 */
-	for_each_drhd_unit(drhd) {
-		if (drhd->ignored)
-			continue;
-
-		iommu = drhd->iommu;
-
+	for_each_active_iommu(iommu, drhd) {
 		/*
 		 * If the queued invalidation is already initialized by us
 		 * (for example, while enabling interrupt-remapping) then
@@ -2523,12 +2512,7 @@ static int __init init_dmars(void)
 		dmar_disable_qi(iommu);
 	}
 
-	for_each_drhd_unit(drhd) {
-		if (drhd->ignored)
-			continue;
-
-		iommu = drhd->iommu;
-
+	for_each_active_iommu(iommu, drhd) {
 		if (dmar_enable_qi(iommu)) {
 			/*
 			 * Queued Invalidate not enabled, use Register Based
@@ -2611,17 +2595,16 @@ static int __init init_dmars(void)
 	 *   global invalidate iotlb
 	 *   enable translation
 	 */
-	for_each_drhd_unit(drhd) {
+	for_each_iommu(iommu, drhd) {
 		if (drhd->ignored) {
 			/*
 			 * we always have to disable PMRs or DMA may fail on
 			 * this device
 			 */
 			if (force_on)
-				iommu_disable_protect_mem_regions(drhd->iommu);
+				iommu_disable_protect_mem_regions(iommu);
 			continue;
 		}
-		iommu = drhd->iommu;
 
 		iommu_flush_write_buffer(iommu);
 
@@ -2643,12 +2626,8 @@ static int __init init_dmars(void)
 
 	return 0;
 error:
-	for_each_drhd_unit(drhd) {
-		if (drhd->ignored)
-			continue;
-		iommu = drhd->iommu;
+	for_each_active_iommu(iommu, drhd)
 		free_iommu(iommu);
-	}
 	kfree(g_iommus);
 	return ret;
 }
@@ -3296,9 +3275,9 @@ static void __init init_no_remapping_devices(void)
 		}
 	}
 
-	for_each_drhd_unit(drhd) {
+	for_each_active_drhd_unit(drhd) {
 		int i;
-		if (drhd->ignored || drhd->include_all)
+		if (drhd->include_all)
 			continue;
 
 		for (i = 0; i < drhd->devices_cnt; i++)
@@ -3647,6 +3626,7 @@ int __init intel_iommu_init(void)
 {
 	int ret = 0;
 	struct dmar_drhd_unit *drhd;
+	struct intel_iommu *iommu;
 
 	/* VT-d is required for a TXT/tboot launch, so enforce that */
 	force_on = tboot_force_iommu();
@@ -3660,16 +3640,9 @@ int __init intel_iommu_init(void)
 	/*
 	 * Disable translation if already enabled prior to OS handover.
 	 */
-	for_each_drhd_unit(drhd) {
-		struct intel_iommu *iommu;
-
-		if (drhd->ignored)
-			continue;
-
-		iommu = drhd->iommu;
+	for_each_active_iommu(iommu, drhd)
 		if (iommu->gcmd & DMA_GCMD_TE)
 			iommu_disable_translation(iommu);
-	}
 
 	if (dmar_dev_scope_init() < 0) {
 		if (force_on)
@@ -3912,11 +3885,7 @@ static void iommu_free_vm_domain(struct dmar_domain *domain)
 	unsigned long i;
 	unsigned long ndomains;
 
-	for_each_drhd_unit(drhd) {
-		if (drhd->ignored)
-			continue;
-		iommu = drhd->iommu;
-
+	for_each_active_iommu(iommu, drhd) {
 		ndomains = cap_ndoms(iommu->cap);
 		for_each_set_bit(i, iommu->domain_ids, ndomains) {
 			if (iommu->domains[i] == domain) {
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 451c7f1..ea425de 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -520,6 +520,7 @@ static int __init dmar_x2apic_optout(void)
 static int __init intel_irq_remapping_supported(void)
 {
 	struct dmar_drhd_unit *drhd;
+	struct intel_iommu *iommu;
 
 	if (disable_irq_remap)
 		return 0;
@@ -538,12 +539,9 @@ static int __init intel_irq_remapping_supported(void)
 	if (!dmar_ir_support())
 		return 0;
 
-	for_each_drhd_unit(drhd) {
-		struct intel_iommu *iommu = drhd->iommu;
-
+	for_each_iommu(iommu, drhd)
 		if (!ecap_ir_support(iommu->ecap))
 			return 0;
-	}
 
 	return 1;
 }
@@ -551,6 +549,7 @@ static int __init intel_irq_remapping_supported(void)
 static int __init intel_enable_irq_remapping(void)
 {
 	struct dmar_drhd_unit *drhd;
+	struct intel_iommu *iommu;
 	bool x2apic_present;
 	int setup = 0;
 	int eim = 0;
@@ -573,9 +572,7 @@ static int __init intel_enable_irq_remapping(void)
 				"Use 'intremap=no_x2apic_optout' to override BIOS request.\n");
 	}
 
-	for_each_drhd_unit(drhd) {
-		struct intel_iommu *iommu = drhd->iommu;
-
+	for_each_iommu(iommu, drhd) {
 		/*
 		 * If the queued invalidation is already initialized,
 		 * shouldn't disable it.
@@ -600,9 +597,7 @@ static int __init intel_enable_irq_remapping(void)
 	/*
 	 * check for the Interrupt-remapping support
 	 */
-	for_each_drhd_unit(drhd) {
-		struct intel_iommu *iommu = drhd->iommu;
-
+	for_each_iommu(iommu, drhd) {
 		if (!ecap_ir_support(iommu->ecap))
 			continue;
 
@@ -616,10 +611,8 @@ static int __init intel_enable_irq_remapping(void)
 	/*
 	 * Enable queued invalidation for all the DRHD's.
 	 */
-	for_each_drhd_unit(drhd) {
-		int ret;
-		struct intel_iommu *iommu = drhd->iommu;
-		ret = dmar_enable_qi(iommu);
+	for_each_iommu(iommu, drhd) {
+		int ret = dmar_enable_qi(iommu);
 
 		if (ret) {
 			printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
@@ -632,9 +625,7 @@ static int __init intel_enable_irq_remapping(void)
 	/*
 	 * Setup Interrupt-remapping for all the DRHD's now.
 	 */
-	for_each_drhd_unit(drhd) {
-		struct intel_iommu *iommu = drhd->iommu;
-
+	for_each_iommu(iommu, drhd) {
 		if (!ecap_ir_support(iommu->ecap))
 			continue;
 
@@ -778,19 +769,17 @@ static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
 static int __init parse_ioapics_under_ir(void)
 {
 	struct dmar_drhd_unit *drhd;
+	struct intel_iommu *iommu;
 	int ir_supported = 0;
 	int ioapic_idx;
 
-	for_each_drhd_unit(drhd) {
-		struct intel_iommu *iommu = drhd->iommu;
-
+	for_each_iommu(iommu, drhd)
 		if (ecap_ir_support(iommu->ecap)) {
 			if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu))
 				return -1;
 
 			ir_supported = 1;
 		}
-	}
 
 	if (!ir_supported)
 		return 0;
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index f614357..bd5026b 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -53,6 +53,10 @@ extern struct list_head dmar_drhd_units;
 #define for_each_drhd_unit(drhd) \
 	list_for_each_entry(drhd, &dmar_drhd_units, list)
 
+#define for_each_active_drhd_unit(drhd)					\
+	list_for_each_entry(drhd, &dmar_drhd_units, list)		\
+		if (drhd->ignored) {} else
+
 #define for_each_active_iommu(i, drhd)					\
 	list_for_each_entry(drhd, &dmar_drhd_units, list)		\
 		if (i=drhd->iommu, drhd->ignored) {} else
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 12/20] iommu/vt-d: fix invalid memory access when freeing DMAR irq
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (10 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 11/20] iommu/vt-d, trivial: simplify code with existing macros Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 13/20] iommu/vt-d: keep shared resources when failed to initialize iommu devices Jiang Liu
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

In function free_dmar_iommu(), it sets IRQ handler data to NULL
before calling free_irq(), which will cause invalid memory access
because free_irq() will access IRQ handler data when calling
function dmar_msi_mask(). So only set IRQ handler data to NULL
after calling free_irq().

Sample stack dump:
[   13.094010] BUG: unable to handle kernel NULL pointer dereference at 0000000000000048
[   13.103215] IP: [<ffffffff810a97cd>] __lock_acquire+0x4d/0x12a0
[   13.110104] PGD 0
[   13.112614] Oops: 0000 [#1] SMP
[   13.116585] Modules linked in:
[   13.120260] CPU: 60 PID: 1 Comm: swapper/0 Tainted: G        W    3.13.0-rc1-gerry+ #9
[   13.129367] Hardware name: Intel Corporation LH Pass ........../SVRBD-ROW_T, BIOS SE5C600.86B.99.99.x059.091020121352 09/10/2012
[   13.142555] task: ffff88042dd38010 ti: ffff88042dd32000 task.ti: ffff88042dd32000
[   13.151179] RIP: 0010:[<ffffffff810a97cd>]  [<ffffffff810a97cd>] __lock_acquire+0x4d/0x12a0
[   13.160867] RSP: 0000:ffff88042dd33b78  EFLAGS: 00010046
[   13.166969] RAX: 0000000000000046 RBX: 0000000000000002 RCX: 0000000000000000
[   13.175122] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000048
[   13.183274] RBP: ffff88042dd33bd8 R08: 0000000000000002 R09: 0000000000000001
[   13.191417] R10: 0000000000000000 R11: 0000000000000001 R12: ffff88042dd38010
[   13.199571] R13: 0000000000000000 R14: 0000000000000048 R15: 0000000000000000
[   13.207725] FS:  0000000000000000(0000) GS:ffff88103f200000(0000) knlGS:0000000000000000
[   13.217014] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   13.223596] CR2: 0000000000000048 CR3: 0000000001a0b000 CR4: 00000000000407e0
[   13.231747] Stack:
[   13.234160]  0000000000000004 0000000000000046 ffff88042dd33b98 ffffffff810a567d
[   13.243059]  ffff88042dd33c08 ffffffff810bb14c ffffffff828995a0 0000000000000046
[   13.251969]  0000000000000000 0000000000000000 0000000000000002 0000000000000000
[   13.260862] Call Trace:
[   13.263775]  [<ffffffff810a567d>] ? trace_hardirqs_off+0xd/0x10
[   13.270571]  [<ffffffff810bb14c>] ? vprintk_emit+0x23c/0x570
[   13.277058]  [<ffffffff810ab1e3>] lock_acquire+0x93/0x120
[   13.283269]  [<ffffffff814623f7>] ? dmar_msi_mask+0x47/0x70
[   13.289677]  [<ffffffff8156b449>] _raw_spin_lock_irqsave+0x49/0x90
[   13.296748]  [<ffffffff814623f7>] ? dmar_msi_mask+0x47/0x70
[   13.303153]  [<ffffffff814623f7>] dmar_msi_mask+0x47/0x70
[   13.309354]  [<ffffffff810c0d93>] irq_shutdown+0x53/0x60
[   13.315467]  [<ffffffff810bdd9d>] __free_irq+0x26d/0x280
[   13.321580]  [<ffffffff810be920>] free_irq+0xf0/0x180
[   13.327395]  [<ffffffff81466591>] free_dmar_iommu+0x271/0x2b0
[   13.333996]  [<ffffffff810a947d>] ? trace_hardirqs_on+0xd/0x10
[   13.340696]  [<ffffffff81461a17>] free_iommu+0x17/0x50
[   13.346597]  [<ffffffff81dc75a5>] init_dmars+0x691/0x77a
[   13.352711]  [<ffffffff81dc7afd>] intel_iommu_init+0x351/0x438
[   13.359400]  [<ffffffff81d8a711>] ? iommu_setup+0x27d/0x27d
[   13.365806]  [<ffffffff81d8a739>] pci_iommu_init+0x28/0x52
[   13.372114]  [<ffffffff81000342>] do_one_initcall+0x122/0x180
[   13.378707]  [<ffffffff81077738>] ? parse_args+0x1e8/0x320
[   13.385016]  [<ffffffff81d850e8>] kernel_init_freeable+0x1e1/0x26c
[   13.392100]  [<ffffffff81d84833>] ? do_early_param+0x88/0x88
[   13.398596]  [<ffffffff8154f8b0>] ? rest_init+0xd0/0xd0
[   13.404614]  [<ffffffff8154f8be>] kernel_init+0xe/0x130
[   13.410626]  [<ffffffff81574d6c>] ret_from_fork+0x7c/0xb0
[   13.416829]  [<ffffffff8154f8b0>] ? rest_init+0xd0/0xd0
[   13.422842] Code: ec 99 00 85 c0 8b 05 53 05 a5 00 41 0f 45 d8 85 c0 0f 84 ff 00 00 00 8b 05 99 f9 7e 01 49 89 fe 41 89 f7 85 c0 0f 84 03 01 00 00 <49> 8b 06 be 01 00 00 00 48 3d c0 0e 01 82 0f 44 de 41 83 ff 01
[   13.450191] RIP  [<ffffffff810a97cd>] __lock_acquire+0x4d/0x12a0
[   13.458598]  RSP <ffff88042dd33b78>
[   13.462671] CR2: 0000000000000048
[   13.466551] ---[ end trace c5bd26a37c81d760 ]---

Reviewed-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel-iommu.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 9e67954..ee536ad 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1291,9 +1291,9 @@ void free_dmar_iommu(struct intel_iommu *iommu)
 		iommu_disable_translation(iommu);
 
 	if (iommu->irq) {
-		irq_set_handler_data(iommu->irq, NULL);
 		/* This will mask the irq */
 		free_irq(iommu->irq, iommu);
+		irq_set_handler_data(iommu->irq, NULL);
 		destroy_irq(iommu->irq);
 	}
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 13/20] iommu/vt-d: keep shared resources when failed to initialize iommu devices
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (11 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 12/20] iommu/vt-d: fix invalid memory access when freeing DMAR irq Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 14/20] iommu/vt-d: avoid double free in error recovery path Jiang Liu
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

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>
---
 drivers/iommu/dmar.c          |   56 ++++++++++++++++++++++++++++-------------
 drivers/iommu/intel-iommu.c   |   13 +++-------
 include/linux/dma_remapping.h |    4 ---
 include/linux/intel-iommu.h   |    1 -
 4 files changed, 43 insertions(+), 31 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 7ecc7b8..302e037 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);
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index ee536ad..60fa821 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)
 static void domain_exit(struct dmar_domain *domain);
 static void vm_domain_exit(struct dmar_domain *domain);
 
-void free_dmar_iommu(struct intel_iommu *iommu)
+static void free_dmar_iommu(struct intel_iommu *iommu)
 {
 	struct dmar_domain *domain;
 	int i;
@@ -1290,15 +1290,10 @@ void free_dmar_iommu(struct intel_iommu *iommu)
 	if (iommu->gcmd & DMA_GCMD_TE)
 		iommu_disable_translation(iommu);
 
-	if (iommu->irq) {
-		/* This will mask the irq */
-		free_irq(iommu->irq, iommu);
-		irq_set_handler_data(iommu->irq, NULL);
-		destroy_irq(iommu->irq);
-	}
-
 	kfree(iommu->domains);
 	kfree(iommu->domain_ids);
+	iommu->domains = NULL;
+	iommu->domain_ids = NULL;
 
 	g_iommus[iommu->seq_id] = NULL;
 
@@ -2627,7 +2622,7 @@ static int __init init_dmars(void)
 	return 0;
 error:
 	for_each_active_iommu(iommu, drhd)
-		free_iommu(iommu);
+		free_dmar_iommu(iommu);
 	kfree(g_iommus);
 	return ret;
 }
diff --git a/include/linux/dma_remapping.h b/include/linux/dma_remapping.h
index 57c9a8a..7ac17f5 100644
--- a/include/linux/dma_remapping.h
+++ b/include/linux/dma_remapping.h
@@ -27,7 +27,6 @@ struct root_entry;
 
 
 #ifdef CONFIG_INTEL_IOMMU
-extern void free_dmar_iommu(struct intel_iommu *iommu);
 extern int iommu_calculate_agaw(struct intel_iommu *iommu);
 extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu);
 extern int dmar_disabled;
@@ -41,9 +40,6 @@ static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
 {
 	return 0;
 }
-static inline void free_dmar_iommu(struct intel_iommu *iommu)
-{
-}
 #define dmar_disabled	(1)
 #define intel_iommu_enabled (0)
 #endif
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index f2c4114..2c4bed5 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -348,7 +348,6 @@ static inline void __iommu_flush_cache(
 extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
 extern int dmar_find_matched_atsr_unit(struct pci_dev *dev);
 
-extern void free_iommu(struct intel_iommu *iommu);
 extern int dmar_enable_qi(struct intel_iommu *iommu);
 extern void dmar_disable_qi(struct intel_iommu *iommu);
 extern int dmar_reenable_qi(struct intel_iommu *iommu);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 14/20] iommu/vt-d: avoid double free in error recovery path
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (12 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 13/20] iommu/vt-d: keep shared resources when failed to initialize iommu devices Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 15/20] iommu/vt-d: fix access after free issue in function free_dmar_iommu() Jiang Liu
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

The g_iommus array will be freed twice when failed to initialize IOMMU
devices, so fix the double free.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel-iommu.c |   14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 60fa821..ccf7304 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1295,19 +1295,10 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
 	iommu->domains = NULL;
 	iommu->domain_ids = NULL;
 
-	g_iommus[iommu->seq_id] = NULL;
-
-	/* if all iommus are freed, free g_iommus */
-	for (i = 0; i < g_num_of_iommus; i++) {
-		if (g_iommus[i])
-			break;
-	}
-
-	if (i == g_num_of_iommus)
-		kfree(g_iommus);
-
 	/* free context mapping */
 	free_context_table(iommu);
+
+	g_iommus[iommu->seq_id] = NULL;
 }
 
 static struct dmar_domain *alloc_domain(void)
@@ -2624,6 +2615,7 @@ error:
 	for_each_active_iommu(iommu, drhd)
 		free_dmar_iommu(iommu);
 	kfree(g_iommus);
+	g_iommus = NULL;
 	return ret;
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 15/20] iommu/vt-d: fix access after free issue in function free_dmar_iommu()
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (13 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 14/20] iommu/vt-d: avoid double free in error recovery path Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 16/20] iommu/vt-d: release invalidation queue when destroying IOMMU unit Jiang Liu
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Function free_dmar_iommu() may access domain->iommu_lock by
	spin_unlock_irqrestore(&domain->iommu_lock, flags);
after freeing corresponding domain structure.

Sample stack dump:
[    8.912818] =========================
[    8.917072] [ BUG: held lock freed! ]
[    8.921335] 3.13.0-rc1-gerry+ #12 Not tainted
[    8.926375] -------------------------
[    8.930629] swapper/0/1 is freeing memory ffff880c23b56040-ffff880c23b5613f, with a lock still held there!
[    8.941675]  (&(&domain->iommu_lock)->rlock){......}, at: [<ffffffff81dc775c>] init_dmars+0x72c/0x95b
[    8.952582] 1 lock held by swapper/0/1:
[    8.957031]  #0:  (&(&domain->iommu_lock)->rlock){......}, at: [<ffffffff81dc775c>] init_dmars+0x72c/0x95b
[    8.968487]
[    8.968487] stack backtrace:
[    8.973602] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.13.0-rc1-gerry+ #12
[    8.981556] Hardware name: Intel Corporation LH Pass ........../SVRBD-ROW_T, BIOS SE5C600.86B.99.99.x059.091020121352 09/10/2012
[    8.994742]  ffff880c23b56040 ffff88042dd33c98 ffffffff815617fd ffff88042dd38b28
[    9.003566]  ffff88042dd33cd0 ffffffff810a977a ffff880c23b56040 0000000000000086
[    9.012403]  ffff88102c4923c0 ffff88042ddb4800 ffffffff81b1e8c0 ffff88042dd33d28
[    9.021240] Call Trace:
[    9.024138]  [<ffffffff815617fd>] dump_stack+0x4d/0x66
[    9.030057]  [<ffffffff810a977a>] debug_check_no_locks_freed+0x15a/0x160
[    9.037723]  [<ffffffff811aa1c2>] kmem_cache_free+0x62/0x5b0
[    9.044225]  [<ffffffff81465e27>] domain_exit+0x197/0x1c0
[    9.050418]  [<ffffffff81dc7788>] init_dmars+0x758/0x95b
[    9.056527]  [<ffffffff81dc7dfa>] intel_iommu_init+0x351/0x438
[    9.063207]  [<ffffffff81d8a711>] ? iommu_setup+0x27d/0x27d
[    9.069601]  [<ffffffff81d8a739>] pci_iommu_init+0x28/0x52
[    9.075910]  [<ffffffff81000342>] do_one_initcall+0x122/0x180
[    9.082509]  [<ffffffff81077738>] ? parse_args+0x1e8/0x320
[    9.088815]  [<ffffffff81d850e8>] kernel_init_freeable+0x1e1/0x26c
[    9.095895]  [<ffffffff81d84833>] ? do_early_param+0x88/0x88
[    9.102396]  [<ffffffff8154f580>] ? rest_init+0xd0/0xd0
[    9.108410]  [<ffffffff8154f58e>] kernel_init+0xe/0x130
[    9.114423]  [<ffffffff81574a2c>] ret_from_fork+0x7c/0xb0
[    9.120612]  [<ffffffff8154f580>] ? rest_init+0xd0/0xd0

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel-iommu.c |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index ccf7304..03780eb 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1268,7 +1268,7 @@ static void vm_domain_exit(struct dmar_domain *domain);
 static void free_dmar_iommu(struct intel_iommu *iommu)
 {
 	struct dmar_domain *domain;
-	int i;
+	int i, count;
 	unsigned long flags;
 
 	if ((iommu->domains) && (iommu->domain_ids)) {
@@ -1277,13 +1277,14 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
 			clear_bit(i, iommu->domain_ids);
 
 			spin_lock_irqsave(&domain->iommu_lock, flags);
-			if (--domain->iommu_count == 0) {
+			count = --domain->iommu_count;
+			spin_unlock_irqrestore(&domain->iommu_lock, flags);
+			if (count == 0) {
 				if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
 					vm_domain_exit(domain);
 				else
 					domain_exit(domain);
 			}
-			spin_unlock_irqrestore(&domain->iommu_lock, flags);
 		}
 	}
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 16/20] iommu/vt-d: release invalidation queue when destroying IOMMU unit
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (14 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 15/20] iommu/vt-d: fix access after free issue in function free_dmar_iommu() Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 17/20] iommu/vt-d: fix wrong return value of dmar_table_init() Jiang Liu
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Release associated invalidation queue when destroying IOMMU unit
to avoid memory leak.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/dmar.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index 302e037..bb635fb 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);
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 17/20] iommu/vt-d: fix wrong return value of dmar_table_init()
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (15 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 16/20] iommu/vt-d: release invalidation queue when destroying IOMMU unit Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 18/20] iommu/vt-d, PCI, trivial: use dev_is_pci() instead of hardcoding Jiang Liu
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

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 <jiang.liu@linux.intel.com>
---
 drivers/iommu/dmar.c |   29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index bb635fb..c4b271d 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)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 18/20] iommu/vt-d, PCI, trivial: use dev_is_pci() instead of hardcoding
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (16 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 17/20] iommu/vt-d: fix wrong return value of dmar_table_init() Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 19/20] iommu/vt-d, trivial: clean sparse warnings Jiang Liu
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams,
	Vinod Koul, Jiri Kosina
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Use helper dev_is_pci() instead of hardcoding.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel-iommu.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 03780eb..6fce741 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2703,7 +2703,7 @@ static int iommu_no_mapping(struct device *dev)
 	struct pci_dev *pdev;
 	int found;
 
-	if (unlikely(dev->bus != &pci_bus_type))
+	if (unlikely(!dev_is_pci(dev)))
 		return 1;
 
 	pdev = to_pci_dev(dev);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 19/20] iommu/vt-d, trivial: clean sparse warnings
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (17 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 18/20] iommu/vt-d, PCI, trivial: use dev_is_pci() instead of hardcoding Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-08  8:57   ` [PATCH] iommu/vt-d: fix compilation error for IA64 platform Jiang Liu
  2014-01-06  6:18 ` [Patch Part1 V3 20/20] iommu/vt-d: free all resources if failed to initialize DMARs Jiang Liu
  2014-01-07 16:09 ` [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Joerg Roedel
  20 siblings, 1 reply; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams,
	Vinod Koul, Jiri Kosina
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Clean up most sparse warnings in Intel DMA and interrupt remapping
drivers.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/dmar.c                |    8 ++++----
 drivers/iommu/intel-iommu.c         |    4 ++--
 drivers/iommu/intel_irq_remapping.c |    4 ++--
 drivers/iommu/irq_remapping.c       |    6 +++---
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index c4b271d..248332e 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -572,7 +572,7 @@ static 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;
 	}
 
@@ -1125,7 +1125,7 @@ static const char *irq_remap_fault_reasons[] =
 	"Blocked an interrupt request due to source-id verification failure",
 };
 
-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))) {
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 6fce741..c28e9fe 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -382,7 +382,7 @@ struct device_domain_info {
 
 static void flush_unmaps_timeout(unsigned long data);
 
-DEFINE_TIMER(unmap_timer,  flush_unmaps_timeout, 0, 0);
+static DEFINE_TIMER(unmap_timer,  flush_unmaps_timeout, 0, 0);
 
 #define HIGH_WATER_MARK 250
 struct deferred_flush_tables {
@@ -3127,7 +3127,7 @@ static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
 	return !dma_addr;
 }
 
-struct dma_map_ops intel_dma_ops = {
+static struct dma_map_ops intel_dma_ops = {
 	.alloc = intel_alloc_coherent,
 	.free = intel_free_coherent,
 	.map_sg = intel_map_sg,
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index ea425de..f307a3f 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -48,7 +48,7 @@ static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
 	return cfg ? &cfg->irq_2_iommu : NULL;
 }
 
-int get_irte(int irq, struct irte *entry)
+static int get_irte(int irq, struct irte *entry)
 {
 	struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
 	unsigned long flags;
@@ -797,7 +797,7 @@ static int __init parse_ioapics_under_ir(void)
 	return 1;
 }
 
-int __init ir_dev_scope_init(void)
+static int __init ir_dev_scope_init(void)
 {
 	if (!irq_remapping_enabled)
 		return 0;
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index 39f81ae..228632c9 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -150,7 +150,7 @@ static int irq_remapping_setup_msi_irqs(struct pci_dev *dev,
 		return do_setup_msix_irqs(dev, nvec);
 }
 
-void eoi_ioapic_pin_remapped(int apic, int pin, int vector)
+static void eoi_ioapic_pin_remapped(int apic, int pin, int vector)
 {
 	/*
 	 * Intr-remapping uses pin number as the virtual vector
@@ -295,8 +295,8 @@ int setup_ioapic_remapped_entry(int irq,
 					     vector, attr);
 }
 
-int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
-			      bool force)
+static int set_remapped_irq_affinity(struct irq_data *data,
+				     const struct cpumask *mask, bool force)
 {
 	if (!config_enabled(CONFIG_SMP) || !remap_ops ||
 	    !remap_ops->set_affinity)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Patch Part1 V3 20/20] iommu/vt-d: free all resources if failed to initialize DMARs
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (18 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 19/20] iommu/vt-d, trivial: clean sparse warnings Jiang Liu
@ 2014-01-06  6:18 ` Jiang Liu
  2014-01-07 16:09 ` [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Joerg Roedel
  20 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-06  6:18 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul
  Cc: Jiang Liu, Ashok Raj, Yijing Wang, Tony Luck, iommu, linux-pci,
	linux-kernel, dmaengine

Enhance intel_iommu_init() to free all resources if failed to
initialize DMAR hardware.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/iommu/intel-iommu.c |   81 ++++++++++++++++++++++++++-----------------
 1 file changed, 49 insertions(+), 32 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c28e9fe..0863e25 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2615,6 +2615,7 @@ static int __init init_dmars(void)
 error:
 	for_each_active_iommu(iommu, drhd)
 		free_dmar_iommu(iommu);
+	kfree(deferred_flush);
 	kfree(g_iommus);
 	g_iommus = NULL;
 	return ret;
@@ -3459,18 +3460,12 @@ static int __init
 rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
 {
 	struct acpi_dmar_reserved_memory *rmrr;
-	int ret;
 
 	rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
-	ret = dmar_parse_dev_scope((void *)(rmrr + 1),
-		((void *)rmrr) + rmrr->header.length,
-		&rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
-
-	if (ret || (rmrru->devices_cnt == 0)) {
-		list_del(&rmrru->list);
-		kfree(rmrru);
-	}
-	return ret;
+	return dmar_parse_dev_scope((void *)(rmrr + 1),
+				    ((void *)rmrr) + rmrr->header.length,
+				    &rmrru->devices_cnt, &rmrru->devices,
+				    rmrr->segment);
 }
 
 static LIST_HEAD(dmar_atsr_units);
@@ -3495,23 +3490,39 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 
 static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
 {
-	int rc;
 	struct acpi_dmar_atsr *atsr;
 
 	if (atsru->include_all)
 		return 0;
 
 	atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
-	rc = dmar_parse_dev_scope((void *)(atsr + 1),
-				(void *)atsr + atsr->header.length,
-				&atsru->devices_cnt, &atsru->devices,
-				atsr->segment);
-	if (rc || !atsru->devices_cnt) {
-		list_del(&atsru->list);
-		kfree(atsru);
+	return dmar_parse_dev_scope((void *)(atsr + 1),
+				    (void *)atsr + atsr->header.length,
+				    &atsru->devices_cnt, &atsru->devices,
+				    atsr->segment);
+}
+
+static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
+{
+	dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
+	kfree(atsru);
+}
+
+static void intel_iommu_free_dmars(void)
+{
+	struct dmar_rmrr_unit *rmrru, *rmrr_n;
+	struct dmar_atsr_unit *atsru, *atsr_n;
+
+	list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
+		list_del(&rmrru->list);
+		dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
+		kfree(rmrru);
 	}
 
-	return rc;
+	list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
+		list_del(&atsru->list);
+		intel_iommu_free_atsr(atsru);
+	}
 }
 
 int dmar_find_matched_atsr_unit(struct pci_dev *dev)
@@ -3555,17 +3566,17 @@ found:
 
 int __init dmar_parse_rmrr_atsr_dev(void)
 {
-	struct dmar_rmrr_unit *rmrr, *rmrr_n;
-	struct dmar_atsr_unit *atsr, *atsr_n;
+	struct dmar_rmrr_unit *rmrr;
+	struct dmar_atsr_unit *atsr;
 	int ret = 0;
 
-	list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
+	list_for_each_entry(rmrr, &dmar_rmrr_units, list) {
 		ret = rmrr_parse_dev(rmrr);
 		if (ret)
 			return ret;
 	}
 
-	list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) {
+	list_for_each_entry(atsr, &dmar_atsr_units, list) {
 		ret = atsr_parse_dev(atsr);
 		if (ret)
 			return ret;
@@ -3612,7 +3623,7 @@ static struct notifier_block device_nb = {
 
 int __init intel_iommu_init(void)
 {
-	int ret = 0;
+	int ret = -ENODEV;
 	struct dmar_drhd_unit *drhd;
 	struct intel_iommu *iommu;
 
@@ -3622,7 +3633,7 @@ int __init intel_iommu_init(void)
 	if (dmar_table_init()) {
 		if (force_on)
 			panic("tboot: Failed to initialize DMAR table\n");
-		return 	-ENODEV;
+		goto out_free_dmar;
 	}
 
 	/*
@@ -3635,16 +3646,16 @@ int __init intel_iommu_init(void)
 	if (dmar_dev_scope_init() < 0) {
 		if (force_on)
 			panic("tboot: Failed to initialize DMAR device scope\n");
-		return 	-ENODEV;
+		goto out_free_dmar;
 	}
 
 	if (no_iommu || dmar_disabled)
-		return -ENODEV;
+		goto out_free_dmar;
 
 	if (iommu_init_mempool()) {
 		if (force_on)
 			panic("tboot: Failed to initialize iommu memory\n");
-		return 	-ENODEV;
+		goto out_free_dmar;
 	}
 
 	if (list_empty(&dmar_rmrr_units))
@@ -3656,7 +3667,7 @@ int __init intel_iommu_init(void)
 	if (dmar_init_reserved_ranges()) {
 		if (force_on)
 			panic("tboot: Failed to reserve iommu ranges\n");
-		return 	-ENODEV;
+		goto out_free_mempool;
 	}
 
 	init_no_remapping_devices();
@@ -3666,9 +3677,7 @@ int __init intel_iommu_init(void)
 		if (force_on)
 			panic("tboot: Failed to initialize DMARs\n");
 		printk(KERN_ERR "IOMMU: dmar init failed\n");
-		put_iova_domain(&reserved_iova_list);
-		iommu_exit_mempool();
-		return ret;
+		goto out_free_reserved_range;
 	}
 	printk(KERN_INFO
 	"PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
@@ -3688,6 +3697,14 @@ int __init intel_iommu_init(void)
 	intel_iommu_enabled = 1;
 
 	return 0;
+
+out_free_reserved_range:
+	put_iova_domain(&reserved_iova_list);
+out_free_mempool:
+	iommu_exit_mempool();
+out_free_dmar:
+	intel_iommu_free_dmars();
+	return ret;
 }
 
 static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [Patch Part1 V3 09/20] iommu/vt-d: mark internal functions as static
  2014-01-06  6:18 ` [Patch Part1 V3 09/20] iommu/vt-d: mark internal functions as static Jiang Liu
@ 2014-01-07 15:25   ` Joerg Roedel
  2014-01-08  8:44     ` Jiang Liu
  0 siblings, 1 reply; 28+ messages in thread
From: Joerg Roedel @ 2014-01-07 15:25 UTC (permalink / raw)
  To: Jiang Liu
  Cc: David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul, Ashok Raj,
	Yijing Wang, Tony Luck, iommu, linux-pci, linux-kernel,
	dmaengine

On Mon, Jan 06, 2014 at 02:18:16PM +0800, Jiang Liu wrote:
> Function detect_intel_iommu()/alloc_iommu()/parse_ioapics_under_ir()
> are only used internally, so mark them as static.

Doesn't seem to be true for detect_intel_iommu which is used in ia64
setup code, no?


	Joerg



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers
  2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
                   ` (19 preceding siblings ...)
  2014-01-06  6:18 ` [Patch Part1 V3 20/20] iommu/vt-d: free all resources if failed to initialize DMARs Jiang Liu
@ 2014-01-07 16:09 ` Joerg Roedel
  20 siblings, 0 replies; 28+ messages in thread
From: Joerg Roedel @ 2014-01-07 16:09 UTC (permalink / raw)
  To: Jiang Liu
  Cc: David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul, Ashok Raj,
	Yijing Wang, Tony Luck, iommu, linux-pci, linux-kernel,
	dmaengine

On Mon, Jan 06, 2014 at 02:18:07PM +0800, Jiang Liu wrote:
> This patchset includes several bugfixes and code improvements for
> Intel DMA remapping and interrupt remapping drivers. It's also a
> preparation for Intel IOMMU device hotplug.
> 
> It applies to the latest mainstream kernel on top of
> 	commit 7e3528c3660a2e8602abc7858b0994d611f74bc3
> 
> It has been tested on Intel SandyBridge and Romley-4S platforms.

Okay, I reviewed these patches and they are looking fine to me. I
applied them to my x86/vt-d branch (fixed the detect_intel_iommu()
problem myself).
Unless anyone speaks up against it or testing in linux-next shows issues
I plan to send these changes upstream for v3.14.

Thanks,

	Joerg



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Patch Part1 V3 09/20] iommu/vt-d: mark internal functions as static
  2014-01-07 15:25   ` Joerg Roedel
@ 2014-01-08  8:44     ` Jiang Liu
  0 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-08  8:44 UTC (permalink / raw)
  To: Joerg Roedel
  Cc: David Woodhouse, Yinghai Lu, Dan Williams, Vinod Koul, Ashok Raj,
	Yijing Wang, Tony Luck, iommu, linux-pci, linux-kernel,
	dmaengine

Hi Joerg,
	Thanks for fix up this issue!
I forgot to test the changes against IA64 platform. There's another
issue related to IA64, I will send out the patch soon. I have setup
cross compilation environment for IA64 and verified all changes
passing compilation tests.

Thanks!
Gerry

On 2014/1/7 23:25, Joerg Roedel wrote:
> On Mon, Jan 06, 2014 at 02:18:16PM +0800, Jiang Liu wrote:
>> Function detect_intel_iommu()/alloc_iommu()/parse_ioapics_under_ir()
>> are only used internally, so mark them as static.
> 
> Doesn't seem to be true for detect_intel_iommu which is used in ia64
> setup code, no?
> 
> 
> 	Joerg
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH] iommu/vt-d: fix compilation error when CONFIG_INTEL_IOMMU is unset
  2014-01-06  6:18 ` [Patch Part1 V3 02/20] iommu/vt-d: fix PCI device reference leakage on error recovery path Jiang Liu
@ 2014-01-08  8:53   ` Jiang Liu
  0 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-08  8:53 UTC (permalink / raw)
  To: Joerg Roedel, Vinod Koul, Dan Williams; +Cc: Jiang Liu, dmaengine, linux-kernel

commit: 3b3dc052f79731f4a7389b760060928da18823c0 [6/22] iommu/vt-d: fix
PCI device reference leakage on error recovery path
config: x86_64-randconfig-r0-01080757 (attached as .config)

All error/warnings:
   drivers/iommu/dmar.c: In function 'dmar_parse_dev_scope':
>> drivers/iommu/dmar.c:153:5: error: implicit declaration of function
'dmar_free_dev_scope' [-Werror=implicit-function-declaration]
        dmar_free_dev_scope(devices, cnt);
        ^
   drivers/iommu/dmar.c: At top level:
>> drivers/iommu/dmar.c:164:6: warning: conflicting types for
'dmar_free_dev_scope' [enabled by default]
    void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt)
         ^
   drivers/iommu/dmar.c:153:5: note: previous implicit declaration of
'dmar_free_dev_scope' was here
        dmar_free_dev_scope(devices, cnt);

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
Hi Joerg,
	Could you please help to fold this into "[6/22] iommu/vt-d: fix
PCI device reference leakage on error recovery path"?
	This issue has been fixed in part2 of the patch series. But I
have only done compilation tests with part1 and part2 all together,
so this issue hasn't been revealed.

Thanks!
Gerry
---
 include/linux/dmar.h |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index bd5026b..30162f9 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -67,6 +67,9 @@ extern struct list_head dmar_drhd_units;
 
 extern int dmar_table_init(void);
 extern int dmar_dev_scope_init(void);
+extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
+				struct pci_dev ***devices, u16 segment);
+extern void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt);
 extern int enable_drhd_fault_handling(void);
 #else
 static inline int dmar_table_init(void)
@@ -151,9 +154,6 @@ struct dmar_atsr_unit {
 int dmar_parse_rmrr_atsr_dev(void);
 extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
 extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
-extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
-				struct pci_dev ***devices, u16 segment);
-extern void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt);
 extern int intel_iommu_init(void);
 #else /* !CONFIG_INTEL_IOMMU: */
 static inline int intel_iommu_init(void) { return -ENODEV; }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH] iommu/vt-d: fix compilation error for IA64 platform
  2014-01-06  6:18 ` [Patch Part1 V3 19/20] iommu/vt-d, trivial: clean sparse warnings Jiang Liu
@ 2014-01-08  8:57   ` Jiang Liu
  2014-01-09 11:55     ` Joerg Roedel
  0 siblings, 1 reply; 28+ messages in thread
From: Jiang Liu @ 2014-01-08  8:57 UTC (permalink / raw)
  To: Joerg Roedel, David Woodhouse; +Cc: Jiang Liu, iommu, linux-kernel

commit: ecd1c02e9fea1c684c9698e8ce6a552656ba0871 [21/22] iommu/vt-d, trivial: clean sparse warnings
config: make ARCH=ia64 defconfig

All error/warnings:
   arch/ia64/kernel/built-in.o: In function `pci_iommu_alloc':
>> (.init.text+0xb541): undefined reference to `intel_dma_ops'
   arch/ia64/kernel/built-in.o: In function `pci_iommu_alloc':
>> (.init.text+0xb561): undefined reference to `intel_dma_ops'

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
Hi Joerg,
	Could you please help to fold this into "[21/22] iommu/vt-d,
trivial: clean sparse warnings"?

Thanks!
Gerry
---
 drivers/iommu/intel-iommu.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 0863e25..70a3257 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3128,7 +3128,7 @@ static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr)
 	return !dma_addr;
 }
 
-static struct dma_map_ops intel_dma_ops = {
+struct dma_map_ops intel_dma_ops = {
 	.alloc = intel_alloc_coherent,
 	.free = intel_free_coherent,
 	.map_sg = intel_map_sg,
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH] iommu/vt-d: fix compilation error for IA64 platform
  2014-01-08  8:57   ` [PATCH] iommu/vt-d: fix compilation error for IA64 platform Jiang Liu
@ 2014-01-09 11:55     ` Joerg Roedel
  2014-01-10  1:39       ` Jiang Liu
  0 siblings, 1 reply; 28+ messages in thread
From: Joerg Roedel @ 2014-01-09 11:55 UTC (permalink / raw)
  To: Jiang Liu; +Cc: David Woodhouse, iommu, linux-kernel

On Wed, Jan 08, 2014 at 04:57:07PM +0800, Jiang Liu wrote:
> Hi Joerg,
> 	Could you please help to fold this into "[21/22] iommu/vt-d,
> trivial: clean sparse warnings"?

Okay, I folded the two patches in, but that is something I'd like to
avoid because it requires a rebase. So next time please just send a
follow-up patch to my x86/vt-d branch to fix things up.


	Joerg



^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] iommu/vt-d: fix compilation error for IA64 platform
  2014-01-09 11:55     ` Joerg Roedel
@ 2014-01-10  1:39       ` Jiang Liu
  0 siblings, 0 replies; 28+ messages in thread
From: Jiang Liu @ 2014-01-10  1:39 UTC (permalink / raw)
  To: Joerg Roedel; +Cc: David Woodhouse, iommu, linux-kernel

Thanks Joerg! Sorry for the inconvenience.

On 2014/1/9 19:55, Joerg Roedel wrote:
> On Wed, Jan 08, 2014 at 04:57:07PM +0800, Jiang Liu wrote:
>> Hi Joerg,
>> 	Could you please help to fold this into "[21/22] iommu/vt-d,
>> trivial: clean sparse warnings"?
> 
> Okay, I folded the two patches in, but that is something I'd like to
> avoid because it requires a rebase. So next time please just send a
> follow-up patch to my x86/vt-d branch to fix things up.
> 
> 
> 	Joerg
> 
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2014-01-10  1:39 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-06  6:18 [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 01/20] iommu/vt-d: use dedicated bitmap to track remapping entry allocation status Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 02/20] iommu/vt-d: fix PCI device reference leakage on error recovery path Jiang Liu
2014-01-08  8:53   ` [PATCH] iommu/vt-d: fix compilation error when CONFIG_INTEL_IOMMU is unset Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 03/20] iommu/vt-d: fix a race window in allocating domain ID for virtual machines Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 04/20] iommu/vt-d: fix resource leakage on error recovery path in iommu_init_domains() Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 05/20] iommu/vt-d, trivial: refine support of 64bit guest address Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 06/20] iommu/vt-d, trivial: print correct domain id of static identity domain Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 07/20] iommu/vt-d, trivial: check suitable flag in function detect_intel_iommu() Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 08/20] iommu/vt-d, trivial: clean up unused code Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 09/20] iommu/vt-d: mark internal functions as static Jiang Liu
2014-01-07 15:25   ` Joerg Roedel
2014-01-08  8:44     ` Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 10/20] iommu/vt-d, trivial: use defined macro instead of hardcoding Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 11/20] iommu/vt-d, trivial: simplify code with existing macros Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 12/20] iommu/vt-d: fix invalid memory access when freeing DMAR irq Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 13/20] iommu/vt-d: keep shared resources when failed to initialize iommu devices Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 14/20] iommu/vt-d: avoid double free in error recovery path Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 15/20] iommu/vt-d: fix access after free issue in function free_dmar_iommu() Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 16/20] iommu/vt-d: release invalidation queue when destroying IOMMU unit Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 17/20] iommu/vt-d: fix wrong return value of dmar_table_init() Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 18/20] iommu/vt-d, PCI, trivial: use dev_is_pci() instead of hardcoding Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 19/20] iommu/vt-d, trivial: clean sparse warnings Jiang Liu
2014-01-08  8:57   ` [PATCH] iommu/vt-d: fix compilation error for IA64 platform Jiang Liu
2014-01-09 11:55     ` Joerg Roedel
2014-01-10  1:39       ` Jiang Liu
2014-01-06  6:18 ` [Patch Part1 V3 20/20] iommu/vt-d: free all resources if failed to initialize DMARs Jiang Liu
2014-01-07 16:09 ` [Patch Part1 V3 00/20] Bugfixes and improvements for Intel IOMMU drivers Joerg Roedel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).