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

x86: Don't panic if can not alloc buffer for swiotlb

Normal boot path on system with iommu support:
swiotlb buffer will be allocated early at first and then try to initialize
iommu, if iommu for intel or AMD could setup properly, swiotlb buffer
will be freed.

The early allocating is with bootmem, and could panic when we try to use
kdump with buffer above 4G only, or with memmap to limit mem under 4G.
for example: memmap=4095M$1M to remove memory under 4G.

According to Eric, add _nopanic version and no_iotlb_memory to fail
map single later if swiotlb is still needed.

-v2: don't pass nopanic, and use -ENOMEM return value according to Eric.
panic early instead of using swiotlb_full to panic...according to Eric/Konrad.
-v3: make swiotlb_init to be notpanic, but will affect:
arm64, ia64, powerpc, tile, unicore32, x86.
-v4: cleanup swiotlb_init by removing swiotlb_init_with_default_size.

Suggested-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Link: http://lkml.kernel.org/r/1359058816-7615-36-git-send-email-yinghai@kernel.org
Reviewed-and-tested-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Cc: linux-mips@linux-mips.org
Cc: xen-devel@lists.xensource.com
Cc: virtualization@lists.linux-foundation.org
Cc: Shuah Khan <shuahkhan@gmail.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>

authored by

Yinghai Lu and committed by
H. Peter Anvin
ac2cbab2 38fa4175

+35 -21
+2 -1
arch/mips/cavium-octeon/dma-octeon.c
··· 317 317 318 318 octeon_swiotlb = alloc_bootmem_low_pages(swiotlbsize); 319 319 320 - swiotlb_init_with_tbl(octeon_swiotlb, swiotlb_nslabs, 1); 320 + if (swiotlb_init_with_tbl(octeon_swiotlb, swiotlb_nslabs, 1) == -ENOMEM) 321 + panic("Cannot allocate SWIOTLB buffer"); 321 322 322 323 mips_dma_map_ops = &octeon_linear_dma_map_ops.dma_map_ops; 323 324 }
+3 -1
drivers/xen/swiotlb-xen.c
··· 231 231 } 232 232 start_dma_addr = xen_virt_to_bus(xen_io_tlb_start); 233 233 if (early) { 234 - swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose); 234 + if (swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, 235 + verbose)) 236 + panic("Cannot allocate SWIOTLB buffer"); 235 237 rc = 0; 236 238 } else 237 239 rc = swiotlb_late_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs);
+1 -1
include/linux/swiotlb.h
··· 23 23 #define IO_TLB_SHIFT 11 24 24 25 25 extern void swiotlb_init(int verbose); 26 - extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose); 26 + int swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose); 27 27 extern unsigned long swiotlb_nr_tbl(void); 28 28 extern int swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs); 29 29
+29 -18
lib/swiotlb.c
··· 122 122 return phys_to_dma(hwdev, virt_to_phys(address)); 123 123 } 124 124 125 + static bool no_iotlb_memory; 126 + 125 127 void swiotlb_print_info(void) 126 128 { 127 129 unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT; 128 130 unsigned char *vstart, *vend; 131 + 132 + if (no_iotlb_memory) { 133 + pr_warn("software IO TLB: No low mem\n"); 134 + return; 135 + } 129 136 130 137 vstart = phys_to_virt(io_tlb_start); 131 138 vend = phys_to_virt(io_tlb_end); ··· 143 136 bytes >> 20, vstart, vend - 1); 144 137 } 145 138 146 - void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) 139 + int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) 147 140 { 148 141 void *v_overflow_buffer; 149 142 unsigned long i, bytes; ··· 157 150 /* 158 151 * Get the overflow emergency buffer 159 152 */ 160 - v_overflow_buffer = alloc_bootmem_low_pages(PAGE_ALIGN(io_tlb_overflow)); 153 + v_overflow_buffer = alloc_bootmem_low_pages_nopanic( 154 + PAGE_ALIGN(io_tlb_overflow)); 161 155 if (!v_overflow_buffer) 162 - panic("Cannot allocate SWIOTLB overflow buffer!\n"); 156 + return -ENOMEM; 163 157 164 158 io_tlb_overflow_buffer = __pa(v_overflow_buffer); 165 159 ··· 177 169 178 170 if (verbose) 179 171 swiotlb_print_info(); 172 + 173 + return 0; 180 174 } 181 175 182 176 /* 183 177 * Statically reserve bounce buffer space and initialize bounce buffer data 184 178 * structures for the software IO TLB used to implement the DMA API. 185 179 */ 186 - static void __init 187 - swiotlb_init_with_default_size(size_t default_size, int verbose) 180 + void __init 181 + swiotlb_init(int verbose) 188 182 { 183 + /* default to 64MB */ 184 + size_t default_size = 64UL<<20; 189 185 unsigned char *vstart; 190 186 unsigned long bytes; 191 187 ··· 200 188 201 189 bytes = io_tlb_nslabs << IO_TLB_SHIFT; 202 190 203 - /* 204 - * Get IO TLB memory from the low pages 205 - */ 206 - vstart = alloc_bootmem_low_pages(PAGE_ALIGN(bytes)); 207 - if (!vstart) 208 - panic("Cannot allocate SWIOTLB buffer"); 191 + /* Get IO TLB memory from the low pages */ 192 + vstart = alloc_bootmem_low_pages_nopanic(PAGE_ALIGN(bytes)); 193 + if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose)) 194 + return; 209 195 210 - swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose); 211 - } 212 - 213 - void __init 214 - swiotlb_init(int verbose) 215 - { 216 - swiotlb_init_with_default_size(64 * (1<<20), verbose); /* default to 64MB */ 196 + if (io_tlb_start) 197 + free_bootmem(io_tlb_start, 198 + PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT)); 199 + pr_warn("Cannot allocate SWIOTLB buffer"); 200 + no_iotlb_memory = true; 217 201 } 218 202 219 203 /* ··· 412 404 unsigned long mask; 413 405 unsigned long offset_slots; 414 406 unsigned long max_slots; 407 + 408 + if (no_iotlb_memory) 409 + panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer"); 415 410 416 411 mask = dma_get_seg_boundary(hwdev); 417 412