Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ia64: rework iommu probing

ia64 currently organizes the iommu probing along machves, which isn't
very helpful. Instead just try to probe for Intel IOMMUs in mem_init
as they are properly described in ACPI and if none was found initialize
the swiotlb buffer. The HP SBA handling is then only done delayed when
the actual hardware is probed. Only in the case that we actually found
usable IOMMUs we then set up the DMA ops and free the not needed
swiotlb buffer. This scheme gets rid of the need for the dma_init
machvec operation, and the dig_vtd machvec.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Link: https://lkml.kernel.org/r/20190813072514.23299-24-hch@lst.de
Signed-off-by: Tony Luck <tony.luck@intel.com>

authored by

Christoph Hellwig and committed by
Tony Luck
974f83ec 16567ca8

+40 -151
-5
arch/ia64/Kconfig
··· 146 146 bool "DIG-compliant" 147 147 select SWIOTLB 148 148 149 - config IA64_DIG_VTD 150 - bool "DIG+Intel+IOMMU" 151 - select INTEL_IOMMU 152 - select PCI_MSI 153 - 154 149 config IA64_HP_ZX1 155 150 bool "HP-zx1/sx1000" 156 151 help
-1
arch/ia64/Makefile
··· 51 51 libs-y += arch/ia64/lib/ 52 52 core-y += arch/ia64/kernel/ arch/ia64/mm/ 53 53 core-$(CONFIG_IA64_DIG) += arch/ia64/dig/ 54 - core-$(CONFIG_IA64_DIG_VTD) += arch/ia64/dig/ 55 54 core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ 56 55 core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ 57 56 core-$(CONFIG_IA64_SGI_UV) += arch/ia64/uv/
-5
arch/ia64/dig/Makefile
··· 7 7 # 8 8 9 9 obj-y := setup.o 10 - ifeq ($(CONFIG_INTEL_IOMMU), y) 11 - obj-$(CONFIG_IA64_GENERIC) += machvec.o machvec_vtd.o 12 - else 13 10 obj-$(CONFIG_IA64_GENERIC) += machvec.o 14 - endif 15 -
-3
arch/ia64/dig/machvec_vtd.c
··· 1 - #define MACHVEC_PLATFORM_NAME dig_vtd 2 - #define MACHVEC_PLATFORM_HEADER <asm/machvec_dig_vtd.h> 3 - #include <asm/machvec_init.h>
+28 -54
arch/ia64/hp/common/sba_iommu.c
··· 35 35 #include <linux/iommu-helper.h> 36 36 #include <linux/dma-mapping.h> 37 37 #include <linux/prefetch.h> 38 + #include <linux/swiotlb.h> 38 39 39 40 #include <asm/delay.h> /* ia64_get_itc() */ 40 41 #include <asm/io.h> ··· 43 42 #include <asm/dma.h> 44 43 45 44 #include <asm/acpi-ext.h> 46 - 47 - extern int swiotlb_late_init_with_default_size (size_t size); 48 45 49 46 #define PFX "IOC: " 50 47 ··· 2055 2056 /* This has to run before acpi_scan_init(). */ 2056 2057 arch_initcall(acpi_sba_ioc_init_acpi); 2057 2058 2059 + static int sba_dma_supported (struct device *dev, u64 mask) 2060 + { 2061 + /* make sure it's at least 32bit capable */ 2062 + return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL); 2063 + } 2064 + 2065 + static const struct dma_map_ops sba_dma_ops = { 2066 + .alloc = sba_alloc_coherent, 2067 + .free = sba_free_coherent, 2068 + .map_page = sba_map_page, 2069 + .unmap_page = sba_unmap_page, 2070 + .map_sg = sba_map_sg_attrs, 2071 + .unmap_sg = sba_unmap_sg_attrs, 2072 + .dma_supported = sba_dma_supported, 2073 + }; 2074 + 2058 2075 static int __init 2059 2076 sba_init(void) 2060 2077 { 2061 - if (!ia64_platform_is("hpzx1")) 2062 - return 0; 2063 - 2064 - #if defined(CONFIG_IA64_GENERIC) 2065 - /* If we are booting a kdump kernel, the sba_iommu will 2066 - * cause devices that were not shutdown properly to MCA 2067 - * as soon as they are turned back on. Our only option for 2068 - * a successful kdump kernel boot is to use the swiotlb. 2078 + /* 2079 + * If we are booting a kdump kernel, the sba_iommu will cause devices 2080 + * that were not shutdown properly to MCA as soon as they are turned 2081 + * back on. Our only option for a successful kdump kernel boot is to 2082 + * use swiotlb. 2069 2083 */ 2070 - if (is_kdump_kernel()) { 2071 - dma_ops = NULL; 2072 - if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0) 2073 - panic("Unable to initialize software I/O TLB:" 2074 - " Try machvec=dig boot option"); 2075 - machvec_init("dig"); 2084 + if (is_kdump_kernel()) 2076 2085 return 0; 2077 - } 2078 - #endif 2079 2086 2080 2087 /* 2081 2088 * ioc_found should be populated by the acpi_sba_ioc_handler's .attach() ··· 2090 2085 while (ioc_found) 2091 2086 acpi_sba_ioc_add(ioc_found); 2092 2087 2093 - if (!ioc_list) { 2094 - #ifdef CONFIG_IA64_GENERIC 2095 - /* 2096 - * If we didn't find something sba_iommu can claim, we 2097 - * need to setup the swiotlb and switch to the dig machvec. 2098 - */ 2099 - dma_ops = NULL; 2100 - if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0) 2101 - panic("Unable to find SBA IOMMU or initialize " 2102 - "software I/O TLB: Try machvec=dig boot option"); 2103 - machvec_init("dig"); 2104 - #else 2105 - panic("Unable to find SBA IOMMU: Try a generic or DIG kernel"); 2106 - #endif 2088 + if (!ioc_list) 2107 2089 return 0; 2108 - } 2109 2090 2110 2091 { 2111 2092 struct pci_bus *b = NULL; 2112 2093 while ((b = pci_find_next_bus(b)) != NULL) 2113 2094 sba_connect_bus(b); 2114 2095 } 2096 + 2097 + /* no need for swiotlb with the iommu */ 2098 + swiotlb_exit(); 2099 + dma_ops = &sba_dma_ops; 2115 2100 2116 2101 #ifdef CONFIG_PROC_FS 2117 2102 ioc_proc_init(); ··· 2116 2121 { 2117 2122 reserve_sba_gart = 0; 2118 2123 return 1; 2119 - } 2120 - 2121 - static int sba_dma_supported (struct device *dev, u64 mask) 2122 - { 2123 - /* make sure it's at least 32bit capable */ 2124 - return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL); 2125 2124 } 2126 2125 2127 2126 __setup("nosbagart", nosbagart); ··· 2142 2153 } 2143 2154 2144 2155 __setup("sbapagesize=",sba_page_override); 2145 - 2146 - const struct dma_map_ops sba_dma_ops = { 2147 - .alloc = sba_alloc_coherent, 2148 - .free = sba_free_coherent, 2149 - .map_page = sba_map_page, 2150 - .unmap_page = sba_unmap_page, 2151 - .map_sg = sba_map_sg_attrs, 2152 - .unmap_sg = sba_unmap_sg_attrs, 2153 - .dma_supported = sba_dma_supported, 2154 - }; 2155 - 2156 - void sba_dma_init(void) 2157 - { 2158 - dma_ops = &sba_dma_ops; 2159 - }
-2
arch/ia64/include/asm/acpi.h
··· 43 43 return "uv"; 44 44 # elif defined (CONFIG_IA64_DIG) 45 45 return "dig"; 46 - # elif defined(CONFIG_IA64_DIG_VTD) 47 - return "dig_vtd"; 48 46 # else 49 47 # error Unknown platform. Fix acpi.c. 50 48 # endif
-11
arch/ia64/include/asm/machvec.h
··· 16 16 struct device; 17 17 18 18 typedef void ia64_mv_setup_t (char **); 19 - typedef void ia64_mv_dma_init (void); 20 19 21 20 extern void machvec_setup (char **); 22 21 23 22 # if defined (CONFIG_IA64_DIG) 24 23 # include <asm/machvec_dig.h> 25 - # elif defined(CONFIG_IA64_DIG_VTD) 26 - # include <asm/machvec_dig_vtd.h> 27 24 # elif defined (CONFIG_IA64_HP_ZX1) 28 25 # include <asm/machvec_hpzx1.h> 29 26 # elif defined (CONFIG_IA64_SGI_UV) ··· 32 35 # else 33 36 # define ia64_platform_name ia64_mv.name 34 37 # define platform_setup ia64_mv.setup 35 - # define platform_dma_init ia64_mv.dma_init 36 38 # endif 37 39 38 40 /* __attribute__((__aligned__(16))) is required to make size of the ··· 42 46 struct ia64_machine_vector { 43 47 const char *name; 44 48 ia64_mv_setup_t *setup; 45 - ia64_mv_dma_init *dma_init; 46 49 } __attribute__((__aligned__(16))); /* align attrib? see above comment */ 47 50 48 51 #define MACHVEC_INIT(name) \ 49 52 { \ 50 53 #name, \ 51 54 platform_setup, \ 52 - platform_dma_init, \ 53 55 } 54 56 55 57 extern struct ia64_machine_vector ia64_mv; ··· 58 64 # error Unknown configuration. Update arch/ia64/include/asm/machvec.h. 59 65 # endif /* CONFIG_IA64_GENERIC */ 60 66 61 - extern void swiotlb_dma_init(void); 62 - 63 67 /* 64 68 * Define default versions so we can extend machvec for new platforms without having 65 69 * to update the machvec files for all existing platforms. 66 70 */ 67 71 #ifndef platform_setup 68 72 # define platform_setup machvec_setup 69 - #endif 70 - #ifndef platform_dma_init 71 - # define platform_dma_init swiotlb_dma_init 72 73 #endif 73 74 74 75 #endif /* _ASM_IA64_MACHVEC_H */
-19
arch/ia64/include/asm/machvec_dig_vtd.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #ifndef _ASM_IA64_MACHVEC_DIG_VTD_h 3 - #define _ASM_IA64_MACHVEC_DIG_VTD_h 4 - 5 - extern ia64_mv_setup_t dig_setup; 6 - extern ia64_mv_dma_init pci_iommu_alloc; 7 - 8 - /* 9 - * This stuff has dual use! 10 - * 11 - * For a generic kernel, the macros are used to initialize the 12 - * platform's machvec structure. When compiling a non-generic kernel, 13 - * the macros are used directly. 14 - */ 15 - #define ia64_platform_name "dig_vtd" 16 - #define platform_setup dig_setup 17 - #define platform_dma_init pci_iommu_alloc 18 - 19 - #endif /* _ASM_IA64_MACHVEC_DIG_VTD_h */
-2
arch/ia64/include/asm/machvec_hpzx1.h
··· 3 3 #define _ASM_IA64_MACHVEC_HPZX1_h 4 4 5 5 extern ia64_mv_setup_t dig_setup; 6 - extern ia64_mv_dma_init sba_dma_init; 7 6 8 7 /* 9 8 * This stuff has dual use! ··· 13 14 */ 14 15 #define ia64_platform_name "hpzx1" 15 16 #define platform_setup dig_setup 16 - #define platform_dma_init sba_dma_init 17 17 18 18 #endif /* _ASM_IA64_MACHVEC_HPZX1_h */
-3
arch/ia64/include/asm/pci.h
··· 69 69 return channel ? isa_irq_to_vector(15) : isa_irq_to_vector(14); 70 70 } 71 71 72 - #ifdef CONFIG_INTEL_IOMMU 73 - extern void pci_iommu_alloc(void); 74 - #endif 75 72 #endif /* _ASM_IA64_PCI_H */
-15
arch/ia64/kernel/acpi.c
··· 65 65 struct acpi_table_rsdp *rsdp; 66 66 struct acpi_table_xsdt *xsdt; 67 67 struct acpi_table_header *hdr; 68 - #ifdef CONFIG_INTEL_IOMMU 69 - u64 i, nentries; 70 - #endif 71 68 72 69 rsdp_phys = acpi_find_rsdp(); 73 70 if (!rsdp_phys) { ··· 94 97 if (!strcmp(hdr->oem_table_id + 4, "UV")) 95 98 return "uv"; 96 99 } 97 - 98 - #ifdef CONFIG_INTEL_IOMMU 99 - /* Look for Intel IOMMU */ 100 - nentries = (hdr->length - sizeof(*hdr)) / 101 - sizeof(xsdt->table_offset_entry[0]); 102 - for (i = 0; i < nentries; i++) { 103 - hdr = __va(xsdt->table_offset_entry[i]); 104 - if (strncmp(hdr->signature, ACPI_SIG_DMAR, 105 - sizeof(ACPI_SIG_DMAR) - 1) == 0) 106 - return "dig_vtd"; 107 - } 108 - #endif 109 100 110 101 return "dig"; 111 102 }
-6
arch/ia64/kernel/dma-mapping.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 #include <linux/dma-direct.h> 3 - #include <linux/swiotlb.h> 4 3 #include <linux/export.h> 5 4 6 5 /* Set this to 1 if there is a HW IOMMU in the system */ ··· 25 26 dma_addr_t dma_addr) 26 27 { 27 28 return page_to_pfn(virt_to_page(cpu_addr)); 28 - } 29 - 30 - void __init swiotlb_dma_init(void) 31 - { 32 - swiotlb_init(1); 33 29 } 34 30 #endif
-21
arch/ia64/kernel/pci-dma.c
··· 34 34 35 35 /* Must execute after PCI subsystem */ 36 36 fs_initcall(pci_iommu_init); 37 - 38 - void __init pci_iommu_alloc(void) 39 - { 40 - /* 41 - * The order of these functions is important for 42 - * fall-back/fail-over reasons 43 - */ 44 - detect_intel_iommu(); 45 - 46 - #ifdef CONFIG_SWIOTLB 47 - if (!iommu_detected) { 48 - #ifdef CONFIG_IA64_GENERIC 49 - printk(KERN_INFO "PCI-DMA: Re-initialize machine vector.\n"); 50 - machvec_init("dig"); 51 - swiotlb_dma_init(); 52 - #else 53 - panic("Unable to find Intel IOMMU"); 54 - #endif /* CONFIG_IA64_GENERIC */ 55 - } 56 - #endif /* CONFIG_SWIOTLB */ 57 - }
+12 -4
arch/ia64/mm/init.c
··· 9 9 #include <linux/init.h> 10 10 11 11 #include <linux/dma-noncoherent.h> 12 + #include <linux/dmar.h> 12 13 #include <linux/efi.h> 13 14 #include <linux/elf.h> 14 15 #include <linux/memblock.h> ··· 24 23 #include <linux/proc_fs.h> 25 24 #include <linux/bitops.h> 26 25 #include <linux/kexec.h> 26 + #include <linux/swiotlb.h> 27 27 28 28 #include <asm/dma.h> 29 29 #include <asm/io.h> ··· 635 633 BUG_ON(PTRS_PER_PTE * sizeof(pte_t) != PAGE_SIZE); 636 634 637 635 /* 638 - * This needs to be called _after_ the command line has been parsed but _before_ 639 - * any drivers that may need the PCI DMA interface are initialized or bootmem has 640 - * been freed. 636 + * This needs to be called _after_ the command line has been parsed but 637 + * _before_ any drivers that may need the PCI DMA interface are 638 + * initialized or bootmem has been freed. 641 639 */ 642 - platform_dma_init(); 640 + #ifdef CONFIG_INTEL_IOMMU 641 + detect_intel_iommu(); 642 + if (!iommu_detected) 643 + #endif 644 + #ifdef CONFIG_SWIOTLB 645 + swiotlb_init(1); 646 + #endif 643 647 644 648 #ifdef CONFIG_FLATMEM 645 649 BUG_ON(!mem_map);