From 98f1ad258254d89ffb550a36d59caf9127a9d53f Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 6 Jul 2012 13:28:37 +0200 Subject: iommu/amd: Fix sparse warnings A few sparse warnings fire in drivers/iommu/amd_iommu_init.c. Fix most of them with this patch. Also fix the sparse warnings in drivers/iommu/irq_remapping.c while at it. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 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 a33612f3206f..55f2033ea69b 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -190,12 +190,6 @@ static u32 dev_table_size; /* size of the device table */ static u32 alias_table_size; /* size of the alias table */ static u32 rlookup_table_size; /* size if the rlookup table */ -/* - * This function flushes all internal caches of - * the IOMMU used by this driver. - */ -extern void iommu_flush_all_caches(struct amd_iommu *iommu); - static int amd_iommu_enable_interrupts(void); static inline void update_last_devid(u16 devid) @@ -358,7 +352,7 @@ static void iommu_disable(struct amd_iommu *iommu) * mapping and unmapping functions for the IOMMU MMIO space. Each AMD IOMMU in * the system has one. */ -static u8 * __init iommu_map_mmio_space(u64 address) +static u8 __iomem * __init iommu_map_mmio_space(u64 address) { if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu")) { pr_err("AMD-Vi: Can not reserve memory region %llx for mmio\n", @@ -367,7 +361,7 @@ static u8 * __init iommu_map_mmio_space(u64 address) return NULL; } - return ioremap_nocache(address, MMIO_REGION_LENGTH); + return (u8 __iomem *)ioremap_nocache(address, MMIO_REGION_LENGTH); } static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu) @@ -1217,7 +1211,7 @@ static int __init init_exclusion_range(struct ivmd_header *m) /* called for unity map ACPI definition */ static int __init init_unity_map_range(struct ivmd_header *m) { - struct unity_map_entry *e = 0; + struct unity_map_entry *e = NULL; char *s; e = kzalloc(sizeof(*e), GFP_KERNEL); @@ -1727,8 +1721,8 @@ __setup("amd_iommu=", parse_amd_iommu_options); IOMMU_INIT_FINISH(amd_iommu_detect, gart_iommu_hole_init, - 0, - 0); + NULL, + NULL); bool amd_iommu_v2_supported(void) { -- cgit v1.2.3 From 02f3b3f5449cd0d9c4fb2c6f85f2973adefb7c72 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 11 Jun 2012 17:45:25 +0200 Subject: iommu/amd: Use acpi_get_table instead of acpi_table_parse This makes it easier to propagate errors while parsing the IVRS table and makes the amd_iommu_init_err hack obsolete. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 118 +++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 52 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 55f2033ea69b..de7a6cedcc45 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -122,7 +124,7 @@ struct ivmd_header { bool amd_iommu_dump; -static int __initdata amd_iommu_detected; +static bool amd_iommu_detected; static bool __initdata amd_iommu_disabled; u16 amd_iommu_last_bdf; /* largest PCI device id we have @@ -148,11 +150,6 @@ bool amd_iommu_v2_present __read_mostly; bool amd_iommu_force_isolation __read_mostly; -/* - * The ACPI table parsing functions set this variable on an error - */ -static int __initdata amd_iommu_init_err; - /* * List of protection domains - used during resume */ @@ -457,11 +454,9 @@ static int __init find_last_devid_acpi(struct acpi_table_header *table) */ for (i = 0; i < table->length; ++i) checksum += p[i]; - if (checksum != 0) { + if (checksum != 0) /* ACPI table corrupt */ - amd_iommu_init_err = -ENODEV; - return 0; - } + return -ENODEV; p += IVRS_HEADER_LENGTH; @@ -1087,16 +1082,12 @@ static int __init init_iommu_all(struct acpi_table_header *table) h->mmio_phys); iommu = kzalloc(sizeof(struct amd_iommu), GFP_KERNEL); - if (iommu == NULL) { - amd_iommu_init_err = -ENOMEM; - return 0; - } + if (iommu == NULL) + return -ENOMEM; ret = init_iommu_one(iommu, h); - if (ret) { - amd_iommu_init_err = ret; - return 0; - } + if (ret) + return ret; break; default: break; @@ -1477,9 +1468,15 @@ static void __init free_on_init_error(void) */ int __init amd_iommu_init_hardware(void) { + struct acpi_table_header *ivrs_base; + acpi_size ivrs_size; + acpi_status status; int i, ret = 0; - if (!amd_iommu_detected) + if (no_iommu || (iommu_detected && !gart_iommu_aperture)) + return -ENODEV; + + if (amd_iommu_disabled || !amd_iommu_detected) return -ENODEV; if (amd_iommu_dev_table != NULL) { @@ -1487,16 +1484,21 @@ int __init amd_iommu_init_hardware(void) return 0; } + status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size); + if (status == AE_NOT_FOUND) + return -ENODEV; + else if (ACPI_FAILURE(status)) { + const char *err = acpi_format_exception(status); + pr_err("AMD-Vi: IVRS table error: %s\n", err); + return -EINVAL; + } + /* * First parse ACPI tables to find the largest Bus/Dev/Func * we need to handle. Upon this information the shared data * structures for the IOMMUs in the system will be allocated */ - if (acpi_table_parse("IVRS", find_last_devid_acpi) != 0) - return -ENODEV; - - ret = amd_iommu_init_err; - if (ret) + if (find_last_devid_acpi(ivrs_base)) goto out; dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE); @@ -1553,22 +1555,13 @@ int __init amd_iommu_init_hardware(void) * now the data structures are allocated and basically initialized * start the real acpi table scan */ - ret = -ENODEV; - if (acpi_table_parse("IVRS", init_iommu_all) != 0) - goto free; - - if (amd_iommu_init_err) { - ret = amd_iommu_init_err; - goto free; - } - - if (acpi_table_parse("IVRS", init_memory_definitions) != 0) + ret = init_iommu_all(ivrs_base); + if (ret) goto free; - if (amd_iommu_init_err) { - ret = amd_iommu_init_err; + ret = init_memory_definitions(ivrs_base); + if (ret) goto free; - } ret = amd_iommu_init_devices(); if (ret) @@ -1581,12 +1574,16 @@ int __init amd_iommu_init_hardware(void) register_syscore_ops(&amd_iommu_syscore_ops); out: + /* Don't leak any ACPI memory */ + early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); + ivrs_base = NULL; + return ret; free: free_on_init_error(); - return ret; + goto out; } static int amd_iommu_enable_interrupts(void) @@ -1604,6 +1601,26 @@ out: return ret; } +static bool detect_ivrs(void) +{ + struct acpi_table_header *ivrs_base; + acpi_size ivrs_size; + acpi_status status; + + status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size); + if (status == AE_NOT_FOUND) + return false; + else if (ACPI_FAILURE(status)) { + const char *err = acpi_format_exception(status); + pr_err("AMD-Vi: IVRS table error: %s\n", err); + return false; + } + + early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); + + return true; +} + /* * This is the core init function for AMD IOMMU hardware in the system. * This function is called from the generic x86 DMA layer initialization @@ -1663,29 +1680,26 @@ free: * IOMMUs * ****************************************************************************/ -static int __init early_amd_iommu_detect(struct acpi_table_header *table) -{ - return 0; -} - int __init amd_iommu_detect(void) { + if (no_iommu || (iommu_detected && !gart_iommu_aperture)) return -ENODEV; if (amd_iommu_disabled) return -ENODEV; - if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) { - iommu_detected = 1; - amd_iommu_detected = 1; - x86_init.iommu.iommu_init = amd_iommu_init; + if (!detect_ivrs()) + return -ENODEV; - /* Make sure ACS will be enabled */ - pci_request_acs(); - return 1; - } - return -ENODEV; + amd_iommu_detected = true; + iommu_detected = 1; + x86_init.iommu.iommu_init = amd_iommu_init; + + /* Make sure ACS will be enabled */ + pci_request_acs(); + + return 0; } /**************************************************************************** -- cgit v1.2.3 From 23c742db217113585ccc6c4a9b6ff96d642b6158 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 12 Jun 2012 11:47:34 +0200 Subject: iommu/amd: Split out PCI related parts of IOMMU initialization For interrupt remapping the relevant IOMMU initialization needs to run earlier at boot when the PCI subsystem is not yet initialized. To support that this patch splits the parts of IOMMU initialization which need PCI accesses out of the initial setup path so that this can be done later. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 224 +++++++++++++++++++++------------------- drivers/iommu/amd_iommu_types.h | 5 +- 2 files changed, 121 insertions(+), 108 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 de7a6cedcc45..c3d650dea240 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -714,90 +714,6 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m) } } -/* - * This function reads some important data from the IOMMU PCI space and - * initializes the driver data structure with it. It reads the hardware - * capabilities and the first/last device entries - */ -static void __init init_iommu_from_pci(struct amd_iommu *iommu) -{ - int cap_ptr = iommu->cap_ptr; - u32 range, misc, low, high; - int i, j; - - 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); - - iommu->first_device = calc_devid(MMIO_GET_BUS(range), - MMIO_GET_FD(range)); - iommu->last_device = calc_devid(MMIO_GET_BUS(range), - MMIO_GET_LD(range)); - iommu->evt_msi_num = MMIO_MSI_NUM(misc); - - if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB))) - 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; - - if (iommu_feature(iommu, FEATURE_GT)) { - int glxval; - u32 pasids; - u64 shift; - - shift = iommu->features & FEATURE_PASID_MASK; - shift >>= FEATURE_PASID_SHIFT; - pasids = (1 << shift); - - amd_iommu_max_pasids = min(amd_iommu_max_pasids, pasids); - - glxval = iommu->features & FEATURE_GLXVAL_MASK; - glxval >>= FEATURE_GLXVAL_SHIFT; - - if (amd_iommu_max_glx_val == -1) - amd_iommu_max_glx_val = glxval; - else - amd_iommu_max_glx_val = min(amd_iommu_max_glx_val, glxval); - } - - if (iommu_feature(iommu, FEATURE_GT) && - iommu_feature(iommu, FEATURE_PPR)) { - iommu->is_iommu_v2 = true; - amd_iommu_v2_present = true; - } - - if (!is_rd890_iommu(iommu->dev)) - return; - - /* - * Some rd890 systems may not be fully reconfigured by the BIOS, so - * it's necessary for us to store this information so it can be - * reprogrammed on resume - */ - - pci_read_config_dword(iommu->dev, iommu->cap_ptr + 4, - &iommu->stored_addr_lo); - pci_read_config_dword(iommu->dev, iommu->cap_ptr + 8, - &iommu->stored_addr_hi); - - /* Low bit locks writes to configuration space */ - iommu->stored_addr_lo &= ~1; - - for (i = 0; i < 6; i++) - for (j = 0; j < 0x12; j++) - iommu->stored_l1[i][j] = iommu_read_l1(iommu, i, j); - - for (i = 0; i < 0x83; i++) - iommu->stored_l2[i] = iommu_read_l2(iommu, i); -} - /* * Takes a pointer to an AMD IOMMU entry in the ACPI table and * initializes the hardware and our data structures with it. @@ -1014,13 +930,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) /* * Copy data from ACPI table entry to the iommu struct */ - iommu->dev = pci_get_bus_and_slot(PCI_BUS(h->devid), h->devid & 0xff); - if (!iommu->dev) - return 1; - - iommu->root_pdev = pci_get_bus_and_slot(iommu->dev->bus->number, - PCI_DEVFN(0, 0)); - + iommu->devid = h->devid; iommu->cap_ptr = h->cap_ptr; iommu->pci_seg = h->pci_seg; iommu->mmio_phys = h->mmio_phys; @@ -1038,20 +948,10 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) iommu->int_enabled = false; - init_iommu_from_pci(iommu); init_iommu_from_acpi(iommu, h); init_iommu_devices(iommu); - if (iommu_feature(iommu, FEATURE_PPR)) { - iommu->ppr_log = alloc_ppr_log(iommu); - if (!iommu->ppr_log) - return -ENOMEM; - } - - if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) - amd_iommu_np_cache = true; - - return pci_enable_device(iommu->dev); + return 0; } /* @@ -1100,6 +1000,121 @@ static int __init init_iommu_all(struct acpi_table_header *table) return 0; } +static int iommu_init_pci(struct amd_iommu *iommu) +{ + int cap_ptr = iommu->cap_ptr; + u32 range, misc, low, high; + + iommu->dev = pci_get_bus_and_slot(PCI_BUS(iommu->devid), + iommu->devid & 0xff); + if (!iommu->dev) + return -ENODEV; + + 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); + + iommu->first_device = calc_devid(MMIO_GET_BUS(range), + MMIO_GET_FD(range)); + iommu->last_device = calc_devid(MMIO_GET_BUS(range), + MMIO_GET_LD(range)); + + if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB))) + 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; + + if (iommu_feature(iommu, FEATURE_GT)) { + int glxval; + u32 pasids; + u64 shift; + + shift = iommu->features & FEATURE_PASID_MASK; + shift >>= FEATURE_PASID_SHIFT; + pasids = (1 << shift); + + amd_iommu_max_pasids = min(amd_iommu_max_pasids, pasids); + + glxval = iommu->features & FEATURE_GLXVAL_MASK; + glxval >>= FEATURE_GLXVAL_SHIFT; + + if (amd_iommu_max_glx_val == -1) + amd_iommu_max_glx_val = glxval; + else + amd_iommu_max_glx_val = min(amd_iommu_max_glx_val, glxval); + } + + if (iommu_feature(iommu, FEATURE_GT) && + iommu_feature(iommu, FEATURE_PPR)) { + iommu->is_iommu_v2 = true; + amd_iommu_v2_present = true; + } + + if (iommu_feature(iommu, FEATURE_PPR)) { + iommu->ppr_log = alloc_ppr_log(iommu); + if (!iommu->ppr_log) + return -ENOMEM; + } + + if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) + amd_iommu_np_cache = true; + + if (is_rd890_iommu(iommu->dev)) { + int i, j; + + iommu->root_pdev = pci_get_bus_and_slot(iommu->dev->bus->number, + PCI_DEVFN(0, 0)); + + /* + * Some rd890 systems may not be fully reconfigured by the + * BIOS, so it's necessary for us to store this information so + * it can be reprogrammed on resume + */ + pci_read_config_dword(iommu->dev, iommu->cap_ptr + 4, + &iommu->stored_addr_lo); + pci_read_config_dword(iommu->dev, iommu->cap_ptr + 8, + &iommu->stored_addr_hi); + + /* Low bit locks writes to configuration space */ + iommu->stored_addr_lo &= ~1; + + for (i = 0; i < 6; i++) + for (j = 0; j < 0x12; j++) + iommu->stored_l1[i][j] = iommu_read_l1(iommu, i, j); + + for (i = 0; i < 0x83; i++) + iommu->stored_l2[i] = iommu_read_l2(iommu, i); + } + + return pci_enable_device(iommu->dev); +} + +static int amd_iommu_init_pci(void) +{ + struct amd_iommu *iommu; + int ret = 0; + + for_each_iommu(iommu) { + ret = iommu_init_pci(iommu); + if (ret) + break; + } + + /* Make sure ACS will be enabled */ + pci_request_acs(); + + ret = amd_iommu_init_devices(); + + return ret; +} + /**************************************************************************** * * The following functions initialize the MSI interrupts for all IOMMUs @@ -1563,7 +1578,7 @@ int __init amd_iommu_init_hardware(void) if (ret) goto free; - ret = amd_iommu_init_devices(); + ret = amd_iommu_init_pci(); if (ret) goto free; @@ -1696,9 +1711,6 @@ int __init amd_iommu_detect(void) iommu_detected = 1; x86_init.iommu.iommu_init = amd_iommu_init; - /* Make sure ACS will be enabled */ - pci_request_acs(); - return 0; } diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 848fc8e37948..d0dab865a8b8 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -501,6 +501,9 @@ struct amd_iommu { /* IOMMUv2 */ bool is_iommu_v2; + /* PCI device id of the IOMMU device */ + u16 devid; + /* * Capability pointer. There could be more than one IOMMU per PCI * device function if there are more than one AMD IOMMU capability @@ -530,8 +533,6 @@ struct amd_iommu { u32 evt_buf_size; /* event buffer virtual address */ u8 *evt_buf; - /* MSI number for event interrupt */ - u16 evt_msi_num; /* Base of the PPR log, if present */ u8 *ppr_log; -- cgit v1.2.3 From 4d121c3256edc66fe8a8e7f975eba72add120a26 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 14 Jun 2012 12:21:55 +0200 Subject: iommu/amd: Move informational prinks out of iommu_enable This function will be called before the PCI subsystem is initialized. Therefore dev_name doen't work and IOMMU information can't be printed to the klog as before. Move the code to print that information to a later point where PCI initializtion has already happened. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 44 ++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 17 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 c3d650dea240..b18034a8fdb3 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -312,23 +312,6 @@ static void iommu_set_inv_tlb_timeout(struct amd_iommu *iommu, int timeout) /* Function to enable the hardware */ static void iommu_enable(struct amd_iommu *iommu) { - static const char * const feat_str[] = { - "PreF", "PPR", "X2APIC", "NX", "GT", "[5]", - "IA", "GA", "HE", "PC", NULL - }; - int i; - - printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx", - dev_name(&iommu->dev->dev), iommu->cap_ptr); - - if (iommu->cap & (1 << IOMMU_CAP_EFR)) { - printk(KERN_CONT " extended features: "); - for (i = 0; feat_str[i]; ++i) - if (iommu_feature(iommu, (1ULL << i))) - printk(KERN_CONT " %s", feat_str[i]); - } - printk(KERN_CONT "\n"); - iommu_feature_enable(iommu, CONTROL_IOMMU_EN); } @@ -1096,6 +1079,31 @@ static int iommu_init_pci(struct amd_iommu *iommu) return pci_enable_device(iommu->dev); } +static void print_iommu_info(void) +{ + static const char * const feat_str[] = { + "PreF", "PPR", "X2APIC", "NX", "GT", "[5]", + "IA", "GA", "HE", "PC" + }; + struct amd_iommu *iommu; + + for_each_iommu(iommu) { + int i; + + pr_info("AMD-Vi: Found IOMMU at %s cap 0x%hx\n", + dev_name(&iommu->dev->dev), iommu->cap_ptr); + + if (iommu->cap & (1 << IOMMU_CAP_EFR)) { + pr_info("AMD-Vi: Extended features: "); + for (i = 0; ARRAY_SIZE(feat_str); ++i) { + if (iommu_feature(iommu, (1ULL << i))) + pr_cont(" %s", feat_str[i]); + } + } + pr_cont("\n"); + } +} + static int amd_iommu_init_pci(void) { struct amd_iommu *iommu; @@ -1112,6 +1120,8 @@ static int amd_iommu_init_pci(void) ret = amd_iommu_init_devices(); + print_iommu_info(); + return ret; } -- cgit v1.2.3 From 643511b37eb72d831646bacafaeace1eeadf5a54 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 12 Jun 2012 12:09:35 +0200 Subject: iommu/amd: Introduce early_amd_iommu_init routine Split out the code to parse the ACPI table and setup relevant data structures into a new function. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 1 - drivers/iommu/amd_iommu_init.c | 38 +++++++++++++++++++++++--------------- 2 files changed, 23 insertions(+), 16 deletions(-) (limited to 'drivers/iommu/amd_iommu_init.c') diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 7f8e7a8bf504..0d0dc8598c72 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -384,7 +384,6 @@ DECLARE_STATS_COUNTER(invalidate_iotlb); DECLARE_STATS_COUNTER(invalidate_iotlb_all); DECLARE_STATS_COUNTER(pri_requests); - static struct dentry *stats_dir; static struct dentry *de_fflush; diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index b18034a8fdb3..a5dbefb8e260 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1491,17 +1491,14 @@ static void __init free_on_init_error(void) * After everything is set up the IOMMUs are enabled and the necessary * hotplug and suspend notifiers are registered. */ -int __init amd_iommu_init_hardware(void) +static int __init early_amd_iommu_init(void) { struct acpi_table_header *ivrs_base; acpi_size ivrs_size; acpi_status status; int i, ret = 0; - if (no_iommu || (iommu_detected && !gart_iommu_aperture)) - return -ENODEV; - - if (amd_iommu_disabled || !amd_iommu_detected) + if (!amd_iommu_detected) return -ENODEV; if (amd_iommu_dev_table != NULL) { @@ -1588,16 +1585,6 @@ int __init amd_iommu_init_hardware(void) if (ret) goto free; - ret = amd_iommu_init_pci(); - if (ret) - goto free; - - enable_iommus(); - - amd_iommu_init_notifier(); - - register_syscore_ops(&amd_iommu_syscore_ops); - out: /* Don't leak any ACPI memory */ early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); @@ -1611,6 +1598,27 @@ free: goto out; } +int __init amd_iommu_init_hardware(void) +{ + int ret = 0; + + ret = early_amd_iommu_init(); + if (ret) + return ret; + + ret = amd_iommu_init_pci(); + if (ret) + return ret; + + enable_iommus(); + + amd_iommu_init_notifier(); + + register_syscore_ops(&amd_iommu_syscore_ops); + + return ret; +} + static int amd_iommu_enable_interrupts(void) { struct amd_iommu *iommu; -- cgit v1.2.3 From 11ee5ac47b78d7e117c84147596a124ce6421a3a Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 12 Jun 2012 16:30:06 +0200 Subject: iommu/amd: Split enable_iommus() routine Split the enable_iommus() routine so that a part of it can run in early code. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 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 a5dbefb8e260..b82cf447724e 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1379,7 +1379,7 @@ static void iommu_apply_resume_quirks(struct amd_iommu *iommu) * This function finally enables all IOMMUs found in the system after * they have been initialized */ -static void enable_iommus(void) +static void early_enable_iommus(void) { struct amd_iommu *iommu; @@ -1389,14 +1389,29 @@ static void enable_iommus(void) iommu_set_device_table(iommu); iommu_enable_command_buffer(iommu); iommu_enable_event_buffer(iommu); - iommu_enable_ppr_log(iommu); - iommu_enable_gt(iommu); iommu_set_exclusion_range(iommu); iommu_enable(iommu); iommu_flush_all_caches(iommu); } } +static void enable_iommus_v2(void) +{ + struct amd_iommu *iommu; + + for_each_iommu(iommu) { + iommu_enable_ppr_log(iommu); + iommu_enable_gt(iommu); + } +} + +static void enable_iommus(void) +{ + early_enable_iommus(); + + enable_iommus_v2(); +} + static void disable_iommus(void) { struct amd_iommu *iommu; -- cgit v1.2.3 From 62410eeb40ef355fa47f63886542f4dacef13ba9 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 12 Jun 2012 16:42:43 +0200 Subject: iommu/amd: Move unmap_flush message to amd_iommu_init_dma_ops() The message belongs there anyway, so move it to that function. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 5 +++++ drivers/iommu/amd_iommu_init.c | 8 -------- 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/iommu/amd_iommu_init.c') diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 0d0dc8598c72..584ea85ab2f0 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2971,6 +2971,11 @@ int __init amd_iommu_init_dma_ops(void) amd_iommu_stats_init(); + if (amd_iommu_unmap_flush) + pr_info("AMD-Vi: IO/TLB flush on unmap enabled\n"); + else + pr_info("AMD-Vi: Lazy IO/TLB flushing enabled\n"); + return 0; free_domains: diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index b82cf447724e..966d8ac9e147 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1702,14 +1702,6 @@ static int __init amd_iommu_init(void) x86_platform.iommu_shutdown = disable_iommus; - if (iommu_pass_through) - goto out; - - if (amd_iommu_unmap_flush) - printk(KERN_INFO "AMD-Vi: IO/TLB flush on unmap enabled\n"); - else - printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n"); - out: return ret; -- cgit v1.2.3 From b9b1ce707d81ec63c04e4fd8c34699ada950e6dc Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 12 Jun 2012 16:51:12 +0200 Subject: iommu/amd: Introduce amd_iommu_init_dma routine This function will initialize everthing necessary so that devices can do DMA. This includes dma_ops and iommu_ops. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 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 966d8ac9e147..53828b61e9ac 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -1627,8 +1627,6 @@ int __init amd_iommu_init_hardware(void) enable_iommus(); - amd_iommu_init_notifier(); - register_syscore_ops(&amd_iommu_syscore_ops); return ret; @@ -1669,6 +1667,25 @@ static bool detect_ivrs(void) return true; } +static int amd_iommu_init_dma(void) +{ + int ret; + + if (iommu_pass_through) + ret = amd_iommu_init_passthrough(); + else + ret = amd_iommu_init_dma_ops(); + + if (ret) + return ret; + + amd_iommu_init_api(); + + amd_iommu_init_notifier(); + + return 0; +} + /* * This is the core init function for AMD IOMMU hardware in the system. * This function is called from the generic x86 DMA layer initialization @@ -1690,11 +1707,7 @@ static int __init amd_iommu_init(void) if (ret) goto free; - if (iommu_pass_through) - ret = amd_iommu_init_passthrough(); - else - ret = amd_iommu_init_dma_ops(); - + ret = amd_iommu_init_dma(); if (ret) goto free; -- cgit v1.2.3 From 2c0ae1720c09c6f8fc8c6bcece29dc80b08ca1af Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 12 Jun 2012 15:59:30 +0200 Subject: iommu/amd: Convert iommu initialization to state machine This step makes it very easy to keep track about the current intialization state of the iommu driver. With this change we can initialize the IOMMU hardware to a point where it can remap interrupts and later resume the initializion to enable dma remapping. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 173 ++++++++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 64 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 53828b61e9ac..500e7f15f5c2 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -187,7 +187,23 @@ static u32 dev_table_size; /* size of the device table */ static u32 alias_table_size; /* size of the alias table */ static u32 rlookup_table_size; /* size if the rlookup table */ +enum iommu_init_state { + IOMMU_START_STATE, + IOMMU_IVRS_DETECTED, + IOMMU_ACPI_FINISHED, + IOMMU_ENABLED, + IOMMU_PCI_INIT, + IOMMU_INTERRUPTS_EN, + IOMMU_DMA_OPS, + IOMMU_INITIALIZED, + IOMMU_NOT_FOUND, + IOMMU_INIT_ERROR, +}; + +static enum iommu_init_state init_state = IOMMU_START_STATE; + static int amd_iommu_enable_interrupts(void); +static int __init iommu_go_to_state(enum iommu_init_state state); static inline void update_last_devid(u16 devid) { @@ -1104,7 +1120,7 @@ static void print_iommu_info(void) } } -static int amd_iommu_init_pci(void) +static int __init amd_iommu_init_pci(void) { struct amd_iommu *iommu; int ret = 0; @@ -1516,11 +1532,6 @@ static int __init early_amd_iommu_init(void) if (!amd_iommu_detected) return -ENODEV; - if (amd_iommu_dev_table != NULL) { - /* Hardware already initialized */ - return 0; - } - status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size); if (status == AE_NOT_FOUND) return -ENODEV; @@ -1535,7 +1546,8 @@ static int __init early_amd_iommu_init(void) * we need to handle. Upon this information the shared data * structures for the IOMMUs in the system will be allocated */ - if (find_last_devid_acpi(ivrs_base)) + ret = find_last_devid_acpi(ivrs_base); + if (ret) goto out; dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE); @@ -1556,20 +1568,20 @@ static int __init early_amd_iommu_init(void) amd_iommu_alias_table = (void *)__get_free_pages(GFP_KERNEL, get_order(alias_table_size)); if (amd_iommu_alias_table == NULL) - goto free; + goto out; /* IOMMU rlookup table - find the IOMMU for a specific device */ amd_iommu_rlookup_table = (void *)__get_free_pages( GFP_KERNEL | __GFP_ZERO, get_order(rlookup_table_size)); if (amd_iommu_rlookup_table == NULL) - goto free; + goto out; amd_iommu_pd_alloc_bitmap = (void *)__get_free_pages( GFP_KERNEL | __GFP_ZERO, get_order(MAX_DOMAIN_ID/8)); if (amd_iommu_pd_alloc_bitmap == NULL) - goto free; + goto out; /* init the device table */ init_device_table(); @@ -1594,41 +1606,17 @@ static int __init early_amd_iommu_init(void) */ ret = init_iommu_all(ivrs_base); if (ret) - goto free; + goto out; ret = init_memory_definitions(ivrs_base); if (ret) - goto free; + goto out; out: /* Don't leak any ACPI memory */ early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); ivrs_base = NULL; - return ret; - -free: - free_on_init_error(); - - goto out; -} - -int __init amd_iommu_init_hardware(void) -{ - int ret = 0; - - ret = early_amd_iommu_init(); - if (ret) - return ret; - - ret = amd_iommu_init_pci(); - if (ret) - return ret; - - enable_iommus(); - - register_syscore_ops(&amd_iommu_syscore_ops); - return ret; } @@ -1686,44 +1674,99 @@ static int amd_iommu_init_dma(void) return 0; } -/* - * This is the core init function for AMD IOMMU hardware in the system. - * This function is called from the generic x86 DMA layer initialization - * code. +/**************************************************************************** * - * The function calls amd_iommu_init_hardware() to setup and enable the - * IOMMU hardware if this has not happened yet. After that the driver - * registers for the DMA-API and for the IOMMU-API as necessary. - */ -static int __init amd_iommu_init(void) + * AMD IOMMU Initialization State Machine + * + ****************************************************************************/ + +static int __init state_next(void) { int ret = 0; - ret = amd_iommu_init_hardware(); - if (ret) - goto out; - - ret = amd_iommu_enable_interrupts(); - if (ret) - goto free; + switch (init_state) { + case IOMMU_START_STATE: + if (!detect_ivrs()) { + init_state = IOMMU_NOT_FOUND; + ret = -ENODEV; + } else { + init_state = IOMMU_IVRS_DETECTED; + } + break; + case IOMMU_IVRS_DETECTED: + ret = early_amd_iommu_init(); + init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED; + break; + case IOMMU_ACPI_FINISHED: + early_enable_iommus(); + register_syscore_ops(&amd_iommu_syscore_ops); + x86_platform.iommu_shutdown = disable_iommus; + init_state = IOMMU_ENABLED; + break; + case IOMMU_ENABLED: + ret = amd_iommu_init_pci(); + init_state = ret ? IOMMU_INIT_ERROR : IOMMU_PCI_INIT; + enable_iommus_v2(); + break; + case IOMMU_PCI_INIT: + ret = amd_iommu_enable_interrupts(); + init_state = ret ? IOMMU_INIT_ERROR : IOMMU_INTERRUPTS_EN; + break; + case IOMMU_INTERRUPTS_EN: + ret = amd_iommu_init_dma(); + init_state = ret ? IOMMU_INIT_ERROR : IOMMU_DMA_OPS; + break; + case IOMMU_DMA_OPS: + init_state = IOMMU_INITIALIZED; + break; + case IOMMU_INITIALIZED: + /* Nothing to do */ + break; + case IOMMU_NOT_FOUND: + case IOMMU_INIT_ERROR: + /* Error states => do nothing */ + ret = -EINVAL; + break; + default: + /* Unknown state */ + BUG(); + } - ret = amd_iommu_init_dma(); - if (ret) - goto free; + return ret; +} - amd_iommu_init_api(); +static int __init iommu_go_to_state(enum iommu_init_state state) +{ + int ret = 0; - x86_platform.iommu_shutdown = disable_iommus; + while (init_state != state) { + ret = state_next(); + if (init_state == IOMMU_NOT_FOUND || + init_state == IOMMU_INIT_ERROR) + break; + } -out: return ret; +} -free: - disable_iommus(); - free_on_init_error(); - goto out; +/* + * This is the core init function for AMD IOMMU hardware in the system. + * This function is called from the generic x86 DMA layer initialization + * code. + */ +static int __init amd_iommu_init(void) +{ + int ret; + + ret = iommu_go_to_state(IOMMU_INITIALIZED); + if (ret) { + disable_iommus(); + free_on_init_error(); + } + + return ret; } /**************************************************************************** @@ -1735,6 +1778,7 @@ free: ****************************************************************************/ int __init amd_iommu_detect(void) { + int ret; if (no_iommu || (iommu_detected && !gart_iommu_aperture)) return -ENODEV; @@ -1742,8 +1786,9 @@ int __init amd_iommu_detect(void) if (amd_iommu_disabled) return -ENODEV; - if (!detect_ivrs()) - return -ENODEV; + ret = iommu_go_to_state(IOMMU_IVRS_DETECTED); + if (ret) + return ret; amd_iommu_detected = true; iommu_detected = 1; -- cgit v1.2.3