Skip to contentSkip to conversation

iommu/amd: Disable previously enabled IOMMUs at boot

PATCH New Joerg Roedel 1 participant 8 messages Jun 16, 2017 IOMMU

lore
Share & tools
lore

Joerg Roedel

author maintainer
#0 lore raw

cover iommu/amd: Disable previously enabled IOMMUs at boot

Hi,

here is a patch-set refactoring the AMD IOMMU init code a bit to make sure the IOMMUs get disabled at boot, even when amd_iommu=off is specified on the kernel command line.

The patch-set is tested with various combinations of kernel command-line parameters and with kexec. It applies to the x86/amd branch of the iommu-tree.

Regards,

Joerg

Joerg Roedel (7):
iommu/amd: Disable IOMMUs at boot if they are enabled iommu/amd: Rename free_on_init_error()
iommu/amd: Add new init-state IOMMU_CMDLINE_DISABLED iommu/amd: Check for error states first in iommu_go_to_state() iommu/amd: Set global pointers to NULL after freeing them iommu/amd: Free IOMMU resources when disabled on command line iommu/amd: Remove amd_iommu_disabled check from amd_iommu_detect()

 drivers/iommu/amd_iommu_init.c | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)
Signature · 1 line
2.7.4
author maintainer
#1 lore raw

PATCH 1/7 iommu/amd: Disable IOMMUs at boot if they are enabled

From: Joerg Roedel <[email protected]>

When booting, make sure the IOMMUs are disabled. They could be previously enabled if we boot into a kexec or kdump kernel. So make sure they are off.

---
 drivers/iommu/amd_iommu_init.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/iommu/amd_iommu_init.c +3 -0
index d9f5ddd..fb7035f 100644
@@ -2316,6 +2316,9 @@ static int __init early_amd_iommu_init(void)
 	if (ret)
 		goto out;
 
+	/* Disable any previously enabled IOMMUs */
+	disable_iommus();
+
 	if (amd_iommu_irq_remap)
 		amd_iommu_irq_remap = check_ioapic_information();
 
Signature · 1 line
2.7.4
author maintainer
#2 lore raw

PATCH 2/7 iommu/amd: Rename free_on_init_error()

In reply to Joerg Roedel

From: Joerg Roedel <[email protected]>

The function will also be used to free iommu resources when amd_iommu=off was specified on the kernel command line. So rename the function to reflect that.

---
 drivers/iommu/amd_iommu_init.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/iommu/amd_iommu_init.c +2 -2
index fb7035f..28bf39c 100644
@@ -2106,7 +2106,7 @@ static struct syscore_ops amd_iommu_syscore_ops = {
 	.resume = amd_iommu_resume,
 };
 
