Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1504796 > unrolled thread
| Started by | Baoquan He <bhe@redhat.com> |
|---|---|
| First post | 2016-10-20 13:40 +0200 |
| Last post | 2016-10-20 13:40 +0200 |
| Articles | 5 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v6 0/9] Fix kdump faults on system with amd iommu Baoquan He <bhe@redhat.com> - 2016-10-20 13:40 +0200
[PATCH v6 8/9] iommu/amd: Add sanity check of irq remap information of old dev table entry Baoquan He <bhe@redhat.com> - 2016-10-20 13:40 +0200
[PATCH v6 5/9] iommu/amd: copy old trans table from old kernel Baoquan He <bhe@redhat.com> - 2016-10-20 13:40 +0200
[PATCH v6 1/9] iommu/amd: Detect pre enabled translation Baoquan He <bhe@redhat.com> - 2016-10-20 13:40 +0200
[PATCH v6 7/9] iommu/amd: Update domain into to dte entry during device driver init Baoquan He <bhe@redhat.com> - 2016-10-20 13:40 +0200
| From | Baoquan He <bhe@redhat.com> |
|---|---|
| Date | 2016-10-20 13:40 +0200 |
| Subject | [PATCH v6 0/9] Fix kdump faults on system with amd iommu |
| Message-ID | <sujRv-6UT-7@gated-at.bofh.it> |
This is v6 post.
The principle of the fix is similar to intel iommu. Just defer the assignment
of device to domain to device driver init. But there's difference than
intel iommu. AMD iommu create protection domain and assign device to
domain in iommu driver init stage. So in this patchset I just allow the
assignment of device to domain in software level, but defer updating the
domain info, especially the pte_root to dev table entry to device driver
init stage.
v5:
bnx2 NIC can't reset itself during driver init. Post patch to reset
it during driver init. IO_PAGE_FAULT can't be seen anymore.
Below is link of v5 post.
https://lists.linuxfoundation.org/pipermail/iommu/2016-September/018527.html
v5->v6:
According to Joerg's comments made several below main changes:
- Add sanity check when copy old dev tables.
- Discard the old patch 6/8.
- If a device is set up with guest translations (DTE.GV=1), then don't
copy that information but move the device over to an empty guest-cr3
table and handle the faults in the PPR log (which just answer them
with INVALID).
Issues need be discussed:
- Joerg suggested hooking the behaviour that updates domain info into
dte entry into the set_dma_mask call-back. I tried, but on my local
machine with amd iommu v2, an ohci pci device doesn't call set_dma_mask.
Then IO_PAGE_FAULT printing flooded.
00:12.0 USB controller: Advanced Micro Devices, Inc. [AMD] FCH USB OHCI Controller (rev 11)
- About GCR3 root pointer copying issue, I don't know how to setup the
test environment and haven't tested yet. Hope Joerg or Zongshun can
tell what steps should be taken to test it, or help take a test in your
test environemnt.
Baoquan He (9):
iommu/amd: Detect pre enabled translation
iommu/amd: add several helper function
iommu/amd: Define bit fields for DTE particularly
iommu/amd: Add function copy_dev_tables
iommu/amd: copy old trans table from old kernel
iommu/amd: Don't update domain info to dte entry at iommu init stage
iommu/amd: Update domain into to dte entry during device driver init
iommu/amd: Add sanity check of irq remap information of old dev table
entry
iommu/amd: Don't copy GCR3 table root pointer
drivers/iommu/amd_iommu.c | 93 +++++++++++++-------
drivers/iommu/amd_iommu_init.c | 189 +++++++++++++++++++++++++++++++++++++---
drivers/iommu/amd_iommu_proto.h | 2 +
drivers/iommu/amd_iommu_types.h | 53 ++++++++++-
drivers/iommu/amd_iommu_v2.c | 18 +++-
5 files changed, 307 insertions(+), 48 deletions(-)
--
2.5.5
[toc] | [next] | [standalone]
| From | Baoquan He <bhe@redhat.com> |
|---|---|
| Date | 2016-10-20 13:40 +0200 |
| Subject | [PATCH v6 8/9] iommu/amd: Add sanity check of irq remap information of old dev table entry |
| Message-ID | <sujRw-6UT-19@gated-at.bofh.it> |
| In reply to | #1504796 |
Firstly split the dev table entry copy into address translation part and
irq remapping part. Because these two parts could be configured to
be available indepentently.
Secondly check if IntCtl and IntTabLen are 10b and 1000b if they are
set.
Signed-off-by: Baoquan He <bhe@redhat.com>
---
drivers/iommu/amd_iommu.c | 5 -----
drivers/iommu/amd_iommu_init.c | 25 ++++++++++++++++++++++---
drivers/iommu/amd_iommu_types.h | 8 ++++++++
3 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 3b95904..46f438f 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3658,11 +3658,6 @@ EXPORT_SYMBOL(amd_iommu_device_info);
static struct irq_chip amd_ir_chip;
-#define DTE_IRQ_PHYS_ADDR_MASK (((1ULL << 45)-1) << 6)
-#define DTE_IRQ_REMAP_INTCTL (2ULL << 60)
-#define DTE_IRQ_TABLE_LEN (8ULL << 1)
-#define DTE_IRQ_REMAP_ENABLE 1ULL
-
static void set_dte_irq_entry(u16 devid, struct irq_remap_table *table)
{
u64 dte;
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index bc214fa..d936c40 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -837,12 +837,12 @@ static int get_dev_entry_bit(u16 devid, u8 bit)
static int copy_dev_tables(void)
{
+ u64 int_ctl, int_tab_len, entry, last_entry = 0;
struct dev_table_entry *old_devtb = NULL;
u32 lo, hi, devid, old_devtb_size;
phys_addr_t old_devtb_phys;
- u64 entry, last_entry = 0;
struct amd_iommu *iommu;
- u16 dom_id, dte_v;
+ u16 dom_id, dte_v, irq_v;
static int copied;
for_each_iommu(iommu) {
@@ -881,8 +881,27 @@ static int copy_dev_tables(void)
amd_iommu_dev_table[devid] = old_devtb[devid];
dom_id = old_devtb[devid].data[1] & DEV_DOMID_MASK;
dte_v = old_devtb[devid].data[0] & DTE_FLAG_V;
- if (dte_v && dom_id)
+ if (dte_v && dom_id) {
+ amd_iommu_dev_table[devid].data[0]
+ = old_devtb[devid].data[0];
+ amd_iommu_dev_table[devid].data[1]
+ = old_devtb[devid].data[1];
__set_bit(dom_id, amd_iommu_pd_alloc_bitmap);
+ }
+
+ irq_v = old_devtb[devid].data[2] & DTE_IRQ_REMAP_ENABLE;
+ int_ctl = old_devtb[devid].data[2] & DTE_IRQ_REMAP_INTCTL_MASK;
+ int_tab_len = old_devtb[devid].data[2] & DTE_IRQ_TABLE_LEN_MASK;
+ if (irq_v && (int_ctl || int_tab_len)) {
+ if ((int_ctl != DTE_IRQ_REMAP_INTCTL) ||
+ (int_tab_len != DTE_IRQ_TABLE_LEN)) {
+ pr_err("Wrong old irq remapping flag: %#x\n", devid);
+ return -1;
+ }
+
+ amd_iommu_dev_table[devid].data[2]
+ = old_devtb[devid].data[2];
+ }
}
memunmap(old_devtb);
copied = 1;
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 454f3bf..e385d50 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -250,6 +250,14 @@
#define GA_GUEST_NR 0x1
+/* Bit value definition for dte irq remapping fields*/
+#define DTE_IRQ_PHYS_ADDR_MASK (((1ULL << 45)-1) << 6)
+#define DTE_IRQ_REMAP_INTCTL_MASK (0x3ULL << 60)
+#define DTE_IRQ_TABLE_LEN_MASK (0xfULL << 1)
+#define DTE_IRQ_REMAP_INTCTL (2ULL << 60)
+#define DTE_IRQ_TABLE_LEN (8ULL << 1)
+#define DTE_IRQ_REMAP_ENABLE 1ULL
+
#define PAGE_MODE_NONE 0x00
#define PAGE_MODE_1_LEVEL 0x01
#define PAGE_MODE_2_LEVEL 0x02
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Baoquan He <bhe@redhat.com> |
|---|---|
| Date | 2016-10-20 13:40 +0200 |
| Subject | [PATCH v6 5/9] iommu/amd: copy old trans table from old kernel |
| Message-ID | <sujRw-6UT-23@gated-at.bofh.it> |
| In reply to | #1504796 |
Here several things need be done:
- If iommu is pre-enabled in a normal kernel, just disable it and print
warning.
- If failed to copy dev table of old kernel, continue to proceed as
it does in normal kernel.
- Disable and Re-enable event/cmd buffer, and install the copied DTE table
to reg.
- Flush all caches
Signed-off-by: Baoquan He <bhe@redhat.com>
---
drivers/iommu/amd_iommu_init.c | 51 ++++++++++++++++++++++++++++++++++++------
1 file changed, 44 insertions(+), 7 deletions(-)
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index d4200e8..bc214fa 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -36,6 +36,7 @@
#include <asm/io_apic.h>
#include <asm/irq_remapping.h>
+#include <linux/crash_dump.h>
#include "amd_iommu_proto.h"
#include "amd_iommu_types.h"
#include "irq_remapping.h"
@@ -1481,9 +1482,12 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
iommu->int_enabled = false;
init_translation_status(iommu);
-
- if (translation_pre_enabled(iommu))
- pr_warn("Translation is already enabled - trying to copy translation structures\n");
+ if (translation_pre_enabled(iommu) && !is_kdump_kernel()) {
+ iommu_disable(iommu);
+ clear_translation_pre_enabled(iommu);
+ pr_warn("Translation was enabled for IOMMU:%d but we are not in kdump mode\n",
+ iommu->index);
+ }
ret = init_iommu_from_acpi(iommu, h);
if (ret)
@@ -1975,8 +1979,7 @@ static int __init init_memory_definitions(struct acpi_table_header *table)
}
/*
- * Init the device table to not allow DMA access for devices and
- * suppress all page faults
+ * Init the device table to not allow DMA access for devices
*/
static void init_device_table_dma(void)
{
@@ -2117,9 +2120,43 @@ static void early_enable_iommu(struct amd_iommu *iommu)
static void early_enable_iommus(void)
{
struct amd_iommu *iommu;
+ bool is_pre_enabled = false;
- for_each_iommu(iommu)
- early_enable_iommu(iommu);
+ for_each_iommu(iommu) {
+ if (translation_pre_enabled(iommu)) {
+ is_pre_enabled = true;
+ break;
+ }
+ }
+
+ if (!is_pre_enabled) {
+ for_each_iommu(iommu)
+ early_enable_iommu(iommu);
+ } else {
+ pr_warn("Translation is already enabled - trying to copy translation structures\n");
+ if (copy_dev_tables()) {
+ pr_err("Failed to copy DEV table from previous kernel.\n");
+ /*
+ * If failed to copy dev tables from old kernel, continue to proceed
+ * as it does in normal kernel.
+ */
+ for_each_iommu(iommu) {
+ clear_translation_pre_enabled(iommu);
+ early_enable_iommu(iommu);
+ }
+ } else {
+ pr_info("Copied DEV table from previous kernel.\n");
+ for_each_iommu(iommu) {
+ iommu_disable_command_buffer(iommu);
+ iommu_disable_event_buffer(iommu);
+ iommu_enable_command_buffer(iommu);
+ iommu_enable_event_buffer(iommu);
+ iommu_enable_ga(iommu);
+ iommu_set_device_table(iommu);
+ iommu_flush_all_caches(iommu);
+ }
+ }
+ }
#ifdef CONFIG_IRQ_REMAP
if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Baoquan He <bhe@redhat.com> |
|---|---|
| Date | 2016-10-20 13:40 +0200 |
| Subject | [PATCH v6 1/9] iommu/amd: Detect pre enabled translation |
| Message-ID | <sujRw-6UT-27@gated-at.bofh.it> |
| In reply to | #1504796 |
Add functions to check whether translation is already enabled in IOMMU.
Signed-off-by: Baoquan He <bhe@redhat.com>
---
drivers/iommu/amd_iommu_init.c | 25 +++++++++++++++++++++++++
drivers/iommu/amd_iommu_proto.h | 1 +
drivers/iommu/amd_iommu_types.h | 4 ++++
3 files changed, 30 insertions(+)
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index 157e934..1628d7e 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -251,6 +251,26 @@ static int amd_iommu_enable_interrupts(void);
static int __init iommu_go_to_state(enum iommu_init_state state);
static void init_device_table_dma(void);
+
+bool translation_pre_enabled(struct amd_iommu *iommu)
+{
+ return (iommu->flags & AMD_IOMMU_FLAG_TRANS_PRE_ENABLED);
+}
+
+static void clear_translation_pre_enabled(struct amd_iommu *iommu)
+{
+ iommu->flags &= ~AMD_IOMMU_FLAG_TRANS_PRE_ENABLED;
+}
+
+static void init_translation_status(struct amd_iommu *iommu)
+{
+ u32 ctrl;
+
+ ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET);
+ if (ctrl & (1<<CONTROL_IOMMU_EN))
+ iommu->flags |= AMD_IOMMU_FLAG_TRANS_PRE_ENABLED;
+}
+
static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
u8 bank, u8 cntr, u8 fxn,
u64 *value, bool is_write);
@@ -1389,6 +1409,11 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
iommu->int_enabled = false;
+ init_translation_status(iommu);
+
+ if (translation_pre_enabled(iommu))
+ pr_warn("Translation is already enabled - trying to copy translation structures\n");
+
ret = init_iommu_from_acpi(iommu, h);
if (ret)
return ret;
diff --git a/drivers/iommu/amd_iommu_proto.h b/drivers/iommu/amd_iommu_proto.h
index 7eb60c1..9560183 100644
--- a/drivers/iommu/amd_iommu_proto.h
+++ b/drivers/iommu/amd_iommu_proto.h
@@ -93,4 +93,5 @@ static inline bool iommu_feature(struct amd_iommu *iommu, u64 f)
return !!(iommu->features & f);
}
+extern bool translation_pre_enabled(struct amd_iommu *iommu);
#endif /* _ASM_X86_AMD_IOMMU_PROTO_H */
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index 0d91785..2bbc19d 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -416,6 +416,7 @@ extern struct kmem_cache *amd_iommu_irq_cache;
#define APERTURE_PAGE_INDEX(a) (((a) >> 21) & 0x3fULL)
+
/*
* This struct is used to pass information about
* incoming PPR faults around.
@@ -434,6 +435,8 @@ struct iommu_domain;
struct irq_domain;
struct amd_irte_ops;
+#define AMD_IOMMU_FLAG_TRANS_PRE_ENABLED (1 << 0)
+
/*
* This structure contains generic data for IOMMU protection domains
* independent of their use.
@@ -566,6 +569,7 @@ struct amd_iommu {
struct amd_irte_ops *irte_ops;
#endif
+ u32 flags;
volatile u64 __aligned(8) cmd_sem;
};
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Baoquan He <bhe@redhat.com> |
|---|---|
| Date | 2016-10-20 13:40 +0200 |
| Subject | [PATCH v6 7/9] iommu/amd: Update domain into to dte entry during device driver init |
| Message-ID | <sujRw-6UT-29@gated-at.bofh.it> |
| In reply to | #1504796 |
All devices are supposed to reset themselves at device driver initialization
stage. At this time if in kdump kernel those on-flight DMA will be stopped
because of device reset. It's best time to update the protection domain info,
especially pte_root, to dte entry which the device relates to.
Signed-off-by: Baoquan He <bhe@redhat.com>
---
drivers/iommu/amd_iommu.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index aa78506..3b95904 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -2396,6 +2396,10 @@ static dma_addr_t __map_single(struct device *dev,
enum dma_data_direction direction,
u64 dma_mask)
{
+ struct iommu_dev_data *dev_data = get_dev_data(dev);
+ struct amd_iommu *iommu = amd_iommu_rlookup_table[dev_data->devid];
+ struct protection_domain *domain = get_domain(dev);
+ u16 alias = amd_iommu_alias_table[dev_data->devid];
dma_addr_t offset = paddr & ~PAGE_MASK;
dma_addr_t address, start, ret;
unsigned int pages;
@@ -2410,6 +2414,13 @@ static dma_addr_t __map_single(struct device *dev,
goto out;
prot = dir2prot(direction);
+ if (translation_pre_enabled(iommu) && !dev_data->domain_updated) {
+ dev_data->domain_updated = true;
+ set_dte_entry(dev_data->devid, domain, dev_data->ats.enabled);
+ if (alias != dev_data->devid)
+ set_dte_entry(alias, domain, dev_data->ats.enabled);
+ device_flush_dte(dev_data);
+ }
start = address;
for (i = 0; i < pages; ++i) {
@@ -2555,6 +2566,9 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction,
unsigned long attrs)
{
+ struct iommu_dev_data *dev_data = get_dev_data(dev);
+ struct amd_iommu *iommu = amd_iommu_rlookup_table[dev_data->devid];
+ u16 alias = amd_iommu_alias_table[dev_data->devid];
int mapped_pages = 0, npages = 0, prot = 0, i;
struct protection_domain *domain;
struct dma_ops_domain *dma_dom;
@@ -2576,6 +2590,13 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
goto out_err;
prot = dir2prot(direction);
+ if (translation_pre_enabled(iommu) && !dev_data->domain_updated) {
+ dev_data->domain_updated = true;
+ set_dte_entry(dev_data->devid, domain, dev_data->ats.enabled);
+ if (alias != dev_data->devid)
+ set_dte_entry(alias, domain, dev_data->ats.enabled);
+ device_flush_dte(dev_data);
+ }
/* Map all sg entries */
for_each_sg(sglist, s, nelems, i) {
--
2.5.5
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web