diff options
author | Baoquan He <bhe@redhat.com> | 2017-08-09 04:33:38 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2017-08-15 12:14:39 -0400 |
commit | 3ac3e5ee5ed56b07448f295902e44916eb6979fc (patch) | |
tree | 1e6c62c314a67922605b7d959708c77157e13d50 | |
parent | 45a01c42933b93e59811099f97aa4179d499a42c (diff) |
iommu/amd: Copy old trans table from old kernel
Here several things need be done:
- If iommu is pre-enabled in a normal kernel, just disable it and print
warning.
- If any one of IOMMUs is not pre-enabled in kdump kernel, just continue
as it does in normal kernel.
- If failed to copy dev table of old kernel, continue to proceed as
it does in normal kernel.
- Only if all IOMMUs are pre-enabled and copy dev table is done well, free
the dev table allocated in early_amd_iommu_init() and make amd_iommu_dev_table
point to the copied one.
- Disable and Re-enable event/cmd buffer, install the copied DTE table
to reg, and detect and enable guest vapic.
- Flush all caches
Signed-off-by: Baoquan He <bhe@redhat.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/iommu/amd_iommu_init.c | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index e2857204d32a..959c25d997e1 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <asm/io_apic.h> | 37 | #include <asm/io_apic.h> |
38 | #include <asm/irq_remapping.h> | 38 | #include <asm/irq_remapping.h> |
39 | 39 | ||
40 | #include <linux/crash_dump.h> | ||
40 | #include "amd_iommu_proto.h" | 41 | #include "amd_iommu_proto.h" |
41 | #include "amd_iommu_types.h" | 42 | #include "amd_iommu_types.h" |
42 | #include "irq_remapping.h" | 43 | #include "irq_remapping.h" |
@@ -262,6 +263,8 @@ static int amd_iommu_enable_interrupts(void); | |||
262 | static int __init iommu_go_to_state(enum iommu_init_state state); | 263 | static int __init iommu_go_to_state(enum iommu_init_state state); |
263 | static void init_device_table_dma(void); | 264 | static void init_device_table_dma(void); |
264 | 265 | ||
266 | static bool __initdata amd_iommu_pre_enabled = true; | ||
267 | |||
265 | bool translation_pre_enabled(struct amd_iommu *iommu) | 268 | bool translation_pre_enabled(struct amd_iommu *iommu) |
266 | { | 269 | { |
267 | return (iommu->flags & AMD_IOMMU_FLAG_TRANS_PRE_ENABLED); | 270 | return (iommu->flags & AMD_IOMMU_FLAG_TRANS_PRE_ENABLED); |
@@ -857,6 +860,8 @@ static bool copy_device_table(void) | |||
857 | u16 dom_id, dte_v; | 860 | u16 dom_id, dte_v; |
858 | gfp_t gfp_flag; | 861 | gfp_t gfp_flag; |
859 | 862 | ||
863 | if (!amd_iommu_pre_enabled) | ||
864 | return false; | ||
860 | 865 | ||
861 | pr_warn("Translation is already enabled - trying to copy translation structures\n"); | 866 | pr_warn("Translation is already enabled - trying to copy translation structures\n"); |
862 | for_each_iommu(iommu) { | 867 | for_each_iommu(iommu) { |
@@ -1496,9 +1501,14 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) | |||
1496 | iommu->int_enabled = false; | 1501 | iommu->int_enabled = false; |
1497 | 1502 | ||
1498 | init_translation_status(iommu); | 1503 | init_translation_status(iommu); |
1499 | 1504 | if (translation_pre_enabled(iommu) && !is_kdump_kernel()) { | |
1500 | if (translation_pre_enabled(iommu)) | 1505 | iommu_disable(iommu); |
1501 | pr_warn("Translation is already enabled - trying to copy translation structures\n"); | 1506 | clear_translation_pre_enabled(iommu); |
1507 | pr_warn("Translation was enabled for IOMMU:%d but we are not in kdump mode\n", | ||
1508 | iommu->index); | ||
1509 | } | ||
1510 | if (amd_iommu_pre_enabled) | ||
1511 | amd_iommu_pre_enabled = translation_pre_enabled(iommu); | ||
1502 | 1512 | ||
1503 | ret = init_iommu_from_acpi(iommu, h); | 1513 | ret = init_iommu_from_acpi(iommu, h); |
1504 | if (ret) | 1514 | if (ret) |
@@ -1993,8 +2003,7 @@ static int __init init_memory_definitions(struct acpi_table_header *table) | |||
1993 | } | 2003 | } |
1994 | 2004 | ||
1995 | /* | 2005 | /* |
1996 | * Init the device table to not allow DMA access for devices and | 2006 | * Init the device table to not allow DMA access for devices |
1997 | * suppress all page faults | ||
1998 | */ | 2007 | */ |
1999 | static void init_device_table_dma(void) | 2008 | static void init_device_table_dma(void) |
2000 | { | 2009 | { |
@@ -2130,14 +2139,48 @@ static void early_enable_iommu(struct amd_iommu *iommu) | |||
2130 | 2139 | ||
2131 | /* | 2140 | /* |
2132 | * This function finally enables all IOMMUs found in the system after | 2141 | * This function finally enables all IOMMUs found in the system after |
2133 | * they have been initialized | 2142 | * they have been initialized. |
2143 | * | ||
2144 | * Or if in kdump kernel and IOMMUs are all pre-enabled, try to copy | ||
2145 | * the old content of device table entries. Not this case or copy failed, | ||
2146 | * just continue as normal kernel does. | ||
2134 | */ | 2147 | */ |
2135 | static void early_enable_iommus(void) | 2148 | static void early_enable_iommus(void) |
2136 | { | 2149 | { |
2137 | struct amd_iommu *iommu; | 2150 | struct amd_iommu *iommu; |
2138 | 2151 | ||
2139 | for_each_iommu(iommu) | 2152 | |
2140 | early_enable_iommu(iommu); | 2153 | if (!copy_device_table()) { |
2154 | /* | ||
2155 | * If come here because of failure in copying device table from old | ||
2156 | * kernel with all IOMMUs enabled, print error message and try to | ||
2157 | * free allocated old_dev_tbl_cpy. | ||
2158 | */ | ||
2159 | if (amd_iommu_pre_enabled) | ||
2160 | pr_err("Failed to copy DEV table from previous kernel.\n"); | ||
2161 | if (old_dev_tbl_cpy != NULL) | ||
2162 | free_pages((unsigned long)old_dev_tbl_cpy, | ||
2163 | get_order(dev_table_size)); | ||
2164 | |||
2165 | for_each_iommu(iommu) { | ||
2166 | clear_translation_pre_enabled(iommu); | ||
2167 | early_enable_iommu(iommu); | ||
2168 | } | ||
2169 | } else { | ||
2170 | pr_info("Copied DEV table from previous kernel.\n"); | ||
2171 | free_pages((unsigned long)amd_iommu_dev_table, | ||
2172 | get_order(dev_table_size)); | ||
2173 | amd_iommu_dev_table = old_dev_tbl_cpy; | ||
2174 | for_each_iommu(iommu) { | ||
2175 | iommu_disable_command_buffer(iommu); | ||
2176 | iommu_disable_event_buffer(iommu); | ||
2177 | iommu_enable_command_buffer(iommu); | ||
2178 | iommu_enable_event_buffer(iommu); | ||
2179 | iommu_enable_ga(iommu); | ||
2180 | iommu_set_device_table(iommu); | ||
2181 | iommu_flush_all_caches(iommu); | ||
2182 | } | ||
2183 | } | ||
2141 | 2184 | ||
2142 | #ifdef CONFIG_IRQ_REMAP | 2185 | #ifdef CONFIG_IRQ_REMAP |
2143 | if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir)) | 2186 | if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir)) |