-static void __init free_on_init_error(void)
+static void __init free_iommu_resources(void)
 {
 	kmemleak_free(irq_lookup_table);
 	free_pages((unsigned long)irq_lookup_table,
@@ -2534,7 +2534,7 @@ static int __init amd_iommu_init(void)
 		free_dma_resources();
 		if (!irq_remapping_enabled) {
 			disable_iommus();
-			free_on_init_error();
+			free_iommu_resources();
 		} else {
 			struct amd_iommu *iommu;
 
Signature · 1 line
2.7.4
author maintainer
#3 lore raw

PATCH 3/7 iommu/amd: Add new init-state IOMMU_CMDLINE_DISABLED

In reply to Joerg Roedel

From: Joerg Roedel <[email protected]>

This will be used when during initialization we detect that the iommu should be disabled.

---
 drivers/iommu/amd_iommu_init.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/iommu/amd_iommu_init.c +5 -2
index 28bf39c..c40adc8 100644
@@ -237,6 +237,7 @@ enum iommu_init_state {
 	IOMMU_INITIALIZED,
 	IOMMU_NOT_FOUND,
 	IOMMU_INIT_ERROR,
+	IOMMU_CMDLINE_DISABLED,
 };
 
 /* Early ioapic and hpet maps from kernel command line */
@@ -2450,6 +2451,7 @@ static int __init state_next(void)
 		break;
 	case IOMMU_NOT_FOUND:
 	case IOMMU_INIT_ERROR:
+	case IOMMU_CMDLINE_DISABLED:
 		/* Error states => do nothing */
 		ret = -EINVAL;
 		break;
@@ -2467,8 +2469,9 @@ static int __init iommu_go_to_state(enum iommu_init_state state)
 
 	while (init_state != state) {
 		ret = state_next();
-		if (init_state == IOMMU_NOT_FOUND ||
-		    init_state == IOMMU_INIT_ERROR)
+		if (init_state == IOMMU_NOT_FOUND         ||
+		    init_state == IOMMU_INIT_ERROR        ||
+		    init_state == IOMMU_CMDLINE_DISABLED)
 			break;
 	}
 
Signature · 1 line
2.7.4
author maintainer
#4 lore raw

PATCH 4/7 iommu/amd: Check for error states first in iommu_go_to_state()

In reply to Joerg Roedel

From: Joerg Roedel <[email protected]>

Check if we are in an error state already before calling into state_next().

---
 drivers/iommu/amd_iommu_init.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/iommu/amd_iommu_init.c +2 -2
index c40adc8..a31f375 100644
@@ -2465,14 +2465,14 @@ static int __init state_next(void)
 
 static int __init iommu_go_to_state(enum iommu_init_state state)
 {
-	int ret = 0;
+	int ret = -EINVAL;
 
 	while (init_state != state) {
-		ret = state_next();
 		if (init_state == IOMMU_NOT_FOUND         ||
 		    init_state == IOMMU_INIT_ERROR        ||
 		    init_state == IOMMU_CMDLINE_DISABLED)
 			break;
+		ret = state_next();
 	}
 
 	return ret;
Signature · 1 line
2.7.4
author maintainer
#5 lore raw

PATCH 5/7 iommu/amd: Set global pointers to NULL after freeing them

In reply to Joerg Roedel

From: Joerg Roedel <[email protected]>

Avoid any tries to double-free these pointers.

---
 drivers/iommu/amd_iommu_init.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/iommu/amd_iommu_init.c +5 -0
index a31f375..d04898c 100644
@@ -2112,18 +2112,22 @@ static void __init free_iommu_resources(void)
 	kmemleak_free(irq_lookup_table);
 	free_pages((unsigned long)irq_lookup_table,
 		   get_order(rlookup_table_size));
+	irq_lookup_table = NULL;
 
 	kmem_cache_destroy(amd_iommu_irq_cache);
 	amd_iommu_irq_cache = NULL;
 
 	free_pages((unsigned long)amd_iommu_rlookup_table,
 		   get_order(rlookup_table_size));
+	amd_iommu_rlookup_table = NULL;
 
 	free_pages((unsigned long)amd_iommu_alias_table,
 		   get_order(alias_table_size));
+	amd_iommu_alias_table = NULL;
 
 	free_pages((unsigned long)amd_iommu_dev_table,
 		   get_order(dev_table_size));
+	amd_iommu_dev_table = NULL;
 
 	free_iommu_all();
 
@@ -2193,6 +2197,7 @@ static void __init free_dma_resources(void)
 {
 	free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
 		   get_order(MAX_DOMAIN_ID/8));
+	amd_iommu_pd_alloc_bitmap = NULL;
 
 	free_unity_maps();
 }
Signature · 1 line
2.7.4
author maintainer
#6 lore raw

PATCH 6/7 iommu/amd: Free IOMMU resources when disabled on command line

In reply to Joerg Roedel

From: Joerg Roedel <[email protected]>

After we made sure that all IOMMUs have been disabled we need to make sure that all resources we allocated are released again.

---
 drivers/iommu/amd_iommu_init.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/iommu/amd_iommu_init.c +7 -0
index d04898c..eedd3d3 100644
@@ -2428,6 +2428,13 @@ static int __init state_next(void)
 	case IOMMU_IVRS_DETECTED:
 		ret = early_amd_iommu_init();
 		init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED;
+		if (init_state == IOMMU_ACPI_FINISHED && amd_iommu_disabled) {
+			pr_info("AMD-Vi: AMD IOMMU disabled on kernel command-line\n");
+			free_dma_resources();
+			free_iommu_resources();
+			init_state = IOMMU_CMDLINE_DISABLED;
+			ret = -EINVAL;
+		}
 		break;
 	case IOMMU_ACPI_FINISHED:
 		early_enable_iommus();
Signature · 1 line
2.7.4
author maintainer
#7 lore raw

PATCH 7/7 iommu/amd: Remove amd_iommu_disabled check from amd_iommu_detect()

In reply to Joerg Roedel

From: Joerg Roedel <[email protected]>

This check needs to happens later now, when all previously enabled IOMMUs have been disabled.

---
 drivers/iommu/amd_iommu_init.c | 3 ---
 1 file changed, 3 deletions(-)
drivers/iommu/amd_iommu_init.c +0 -3
index eedd3d3..bc9dfcf 100644
@@ -2576,9 +2576,6 @@ int __init amd_iommu_detect(void)
 	if (no_iommu || (iommu_detected && !gart_iommu_aperture))
 		return -ENODEV;
 
-	if (amd_iommu_disabled)
-		return -ENODEV;
-
 	ret = iommu_go_to_state(IOMMU_IVRS_DETECTED);
 	if (ret)
 		return ret;
Signature · 1 line
2.7.4