diff options
| -rw-r--r-- | arch/ia64/hp/common/hwsw_iommu.c | 13 | ||||
| -rw-r--r-- | arch/ia64/hp/common/sba_iommu.c | 45 | ||||
| -rw-r--r-- | arch/ia64/lib/swiotlb.c | 102 | ||||
| -rw-r--r-- | include/asm-ia64/machvec_hpzx1.h | 21 | ||||
| -rw-r--r-- | include/asm-ia64/machvec_hpzx1_swiotlb.h | 3 |
5 files changed, 156 insertions, 28 deletions
diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c index 80f8ef013939..317c334c5a18 100644 --- a/arch/ia64/hp/common/hwsw_iommu.c +++ b/arch/ia64/hp/common/hwsw_iommu.c | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | #include <asm/machvec.h> | 17 | #include <asm/machvec.h> |
| 18 | 18 | ||
| 19 | /* swiotlb declarations & definitions: */ | 19 | /* swiotlb declarations & definitions: */ |
| 20 | extern void swiotlb_init_with_default_size (size_t size); | 20 | extern int swiotlb_late_init_with_default_size (size_t size); |
| 21 | extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent; | 21 | extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent; |
| 22 | extern ia64_mv_dma_free_coherent swiotlb_free_coherent; | 22 | extern ia64_mv_dma_free_coherent swiotlb_free_coherent; |
| 23 | extern ia64_mv_dma_map_single swiotlb_map_single; | 23 | extern ia64_mv_dma_map_single swiotlb_map_single; |
| @@ -67,7 +67,16 @@ void | |||
| 67 | hwsw_init (void) | 67 | hwsw_init (void) |
| 68 | { | 68 | { |
| 69 | /* default to a smallish 2MB sw I/O TLB */ | 69 | /* default to a smallish 2MB sw I/O TLB */ |
| 70 | swiotlb_init_with_default_size (2 * (1<<20)); | 70 | if (swiotlb_late_init_with_default_size (2 * (1<<20)) != 0) { |
| 71 | #ifdef CONFIG_IA64_GENERIC | ||
| 72 | /* Better to have normal DMA than panic */ | ||
| 73 | printk(KERN_WARNING "%s: Failed to initialize software I/O TLB," | ||
| 74 | " reverting to hpzx1 platform vector\n", __FUNCTION__); | ||
| 75 | machvec_init("hpzx1"); | ||
| 76 | #else | ||
| 77 | panic("Unable to initialize software I/O TLB services"); | ||
| 78 | #endif | ||
| 79 | } | ||
| 71 | } | 80 | } |
| 72 | 81 | ||
| 73 | void * | 82 | void * |
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 11957598a8b9..e64ca04ace89 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c | |||
| @@ -2028,9 +2028,40 @@ static struct acpi_driver acpi_sba_ioc_driver = { | |||
| 2028 | static int __init | 2028 | static int __init |
| 2029 | sba_init(void) | 2029 | sba_init(void) |
| 2030 | { | 2030 | { |
| 2031 | if (!ia64_platform_is("hpzx1") && !ia64_platform_is("hpzx1_swiotlb")) | ||
| 2032 | return 0; | ||
| 2033 | |||
| 2031 | acpi_bus_register_driver(&acpi_sba_ioc_driver); | 2034 | acpi_bus_register_driver(&acpi_sba_ioc_driver); |
| 2032 | if (!ioc_list) | 2035 | if (!ioc_list) { |
| 2036 | #ifdef CONFIG_IA64_GENERIC | ||
| 2037 | extern int swiotlb_late_init_with_default_size (size_t size); | ||
| 2038 | |||
| 2039 | /* | ||
| 2040 | * If we didn't find something sba_iommu can claim, we | ||
| 2041 | * need to setup the swiotlb and switch to the dig machvec. | ||
| 2042 | */ | ||
| 2043 | if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0) | ||
| 2044 | panic("Unable to find SBA IOMMU or initialize " | ||
| 2045 | "software I/O TLB: Try machvec=dig boot option"); | ||
| 2046 | machvec_init("dig"); | ||
| 2047 | #else | ||
| 2048 | panic("Unable to find SBA IOMMU: Try a generic or DIG kernel"); | ||
| 2049 | #endif | ||
| 2033 | return 0; | 2050 | return 0; |
| 2051 | } | ||
| 2052 | |||
| 2053 | #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_HP_ZX1_SWIOTLB) | ||
| 2054 | /* | ||
| 2055 | * hpzx1_swiotlb needs to have a fairly small swiotlb bounce | ||
| 2056 | * buffer setup to support devices with smaller DMA masks than | ||
| 2057 | * sba_iommu can handle. | ||
| 2058 | */ | ||
| 2059 | if (ia64_platform_is("hpzx1_swiotlb")) { | ||
| 2060 | extern void hwsw_init(void); | ||
| 2061 | |||
| 2062 | hwsw_init(); | ||
| 2063 | } | ||
| 2064 | #endif | ||
| 2034 | 2065 | ||
| 2035 | #ifdef CONFIG_PCI | 2066 | #ifdef CONFIG_PCI |
| 2036 | { | 2067 | { |
| @@ -2048,18 +2079,6 @@ sba_init(void) | |||
| 2048 | 2079 | ||
| 2049 | subsys_initcall(sba_init); /* must be initialized after ACPI etc., but before any drivers... */ | 2080 | subsys_initcall(sba_init); /* must be initialized after ACPI etc., but before any drivers... */ |
| 2050 | 2081 | ||
| 2051 | extern void dig_setup(char**); | ||
| 2052 | /* | ||
| 2053 | * MAX_DMA_ADDRESS needs to be setup prior to paging_init to do any good, | ||
| 2054 | * so we use the platform_setup hook to fix it up. | ||
| 2055 | */ | ||
| 2056 | void __init | ||
| 2057 | sba_setup(char **cmdline_p) | ||
| 2058 | { | ||
| 2059 | MAX_DMA_ADDRESS = ~0UL; | ||
| 2060 | dig_setup(cmdline_p); | ||
| 2061 | } | ||
| 2062 | |||
| 2063 | static int __init | 2082 | static int __init |
| 2064 | nosbagart(char *str) | 2083 | nosbagart(char *str) |
| 2065 | { | 2084 | { |
diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c index dbc0b3e449c5..875b0c16250c 100644 --- a/arch/ia64/lib/swiotlb.c +++ b/arch/ia64/lib/swiotlb.c | |||
| @@ -49,6 +49,15 @@ | |||
| 49 | */ | 49 | */ |
| 50 | #define IO_TLB_SHIFT 11 | 50 | #define IO_TLB_SHIFT 11 |
| 51 | 51 | ||
| 52 | #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT)) | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Minimum IO TLB size to bother booting with. Systems with mainly | ||
| 56 | * 64bit capable cards will only lightly use the swiotlb. If we can't | ||
| 57 | * allocate a contiguous 1MB, we're probably in trouble anyway. | ||
| 58 | */ | ||
| 59 | #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT) | ||
| 60 | |||
| 52 | int swiotlb_force; | 61 | int swiotlb_force; |
| 53 | 62 | ||
| 54 | /* | 63 | /* |
| @@ -154,6 +163,99 @@ swiotlb_init (void) | |||
| 154 | swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */ | 163 | swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */ |
| 155 | } | 164 | } |
| 156 | 165 | ||
| 166 | /* | ||
| 167 | * Systems with larger DMA zones (those that don't support ISA) can | ||
| 168 | * initialize the swiotlb later using the slab allocator if needed. | ||
| 169 | * This should be just like above, but with some error catching. | ||
| 170 | */ | ||
| 171 | int | ||
| 172 | swiotlb_late_init_with_default_size (size_t default_size) | ||
| 173 | { | ||
| 174 | unsigned long i, req_nslabs = io_tlb_nslabs; | ||
| 175 | unsigned int order; | ||
| 176 | |||
| 177 | if (!io_tlb_nslabs) { | ||
| 178 | io_tlb_nslabs = (default_size >> IO_TLB_SHIFT); | ||
| 179 | io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); | ||
| 180 | } | ||
| 181 | |||
| 182 | /* | ||
| 183 | * Get IO TLB memory from the low pages | ||
| 184 | */ | ||
| 185 | order = get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT)); | ||
| 186 | io_tlb_nslabs = SLABS_PER_PAGE << order; | ||
| 187 | |||
| 188 | while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) { | ||
| 189 | io_tlb_start = (char *)__get_free_pages(GFP_DMA | __GFP_NOWARN, | ||
| 190 | order); | ||
| 191 | if (io_tlb_start) | ||
| 192 | break; | ||
| 193 | order--; | ||
| 194 | } | ||
| 195 | |||
| 196 | if (!io_tlb_start) | ||
| 197 | goto cleanup1; | ||
| 198 | |||
| 199 | if (order != get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT))) { | ||
| 200 | printk(KERN_WARNING "Warning: only able to allocate %ld MB " | ||
| 201 | "for software IO TLB\n", (PAGE_SIZE << order) >> 20); | ||
| 202 | io_tlb_nslabs = SLABS_PER_PAGE << order; | ||
| 203 | } | ||
| 204 | io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT); | ||
| 205 | memset(io_tlb_start, 0, io_tlb_nslabs * (1 << IO_TLB_SHIFT)); | ||
| 206 | |||
| 207 | /* | ||
| 208 | * Allocate and initialize the free list array. This array is used | ||
| 209 | * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE | ||
| 210 | * between io_tlb_start and io_tlb_end. | ||
| 211 | */ | ||
| 212 | io_tlb_list = (unsigned int *)__get_free_pages(GFP_KERNEL, | ||
| 213 | get_order(io_tlb_nslabs * sizeof(int))); | ||
| 214 | if (!io_tlb_list) | ||
| 215 | goto cleanup2; | ||
| 216 | |||
| 217 | for (i = 0; i < io_tlb_nslabs; i++) | ||
| 218 | io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); | ||
| 219 | io_tlb_index = 0; | ||
| 220 | |||
| 221 | io_tlb_orig_addr = (unsigned char **)__get_free_pages(GFP_KERNEL, | ||
| 222 | get_order(io_tlb_nslabs * sizeof(char *))); | ||
| 223 | if (!io_tlb_orig_addr) | ||
| 224 | goto cleanup3; | ||
| 225 | |||
| 226 | memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(char *)); | ||
| 227 | |||
| 228 | /* | ||
| 229 | * Get the overflow emergency buffer | ||
| 230 | */ | ||
| 231 | io_tlb_overflow_buffer = (void *)__get_free_pages(GFP_DMA, | ||
| 232 | get_order(io_tlb_overflow)); | ||
| 233 | if (!io_tlb_overflow_buffer) | ||
| 234 | goto cleanup4; | ||
| 235 | |||
| 236 | printk(KERN_INFO "Placing %ldMB software IO TLB between 0x%lx - " | ||
| 237 | "0x%lx\n", (io_tlb_nslabs * (1 << IO_TLB_SHIFT)) >> 20, | ||
| 238 | virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end)); | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | |||
| 242 | cleanup4: | ||
| 243 | free_pages((unsigned long)io_tlb_orig_addr, get_order(io_tlb_nslabs * | ||
| 244 | sizeof(char *))); | ||
| 245 | io_tlb_orig_addr = NULL; | ||
| 246 | cleanup3: | ||
| 247 | free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs * | ||
| 248 | sizeof(int))); | ||
| 249 | io_tlb_list = NULL; | ||
| 250 | io_tlb_end = NULL; | ||
| 251 | cleanup2: | ||
| 252 | free_pages((unsigned long)io_tlb_start, order); | ||
| 253 | io_tlb_start = NULL; | ||
| 254 | cleanup1: | ||
| 255 | io_tlb_nslabs = req_nslabs; | ||
| 256 | return -ENOMEM; | ||
| 257 | } | ||
| 258 | |||
| 157 | static inline int | 259 | static inline int |
| 158 | address_needs_mapping(struct device *hwdev, dma_addr_t addr) | 260 | address_needs_mapping(struct device *hwdev, dma_addr_t addr) |
| 159 | { | 261 | { |
diff --git a/include/asm-ia64/machvec_hpzx1.h b/include/asm-ia64/machvec_hpzx1.h index daafe504c5f4..e90daf9ce340 100644 --- a/include/asm-ia64/machvec_hpzx1.h +++ b/include/asm-ia64/machvec_hpzx1.h | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #ifndef _ASM_IA64_MACHVEC_HPZX1_h | 1 | #ifndef _ASM_IA64_MACHVEC_HPZX1_h |
| 2 | #define _ASM_IA64_MACHVEC_HPZX1_h | 2 | #define _ASM_IA64_MACHVEC_HPZX1_h |
| 3 | 3 | ||
| 4 | extern ia64_mv_setup_t dig_setup; | 4 | extern ia64_mv_setup_t dig_setup; |
| 5 | extern ia64_mv_setup_t sba_setup; | ||
| 6 | extern ia64_mv_dma_alloc_coherent sba_alloc_coherent; | 5 | extern ia64_mv_dma_alloc_coherent sba_alloc_coherent; |
| 7 | extern ia64_mv_dma_free_coherent sba_free_coherent; | 6 | extern ia64_mv_dma_free_coherent sba_free_coherent; |
| 8 | extern ia64_mv_dma_map_single sba_map_single; | 7 | extern ia64_mv_dma_map_single sba_map_single; |
| @@ -19,15 +18,15 @@ extern ia64_mv_dma_mapping_error sba_dma_mapping_error; | |||
| 19 | * platform's machvec structure. When compiling a non-generic kernel, | 18 | * platform's machvec structure. When compiling a non-generic kernel, |
| 20 | * the macros are used directly. | 19 | * the macros are used directly. |
| 21 | */ | 20 | */ |
| 22 | #define platform_name "hpzx1" | 21 | #define platform_name "hpzx1" |
| 23 | #define platform_setup sba_setup | 22 | #define platform_setup dig_setup |
| 24 | #define platform_dma_init machvec_noop | 23 | #define platform_dma_init machvec_noop |
| 25 | #define platform_dma_alloc_coherent sba_alloc_coherent | 24 | #define platform_dma_alloc_coherent sba_alloc_coherent |
| 26 | #define platform_dma_free_coherent sba_free_coherent | 25 | #define platform_dma_free_coherent sba_free_coherent |
| 27 | #define platform_dma_map_single sba_map_single | 26 | #define platform_dma_map_single sba_map_single |
| 28 | #define platform_dma_unmap_single sba_unmap_single | 27 | #define platform_dma_unmap_single sba_unmap_single |
| 29 | #define platform_dma_map_sg sba_map_sg | 28 | #define platform_dma_map_sg sba_map_sg |
| 30 | #define platform_dma_unmap_sg sba_unmap_sg | 29 | #define platform_dma_unmap_sg sba_unmap_sg |
| 31 | #define platform_dma_sync_single_for_cpu machvec_dma_sync_single | 30 | #define platform_dma_sync_single_for_cpu machvec_dma_sync_single |
| 32 | #define platform_dma_sync_sg_for_cpu machvec_dma_sync_sg | 31 | #define platform_dma_sync_sg_for_cpu machvec_dma_sync_sg |
| 33 | #define platform_dma_sync_single_for_device machvec_dma_sync_single | 32 | #define platform_dma_sync_single_for_device machvec_dma_sync_single |
diff --git a/include/asm-ia64/machvec_hpzx1_swiotlb.h b/include/asm-ia64/machvec_hpzx1_swiotlb.h index 9924b1b00a6c..f00a34a148ff 100644 --- a/include/asm-ia64/machvec_hpzx1_swiotlb.h +++ b/include/asm-ia64/machvec_hpzx1_swiotlb.h | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | #define _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h | 2 | #define _ASM_IA64_MACHVEC_HPZX1_SWIOTLB_h |
| 3 | 3 | ||
| 4 | extern ia64_mv_setup_t dig_setup; | 4 | extern ia64_mv_setup_t dig_setup; |
| 5 | extern ia64_mv_dma_init hwsw_init; | ||
| 6 | extern ia64_mv_dma_alloc_coherent hwsw_alloc_coherent; | 5 | extern ia64_mv_dma_alloc_coherent hwsw_alloc_coherent; |
| 7 | extern ia64_mv_dma_free_coherent hwsw_free_coherent; | 6 | extern ia64_mv_dma_free_coherent hwsw_free_coherent; |
| 8 | extern ia64_mv_dma_map_single hwsw_map_single; | 7 | extern ia64_mv_dma_map_single hwsw_map_single; |
| @@ -26,7 +25,7 @@ extern ia64_mv_dma_sync_sg_for_device hwsw_sync_sg_for_device; | |||
| 26 | #define platform_name "hpzx1_swiotlb" | 25 | #define platform_name "hpzx1_swiotlb" |
| 27 | 26 | ||
| 28 | #define platform_setup dig_setup | 27 | #define platform_setup dig_setup |
| 29 | #define platform_dma_init hwsw_init | 28 | #define platform_dma_init machvec_noop |
| 30 | #define platform_dma_alloc_coherent hwsw_alloc_coherent | 29 | #define platform_dma_alloc_coherent hwsw_alloc_coherent |
| 31 | #define platform_dma_free_coherent hwsw_free_coherent | 30 | #define platform_dma_free_coherent hwsw_free_coherent |
| 32 | #define platform_dma_map_single hwsw_map_single | 31 | #define platform_dma_map_single hwsw_map_single |
