[PATCH v2 1/1] iommu/vt-d: Fix list_add double add when enabling VMD and scalable mode
From: Adrian Huang When enabling VMD and IOMMU scalable mode, the following kernel panic call trace/kernel log is shown in Eagle Stream platform (Sapphire Rapids CPU) during booting: pci :59:00.5: Adding to iommu group 42 ... vmd :59:00.5: PCI host bridge to bus 1:80 pci 1:80:01.0: [8086:352a] type 01 class 0x060400 pci 1:80:01.0: reg 0x10: [mem 0x-0x0001 64bit] pci 1:80:01.0: enabling Extended Tags pci 1:80:01.0: PME# supported from D0 D3hot D3cold pci 1:80:01.0: DMAR: Setup RID2PASID failed pci 1:80:01.0: Failed to add to iommu group 42: -16 pci 1:80:03.0: [8086:352b] type 01 class 0x060400 pci 1:80:03.0: reg 0x10: [mem 0x-0x0001 64bit] pci 1:80:03.0: enabling Extended Tags pci 1:80:03.0: PME# supported from D0 D3hot D3cold list_add double add: new=ff4d61160b74b8a0, prev=ff4d611d8e245c10, next=ff4d61160b74b8a0. [ cut here ] kernel BUG at lib/list_debug.c:29! invalid opcode: [#1] PREEMPT SMP NOPTI CPU: 0 PID: 7 Comm: kworker/0:1 Not tainted 5.17.0-rc3+ #7 Hardware name: Lenovo ThinkSystem SR650V3/SB27A86647, BIOS ESE101Y-1.00 01/13/2022 Workqueue: events work_for_cpu_fn RIP: 0010:__list_add_valid.cold+0x26/0x3f Code: 9a 4a ab ff 4c 89 c1 48 c7 c7 40 0c d9 9e e8 b9 b1 fe ff 0f 0b 48 89 f2 4c 89 c1 48 89 fe 48 c7 c7 f0 0c d9 9e e8 a2 b1 fe ff <0f> 0b 48 89 d1 4c 89 c6 4c 89 ca 48 c7 c7 98 0c d9 9e e8 8b b1 fe RSP: :ff5ad434865b3a40 EFLAGS: 00010246 RAX: 0058 RBX: ff4d61160b74b880 RCX: ff4d61255e1fffa8 RDX: RSI: fffe RDI: 9fd34f20 RBP: ff4d611d8e245c00 R08: R09: ff5ad434865b3888 R10: ff5ad434865b3880 R11: ff4d61257fdc6fe8 R12: ff4d61160b74b8a0 R13: ff4d61160b74b8a0 R14: ff4d611d8e245c10 R15: ff4d611d8001ba70 FS: () GS:ff4d611d5ea0() knlGS: CS: 0010 DS: ES: CR0: 80050033 CR2: ff4d611fa1401000 CR3: 000aa0210001 CR4: 00771ef0 DR0: DR1: DR2: DR3: DR6: fffe07f0 DR7: 0400 PKRU: 5554 Call Trace: intel_pasid_alloc_table+0x9c/0x1d0 dmar_insert_one_dev_info+0x423/0x540 ? device_to_iommu+0x12d/0x2f0 intel_iommu_attach_device+0x116/0x290 __iommu_attach_device+0x1a/0x90 iommu_group_add_device+0x190/0x2c0 __iommu_probe_device+0x13e/0x250 iommu_probe_device+0x24/0x150 iommu_bus_notifier+0x69/0x90 blocking_notifier_call_chain+0x5a/0x80 device_add+0x3db/0x7b0 ? arch_memremap_can_ram_remap+0x19/0x50 ? memremap+0x75/0x140 pci_device_add+0x193/0x1d0 pci_scan_single_device+0xb9/0xf0 pci_scan_slot+0x4c/0x110 pci_scan_child_bus_extend+0x3a/0x290 vmd_enable_domain.constprop.0+0x63e/0x820 vmd_probe+0x163/0x190 local_pci_probe+0x42/0x80 work_for_cpu_fn+0x13/0x20 process_one_work+0x1e2/0x3b0 worker_thread+0x1c4/0x3a0 ? rescuer_thread+0x370/0x370 kthread+0xc7/0xf0 ? kthread_complete_and_exit+0x20/0x20 ret_from_fork+0x1f/0x30 Modules linked in: ---[ end trace ]--- ... Kernel panic - not syncing: Fatal exception Kernel Offset: 0x1ca0 from 0x8100 (relocation range: 0x8000-0xbfff) ---[ end Kernel panic - not syncing: Fatal exception ]--- The following 'lspci' output shows devices '1:80:*' are subdevices of the VMD device :59:00.5: $ lspci ... :59:00.5 RAID bus controller: Intel Corporation Volume Management Device NVMe RAID Controller (rev 20) ... 1:80:01.0 PCI bridge: Intel Corporation Device 352a (rev 03) 1:80:03.0 PCI bridge: Intel Corporation Device 352b (rev 03) 1:80:05.0 PCI bridge: Intel Corporation Device 352c (rev 03) 1:80:07.0 PCI bridge: Intel Corporation Device 352d (rev 03) 1:81:00.0 Non-Volatile memory controller: Intel Corporation NVMe Datacenter SSD [3DNAND, Beta Rock Controller] 1:82:00.0 Non-Volatile memory controller: Intel Corporation NVMe Datacenter SSD [3DNAND, Beta Rock Controller] The symptom 'list_add double add' is caused by the following failure message: pci 1:80:01.0: DMAR: Setup RID2PASID failed pci 1:80:01.0: Failed to add to iommu group 42: -16 pci 1:80:03.0: [8086:352b] type 01 class 0x060400 Device 1:80:01.0 is the subdevice of the VMD device :59:00.5, so invoking intel_pasid_alloc_table() gets the pasid_table of the VMD device :59:00.5. Here is call path: intel_pasid_alloc_table pci_for_each_dma_alias get_alias_pasid_table search_pasid_table pci_real_dma_dev() in pci_for_each_dma_alias() gets the real dma device which is the VMD device :59:00.5. However, pte of the VMD device :59:00.5 has been configured during this message "pci :59:00.5: Adding to iommu group 42". So, the status -EBUSY is returned when configuring pasid entry for device 1:80:01.0. It then invokes dmar_remove_one_dev_info() to release 'struct device_dom
[PATCH] iommu/vt-d: Fix list_add double add when enabling VMD and scalable mode
From: Adrian Huang When enabling VMD and IOMMU scalable mode, the following kernel panic call trace/kernel log is shown in Eagle Stream platform (Sapphire Rapids CPU) during booting: pci :59:00.5: Adding to iommu group 42 ... vmd :59:00.5: PCI host bridge to bus 1:80 pci 1:80:01.0: [8086:352a] type 01 class 0x060400 pci 1:80:01.0: reg 0x10: [mem 0x-0x0001 64bit] pci 1:80:01.0: enabling Extended Tags pci 1:80:01.0: PME# supported from D0 D3hot D3cold pci 1:80:01.0: DMAR: Setup RID2PASID failed pci 1:80:01.0: Failed to add to iommu group 42: -16 pci 1:80:03.0: [8086:352b] type 01 class 0x060400 pci 1:80:03.0: reg 0x10: [mem 0x-0x0001 64bit] pci 1:80:03.0: enabling Extended Tags pci 1:80:03.0: PME# supported from D0 D3hot D3cold list_add double add: new=ff4d61160b74b8a0, prev=ff4d611d8e245c10, next=ff4d61160b74b8a0. [ cut here ] kernel BUG at lib/list_debug.c:29! invalid opcode: [#1] PREEMPT SMP NOPTI CPU: 0 PID: 7 Comm: kworker/0:1 Not tainted 5.17.0-rc3+ #7 Hardware name: Lenovo ThinkSystem SR650V3/SB27A86647, BIOS ESE101Y-1.00 01/13/2022 Workqueue: events work_for_cpu_fn RIP: 0010:__list_add_valid.cold+0x26/0x3f Code: 9a 4a ab ff 4c 89 c1 48 c7 c7 40 0c d9 9e e8 b9 b1 fe ff 0f 0b 48 89 f2 4c 89 c1 48 89 fe 48 c7 c7 f0 0c d9 9e e8 a2 b1 fe ff <0f> 0b 48 89 d1 4c 89 c6 4c 89 ca 48 c7 c7 98 0c d9 9e e8 8b b1 fe RSP: :ff5ad434865b3a40 EFLAGS: 00010246 RAX: 0058 RBX: ff4d61160b74b880 RCX: ff4d61255e1fffa8 RDX: RSI: fffe RDI: 9fd34f20 RBP: ff4d611d8e245c00 R08: R09: ff5ad434865b3888 R10: ff5ad434865b3880 R11: ff4d61257fdc6fe8 R12: ff4d61160b74b8a0 R13: ff4d61160b74b8a0 R14: ff4d611d8e245c10 R15: ff4d611d8001ba70 FS: () GS:ff4d611d5ea0() knlGS: CS: 0010 DS: ES: CR0: 80050033 CR2: ff4d611fa1401000 CR3: 000aa0210001 CR4: 00771ef0 DR0: DR1: DR2: DR3: DR6: fffe07f0 DR7: 0400 PKRU: 5554 Call Trace: intel_pasid_alloc_table+0x9c/0x1d0 dmar_insert_one_dev_info+0x423/0x540 ? device_to_iommu+0x12d/0x2f0 intel_iommu_attach_device+0x116/0x290 __iommu_attach_device+0x1a/0x90 iommu_group_add_device+0x190/0x2c0 __iommu_probe_device+0x13e/0x250 iommu_probe_device+0x24/0x150 iommu_bus_notifier+0x69/0x90 blocking_notifier_call_chain+0x5a/0x80 device_add+0x3db/0x7b0 ? arch_memremap_can_ram_remap+0x19/0x50 ? memremap+0x75/0x140 pci_device_add+0x193/0x1d0 pci_scan_single_device+0xb9/0xf0 pci_scan_slot+0x4c/0x110 pci_scan_child_bus_extend+0x3a/0x290 vmd_enable_domain.constprop.0+0x63e/0x820 vmd_probe+0x163/0x190 local_pci_probe+0x42/0x80 work_for_cpu_fn+0x13/0x20 process_one_work+0x1e2/0x3b0 worker_thread+0x1c4/0x3a0 ? rescuer_thread+0x370/0x370 kthread+0xc7/0xf0 ? kthread_complete_and_exit+0x20/0x20 ret_from_fork+0x1f/0x30 Modules linked in: ---[ end trace ]--- ... Kernel panic - not syncing: Fatal exception Kernel Offset: 0x1ca0 from 0x8100 (relocation range: 0x8000-0xbfff) ---[ end Kernel panic - not syncing: Fatal exception ]--- The following 'lspci' output shows devices '1:80:*' are subdevices of the VMD device :59:00.5: $ lspci ... :59:00.5 RAID bus controller: Intel Corporation Volume Management Device NVMe RAID Controller (rev 20) ... 1:80:01.0 PCI bridge: Intel Corporation Device 352a (rev 03) 1:80:03.0 PCI bridge: Intel Corporation Device 352b (rev 03) 1:80:05.0 PCI bridge: Intel Corporation Device 352c (rev 03) 1:80:07.0 PCI bridge: Intel Corporation Device 352d (rev 03) 1:81:00.0 Non-Volatile memory controller: Intel Corporation NVMe Datacenter SSD [3DNAND, Beta Rock Controller] 1:82:00.0 Non-Volatile memory controller: Intel Corporation NVMe Datacenter SSD [3DNAND, Beta Rock Controller] The symptom 'list_add double add' is caused by the following failure message: pci 1:80:01.0: DMAR: Setup RID2PASID failed pci 1:80:01.0: Failed to add to iommu group 42: -16 pci 1:80:03.0: [8086:352b] type 01 class 0x060400 Device 1:80:01.0 is the subdevice of the VMD device :59:00.5, so invoking intel_pasid_alloc_table() gets the pasid_table of the VMD device :59:00.5. Here is call path: intel_pasid_alloc_table pci_for_each_dma_alias get_alias_pasid_table search_pasid_table pci_real_dma_dev() in pci_for_each_dma_alias() gets the real dma device which is the VMD device :59:00.5. However, pte of the VMD device :59:00.5 has been configured during this message "pci :59:00.5: Adding to iommu group 42". So, the status -EBUSY is returned when configuring pasid entry for device 1:80:01.0. It then invokes dmar_remove_one_dev_info() to release 'struct device_dom
[RESEND PATCH 1/1] iommu/amd: Remove unnecessary assignment
From: Adrian Huang From: Adrian Huang The values of local variables are assigned after local variables are declared, so no need to assign the initial value during the variable declaration. And, no need to assign NULL for the local variable 'ivrs_base' after invoking acpi_put_table(). Signed-off-by: Adrian Huang --- drivers/iommu/amd/init.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 23a790f8f550..103cbf8fc2d9 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -1916,7 +1916,7 @@ static void print_iommu_info(void) static int __init amd_iommu_init_pci(void) { struct amd_iommu *iommu; - int ret = 0; + int ret; for_each_iommu(iommu) { ret = iommu_init_pci(iommu); @@ -2555,8 +2555,8 @@ static void __init free_dma_resources(void) static int __init early_amd_iommu_init(void) { struct acpi_table_header *ivrs_base; + int i, remap_cache_sz, ret; acpi_status status; - int i, remap_cache_sz, ret = 0; u32 pci_id; if (!amd_iommu_detected) @@ -2698,7 +2698,6 @@ static int __init early_amd_iommu_init(void) out: /* Don't leak any ACPI memory */ acpi_put_table(ivrs_base); - ivrs_base = NULL; return ret; } -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/1] iommu/amd: Remove unnecessary assignment
From: Adrian Huang The values of local variables are assigned after local variables are declared, so no need to assign the initial value during the variable declaration. And, no need to assign NULL for the local variable 'ivrs_base' after invoking acpi_put_table(). Signed-off-by: Adrian Huang --- drivers/iommu/amd/init.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 1ba6b4cc56e8..f171078f7ea0 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -1858,7 +1858,7 @@ static void print_iommu_info(void) static int __init amd_iommu_init_pci(void) { struct amd_iommu *iommu; - int ret = 0; + int ret; for_each_iommu(iommu) { ret = iommu_init_pci(iommu); @@ -2494,8 +2494,8 @@ static void __init free_dma_resources(void) static int __init early_amd_iommu_init(void) { struct acpi_table_header *ivrs_base; + int i, remap_cache_sz, ret; acpi_status status; - int i, remap_cache_sz, ret = 0; u32 pci_id; if (!amd_iommu_detected) @@ -2637,7 +2637,6 @@ static int __init early_amd_iommu_init(void) out: /* Don't leak any ACPI memory */ acpi_put_table(ivrs_base); - ivrs_base = NULL; return ret; } -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/1] iommu/amd: Fix the overwritten field in IVMD header
From: Adrian Huang Commit 387caf0b759a ("iommu/amd: Treat per-device exclusion ranges as r/w unity-mapped regions") accidentally overwrites the 'flags' field in IVMD (struct ivmd_header) when the I/O virtualization memory definition is associated with the exclusion range entry. This leads to the corrupted IVMD table (incorrect checksum). The kdump kernel reports the invalid checksum: ACPI BIOS Warning (bug): Incorrect checksum in table [IVRS] - 0x5C, should be 0x60 (20200717/tbprint-177) AMD-Vi: [Firmware Bug]: IVRS invalid checksum Fix the above-mentioned issue by modifying the 'struct unity_map_entry' member instead of the IVMD header. Cleanup: The *exclusion_range* functions are not used anymore, so get rid of them. Fixes: 387caf0b759a ("iommu/amd: Treat per-device exclusion ranges as r/w unity-mapped regions") Reported-and-tested-by: Baoquan He Signed-off-by: Adrian Huang Cc: Jerry Snitselaar --- drivers/iommu/amd/init.c | 56 +++- 1 file changed, 10 insertions(+), 46 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 445a08d23fed..1ba6b4cc56e8 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -1103,25 +1103,6 @@ static int __init add_early_maps(void) return 0; } -/* - * Reads the device exclusion range from ACPI and initializes the IOMMU with - * it - */ -static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) -{ - if (!(m->flags & IVMD_FLAG_EXCL_RANGE)) - return; - - /* -* Treat per-device exclusion ranges as r/w unity-mapped regions -* since some buggy BIOSes might lead to the overwritten exclusion -* range (exclusion_start and exclusion_length members). This -* happens when there are multiple exclusion ranges (IVMD entries) -* defined in ACPI table. -*/ - m->flags = (IVMD_FLAG_IW | IVMD_FLAG_IR | IVMD_FLAG_UNITY_MAP); -} - /* * Takes a pointer to an AMD IOMMU entry in the ACPI table and * initializes the hardware and our data structures with it. @@ -2073,30 +2054,6 @@ static void __init free_unity_maps(void) } } -/* called when we find an exclusion range definition in ACPI */ -static int __init init_exclusion_range(struct ivmd_header *m) -{ - int i; - - switch (m->type) { - case ACPI_IVMD_TYPE: - set_device_exclusion_range(m->devid, m); - break; - case ACPI_IVMD_TYPE_ALL: - for (i = 0; i <= amd_iommu_last_bdf; ++i) - set_device_exclusion_range(i, m); - break; - case ACPI_IVMD_TYPE_RANGE: - for (i = m->devid; i <= m->aux; ++i) - set_device_exclusion_range(i, m); - break; - default: - break; - } - - return 0; -} - /* called for unity map ACPI definition */ static int __init init_unity_map_range(struct ivmd_header *m) { @@ -2107,9 +2064,6 @@ static int __init init_unity_map_range(struct ivmd_header *m) if (e == NULL) return -ENOMEM; - if (m->flags & IVMD_FLAG_EXCL_RANGE) - init_exclusion_range(m); - switch (m->type) { default: kfree(e); @@ -2133,6 +2087,16 @@ static int __init init_unity_map_range(struct ivmd_header *m) e->address_end = e->address_start + PAGE_ALIGN(m->range_length); e->prot = m->flags >> 1; + /* +* Treat per-device exclusion ranges as r/w unity-mapped regions +* since some buggy BIOSes might lead to the overwritten exclusion +* range (exclusion_start and exclusion_length members). This +* happens when there are multiple exclusion ranges (IVMD entries) +* defined in ACPI table. +*/ + if (m->flags & IVMD_FLAG_EXCL_RANGE) + e->prot = (IVMD_FLAG_IW | IVMD_FLAG_IR) >> 1; + DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x" " range_start: %016llx range_end: %016llx flags: %x\n", s, PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start), -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/1] iommu/amd: Fix the configuration of GCR3 table root pointer
From: Adrian Huang The SPA of the GCR3 table root pointer[51:31] masks 20 bits. However, this requires 21 bits (Please see the AMD IOMMU specification). This leads to the potential failure when the bit 51 of SPA of the GCR3 table root pointer is 1'. Signed-off-by: Adrian Huang --- drivers/iommu/amd_iommu_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index f8d01d6b00da..ca8c4522045b 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -348,7 +348,7 @@ #define DTE_GCR3_VAL_A(x) (((x) >> 12) & 0x7ULL) #define DTE_GCR3_VAL_B(x) (((x) >> 15) & 0x0ULL) -#define DTE_GCR3_VAL_C(x) (((x) >> 31) & 0xfULL) +#define DTE_GCR3_VAL_C(x) (((x) >> 31) & 0x1fULL) #define DTE_GCR3_INDEX_A 0 #define DTE_GCR3_INDEX_B 1 -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/1] iommu/amd: Remove the unnecessary assignment
From: Adrian Huang The assignment of the global variable 'iommu_detected' has been moved from amd_iommu_init_dma_ops() to amd_iommu_detect(), so this patch removes the assignment in amd_iommu_init_dma_ops(). Signed-off-by: Adrian Huang --- drivers/iommu/amd_iommu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index bd25674ee4db..79f08c0a1f00 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2297,7 +2297,6 @@ int __init amd_iommu_init_api(void) int __init amd_iommu_init_dma_ops(void) { swiotlb= (iommu_default_passthrough() || sme_me_mask) ? 1 : 0; - iommu_detected = 1; if (amd_iommu_unmap_flush) pr_info("IO/TLB flush on unmap enabled\n"); -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 0/2] iommu/amd: Optimization and cleanup for unused variables
This series optimizes the register reading by using readq instead of readl and cleans up the unused variables. Adrian Huang (2): iommu/amd: Replace two consecutive readl calls with one readq iommu/amd: Remove unused struct member drivers/iommu/amd_iommu_init.c | 6 +- drivers/iommu/amd_iommu_types.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/2] iommu/amd: Replace two consecutive readl calls with one readq
From: Adrian Huang Optimize the reigster reading by using readq instead of the two consecutive readl calls. Signed-off-by: Adrian Huang --- drivers/iommu/amd_iommu_init.c | 6 +- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index c5167fe0bd5f..cfdc4b60ccbe 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1718,7 +1718,6 @@ static const struct attribute_group *amd_iommu_groups[] = { static int __init iommu_init_pci(struct amd_iommu *iommu) { int cap_ptr = iommu->cap_ptr; - u32 low, high; int ret; iommu->dev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(iommu->devid), @@ -1736,10 +1735,7 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) amd_iommu_iotlb_sup = false; /* read extended feature bits */ - low = readl(iommu->mmio_base + MMIO_EXT_FEATURES); - high = readl(iommu->mmio_base + MMIO_EXT_FEATURES + 4); - - iommu->features = ((u64)high << 32) | low; + iommu->features = readq(iommu->mmio_base + MMIO_EXT_FEATURES); if (iommu_feature(iommu, FEATURE_GT)) { int glxval; -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 2/2] iommu/amd: Remove unused struct member
From: Adrian Huang Commit c805b428f206 ("iommu/amd: Remove amd_iommu_pd_list") removes the global list for the allocated protection domains. The corresponding member 'list' of the protection_domain struct is not used anymore, so it can be removed. Signed-off-by: Adrian Huang --- drivers/iommu/amd_iommu_types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 500f0b78879d..f8d01d6b00da 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -463,7 +463,6 @@ struct amd_irte_ops; * independent of their use. */ struct protection_domain { - struct list_head list; /* for list of all protection domains */ struct list_head dev_list; /* List of all devices in this domain */ struct iommu_domain domain; /* generic domain handle used by iommu core code */ -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/1] iommu/amd: Fix typos for PPR macros
From: Adrian Huang The bit 13 and bit 14 of the IOMMU control register are PPRLogEn and PPRIntEn. They are related to PPR (Peripheral Page Request) instead of 'PPF'. Fix them accrodingly. Signed-off-by: Adrian Huang --- drivers/iommu/amd_iommu_init.c | 4 ++-- drivers/iommu/amd_iommu_types.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index ba7ee4aa04f9..6e82aa606e2b 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -716,7 +716,7 @@ static void iommu_enable_ppr_log(struct amd_iommu *iommu) writel(0x00, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); writel(0x00, iommu->mmio_base + MMIO_PPR_TAIL_OFFSET); - iommu_feature_enable(iommu, CONTROL_PPFLOG_EN); + iommu_feature_enable(iommu, CONTROL_PPRLOG_EN); iommu_feature_enable(iommu, CONTROL_PPR_EN); } @@ -2035,7 +2035,7 @@ static int iommu_init_msi(struct amd_iommu *iommu) iommu_feature_enable(iommu, CONTROL_EVT_INT_EN); if (iommu->ppr_log != NULL) - iommu_feature_enable(iommu, CONTROL_PPFINT_EN); + iommu_feature_enable(iommu, CONTROL_PPRINT_EN); iommu_ga_log_enable(iommu); diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 798e1533a147..500f0b78879d 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -147,8 +147,8 @@ #define CONTROL_COHERENT_EN 0x0aULL #define CONTROL_ISOC_EN 0x0bULL #define CONTROL_CMDBUF_EN 0x0cULL -#define CONTROL_PPFLOG_EN 0x0dULL -#define CONTROL_PPFINT_EN 0x0eULL +#define CONTROL_PPRLOG_EN 0x0dULL +#define CONTROL_PPRINT_EN 0x0eULL #define CONTROL_PPR_EN 0x0fULL #define CONTROL_GT_EN 0x10ULL #define CONTROL_GA_EN 0x11ULL -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/1] iommu/amd: Remove local variables
From: Adrian Huang The usage of the local variables 'range' and 'misc' was removed from commit 226e889b20a9 ("iommu/amd: Remove first/last_device handling") and commit 23c742db2171 ("iommu/amd: Split out PCI related parts of IOMMU initialization"). So, remove them accrodingly. Signed-off-by: Adrian Huang --- drivers/iommu/amd_iommu_init.c | 6 +- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index ba7ee4aa04f9..2cc7d61b1802 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1718,7 +1718,7 @@ static const struct attribute_group *amd_iommu_groups[] = { static int __init iommu_init_pci(struct amd_iommu *iommu) { int cap_ptr = iommu->cap_ptr; - u32 range, misc, low, high; + u32 low, high; int ret; iommu->dev = pci_get_domain_bus_and_slot(0, PCI_BUS_NUM(iommu->devid), @@ -1731,10 +1731,6 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET, >cap); - pci_read_config_dword(iommu->dev, cap_ptr + MMIO_RANGE_OFFSET, - ); - pci_read_config_dword(iommu->dev, cap_ptr + MMIO_MISC_OFFSET, - ); if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB))) amd_iommu_iotlb_sup = false; -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/1] iommu/amd: Treat per-device exclusion ranges as r/w unity-mapped regions
Some buggy BIOSes might define multiple exclusion ranges of the IVMD entries which are associated with the same IOMMU hardware. This leads to the overwritten exclusion range (exclusion_start and exclusion_length members) in set_device_exclusion_range(). Here is a real case: When attaching two Broadcom RAID controllers to a server, the first one reports the failure during booting (the disks connecting to the RAID controller cannot be detected). This patch prevents the issue by treating per-device exclusion ranges as r/w unity-mapped regions. Discussion: * https://lists.linuxfoundation.org/pipermail/iommu/2019-November/040140.html Suggested-by: Joerg Roedel Signed-off-by: Adrian Huang --- drivers/iommu/amd_iommu_init.c | 20 ++-- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 568c52317757..1b65302e07b1 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -71,6 +71,8 @@ #define IVHD_FLAG_ISOC_EN_MASK 0x08 #define IVMD_FLAG_EXCL_RANGE0x08 +#define IVMD_FLAG_IW0x04 +#define IVMD_FLAG_IR0x02 #define IVMD_FLAG_UNITY_MAP 0x01 #define ACPI_DEVFLAG_INITPASS 0x01 @@ -1121,16 +1123,14 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) if (!(m->flags & IVMD_FLAG_EXCL_RANGE)) return; - if (iommu) { - /* -* We only can configure exclusion ranges per IOMMU, not -* per device. But we can enable the exclusion range per -* device. This is done here -*/ - set_dev_entry_bit(devid, DEV_ENTRY_EX); - iommu->exclusion_start = m->range_start; - iommu->exclusion_length = m->range_length; - } + /* +* Treat per-device exclusion ranges as r/w unity-mapped regions +* since some buggy BIOSes might lead to the overwritten exclusion +* range (exclusion_start and exclusion_length members). This +* happens when there are multiple exclusion ranges (IVMD entries) +* defined in ACPI table. +*/ + m->flags = (IVMD_FLAG_IW | IVMD_FLAG_IR | IVMD_FLAG_UNITY_MAP); } /* -- 2.17.1 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH 1/1] iommu/amd: Fix the overwritten exclusion range with multiple IVMDs
When attaching two Broadcom RAID controllers to a server, the first one reports the failure during booting (the disks connecting to the RAID controller cannot be detected): megaraid_sas :42:00.0: Init cmd return status FAILED for SCSI host 0 megaraid_sas :42:00.0: Failed from megasas_init_fw 6376 Root-cause of the issue: 1) Those two RAID controllers define their own IVMDs with the valid exclusion range, and they are associated with the same IOMMU hardware: Subtable Type : 10 [Hardware Definition Block] Flags : B0 Length : 0028 DeviceId : 4002 Capability Offset : 0040 Base Address : B410 PCI Segment Group : Virtualization Info : Reserved : 80048F6F Entry Type : 03 Device ID : 4008 Data Setting : 00 Entry Type : 04 Device ID : 7FFE Data Setting : 00 Subtable Type : 21 [Memory Definition Block] Flags : 08 Length : 0020 DeviceId : 4200 Auxiliary Data : Reserved : Start Address : 9F58D000 Memory Length : 0804 Subtable Type : 21 [Memory Definition Block] Flags : 08 Length : 0020 DeviceId : 4300 Auxiliary Data : Reserved : Start Address : 9754D000 Memory Length : 0804 2) When set_device_exclusion_range() parses the IVMD of devce id '4200', the exclusion range of the amd_iommu struct becomes: iommu->exclusion_start = 0x9F58D000; iommu->exclusion_length = 0x804; 3) When parsing the second IVMD (device id '4300') in set_device_exclusion_range(), the exclusion range of the amd_iommu struct becomes: iommu->exclusion_start = 0x9754D000; iommu->exclusion_length = 0x804; This overwrites the first IVMD configuration, which leads to the failure of the first RAID controller. This patch fixes the issue by using unity map for multiple IVMDs if those IVMDs define the valid exclusion range (different exclusion range) and they are associated with the same IOMMU hardware. Note that the first IVMD still uses the exclusion range. Signed-off-by: Adrian Huang --- drivers/iommu/amd_iommu_init.c | 33 +++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 568c52317757..d65b548a42f5 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -71,6 +71,8 @@ #define IVHD_FLAG_ISOC_EN_MASK 0x08 #define IVMD_FLAG_EXCL_RANGE0x08 +#define IVMD_FLAG_IW0x04 +#define IVMD_FLAG_IR0x02 #define IVMD_FLAG_UNITY_MAP 0x01 #define ACPI_DEVFLAG_INITPASS 0x01 @@ -1110,6 +1112,32 @@ static int __init add_early_maps(void) return 0; } +static int __init exclusion_range_has_configured(struct amd_iommu *iommu, + struct ivmd_header *m) +{ + /* Not configure yet. */ + if (!iommu->exclusion_start) { + iommu->exclusion_start = m->range_start; + iommu->exclusion_length = m->range_length; + + return 0; + } + + if (iommu->exclusion_start == m->range_start && + iommu->exclusion_length == m->range_length) + return 0; + + /* +* The exclusion range of the iommu has been configured +* by the other IVMD, so we need to use unity map for this +* IVMD to avoid the overwritten exclusion range members of the +* amd_iommu structure. +*/ + m->flags = (IVMD_FLAG_IW | IVMD_FLAG_IR | IVMD_FLAG_UNITY_MAP); + + return 1; +} + /* * Reads the device exclusion range from ACPI and initializes the IOMMU with * it @@ -1122,14 +1150,15 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) return; if (iommu) { + if (exclusion_range_has_configured(iommu, m)) + return; + /* * We only can configure exclusion ranges per IOMMU, not * per device. But we can enable the exclusion range per * device. This is done here */