From 387caf0b759ac437a65ad5d59665558025f350fc Mon Sep 17 00:00:00 2001 From: Adrian Huang Date: Thu, 14 Nov 2019 14:14:47 +0800 Subject: 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 Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/iommu/amd_iommu_init.c') 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_RANGE 0x08 +#define IVMD_FLAG_IW 0x04 +#define IVMD_FLAG_IR 0x02 #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); } /* -- cgit v1.2.3 From 813071438e83d338ba5cfe98b3b26c890dc0a6c0 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Wed, 20 Nov 2019 07:55:48 -0600 Subject: iommu/amd: Check feature support bit before accessing MSI capability registers The IOMMU MMIO access to MSI capability registers is available only if the EFR[MsiCapMmioSup] is set. Current implementation assumes this bit is set if the EFR[XtSup] is set, which might not be the case. Fix by checking the EFR[MsiCapMmioSup] before accessing the MSI address low/high and MSI data registers via the MMIO. Fixes: 66929812955b ('iommu/amd: Add support for X2APIC IOMMU interrupts') Signed-off-by: Suravee Suthikulpanit Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/iommu/amd_iommu_init.c') diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 1b65302e07b1..f46e4aba3d91 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -149,7 +149,7 @@ bool amd_iommu_dump; bool amd_iommu_irq_remap __read_mostly; int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC; -static int amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE; +static int amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE; static bool amd_iommu_detected; static bool __initdata amd_iommu_disabled; @@ -1534,8 +1534,15 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; if (((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0)) amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; - if (((h->efr_reg & (0x1 << IOMMU_EFR_XTSUP_SHIFT)) == 0)) - amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE; + /* + * Note: Since iommu_update_intcapxt() leverages + * the IOMMU MMIO access to MSI capability block registers + * for MSI address lo/hi/data, we need to check both + * EFR[XtSup] and EFR[MsiCapMmioSup] for x2APIC support. + */ + if ((h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT)) && + (h->efr_reg & BIT(IOMMU_EFR_MSICAPMMIOSUP_SHIFT))) + amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE; break; default: return -EINVAL; @@ -1984,8 +1991,8 @@ static int iommu_init_intcapxt(struct amd_iommu *iommu) struct irq_affinity_notify *notify = &iommu->intcapxt_notify; /** - * IntCapXT requires XTSup=1, which can be inferred - * amd_iommu_xt_mode. + * IntCapXT requires XTSup=1 and MsiCapMmioSup=1, + * which can be inferred from amd_iommu_xt_mode. */ if (amd_iommu_xt_mode != IRQ_REMAP_X2APIC_MODE) return 0; -- cgit v1.2.3 From 966b753cf3969553ca50bacd2b8c4ddade5ecc9e Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Wed, 20 Nov 2019 07:55:49 -0600 Subject: iommu/amd: Only support x2APIC with IVHD type 11h/40h Current implementation for IOMMU x2APIC support makes use of the MMIO access to MSI capability block registers, which requires checking EFR[MsiCapMmioSup]. However, only IVHD type 11h/40h contain the information, and not in the IVHD type 10h IOMMU feature reporting field. Since the BIOS in newer systems, which supports x2APIC, would normally contain IVHD type 11h/40h, remove the IOMMU_FEAT_XTSUP_SHIFT check for IVHD type 10h, and only support x2APIC with IVHD type 11h/40h. Fixes: 66929812955b ('iommu/amd: Add support for X2APIC IOMMU interrupts') Signed-off-by: Suravee Suthikulpanit Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/iommu/amd_iommu_init.c') diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index f46e4aba3d91..36649592ddf3 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1523,8 +1523,6 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; if (((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0)) amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; - if (((h->efr_attr & (0x1 << IOMMU_FEAT_XTSUP_SHIFT)) == 0)) - amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE; break; case 0x11: case 0x40: -- cgit v1.2.3 From 2ca6b6dc8512abd697c251c3e492fb12f3cb1856 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Dec 2019 14:09:46 +0100 Subject: iommu/amd: Remove unused variable The iommu variable in set_device_exclusion_range() us unused now and causes a compiler warning. Remove it. Fixes: 387caf0b759a ("iommu/amd: Treat per-device exclusion ranges as r/w unity-mapped regions") Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/iommu/amd_iommu_init.c') diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 36649592ddf3..ba7ee4aa04f9 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1118,8 +1118,6 @@ static int __init add_early_maps(void) */ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) { - struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; - if (!(m->flags & IVMD_FLAG_EXCL_RANGE)) return; -- cgit v1.2.3 From 858defad2ae2b0ec9a0350d1414da2c2c933a054 Mon Sep 17 00:00:00 2001 From: Adrian Huang Date: Tue, 24 Dec 2019 22:46:47 +0800 Subject: iommu/amd: Remove local variables 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 Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/iommu/amd_iommu_init.c') 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, &iommu->cap); - pci_read_config_dword(iommu->dev, cap_ptr + MMIO_RANGE_OFFSET, - &range); - pci_read_config_dword(iommu->dev, cap_ptr + MMIO_MISC_OFFSET, - &misc); if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB))) amd_iommu_iotlb_sup = false; -- cgit v1.2.3 From bde9e6b9ba755e35768261a5ea15541a4c4b4de8 Mon Sep 17 00:00:00 2001 From: Adrian Huang Date: Mon, 30 Dec 2019 13:56:54 +0800 Subject: iommu/amd: Fix typos for PPR macros 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 Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iommu/amd_iommu_init.c') diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 2cc7d61b1802..c5167fe0bd5f 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); } @@ -2031,7 +2031,7 @@ enable_faults: 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); -- cgit v1.2.3 From 62dcee71608506ad83b0525aa1b53a78b3f1689a Mon Sep 17 00:00:00 2001 From: Adrian Huang Date: Thu, 9 Jan 2020 11:02:50 +0800 Subject: iommu/amd: Replace two consecutive readl calls with one readq Optimize the reigster reading by using readq instead of the two consecutive readl calls. Signed-off-by: Adrian Huang Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/iommu/amd_iommu_init.c') 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; -- cgit v1.2.3