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

Configure Feed

Select the types of activity you want to include in your feed.

[PATCH] swiotlb: make sure initial DMA allocations really are in DMA memory

This introduces a limit parameter to the core bootmem allocator; The new
parameter indicates that physical memory allocated by the bootmem
allocator should be within the requested limit.

We also introduce alloc_bootmem_low_pages_limit, alloc_bootmem_node_limit,
alloc_bootmem_low_pages_node_limit apis, but alloc_bootmem_low_pages_limit
is the only api used for swiotlb.

The existing alloc_bootmem_low_pages() api could instead have been
changed and made to pass right limit to the core allocator. But that
would make the patch more intrusive for 2.6.14, as other arches use
alloc_bootmem_low_pages(). We may be done that post 2.6.14 as a
cleanup.

With this, swiotlb gets memory within 4G for both x86_64 and ia64
arches.

Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
Cc: Ravikiran G Thirumalai <kiran@scalex86.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Yasunori Goto and committed by
Linus Torvalds
281dd25c 51b190b3

+53 -14
+2 -2
arch/ia64/lib/swiotlb.c
··· 123 123 /* 124 124 * Get IO TLB memory from the low pages 125 125 */ 126 - io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * 127 - (1 << IO_TLB_SHIFT)); 126 + io_tlb_start = alloc_bootmem_low_pages_limit(io_tlb_nslabs * 127 + (1 << IO_TLB_SHIFT), 0x100000000); 128 128 if (!io_tlb_start) 129 129 panic("Cannot allocate SWIOTLB buffer"); 130 130 io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
+30 -2
include/linux/bootmem.h
··· 43 43 extern unsigned long __init bootmem_bootmap_pages (unsigned long); 44 44 extern unsigned long __init init_bootmem (unsigned long addr, unsigned long memend); 45 45 extern void __init free_bootmem (unsigned long addr, unsigned long size); 46 - extern void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal); 46 + extern void * __init __alloc_bootmem_limit (unsigned long size, unsigned long align, unsigned long goal, unsigned long limit); 47 47 #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE 48 48 extern void __init reserve_bootmem (unsigned long addr, unsigned long size); 49 49 #define alloc_bootmem(x) \ ··· 54 54 __alloc_bootmem((x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS)) 55 55 #define alloc_bootmem_low_pages(x) \ 56 56 __alloc_bootmem((x), PAGE_SIZE, 0) 57 + 58 + #define alloc_bootmem_limit(x, limit) \ 59 + __alloc_bootmem_limit((x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS), (limit)) 60 + #define alloc_bootmem_low_limit(x, limit) \ 61 + __alloc_bootmem_limit((x), SMP_CACHE_BYTES, 0, (limit)) 62 + #define alloc_bootmem_pages_limit(x, limit) \ 63 + __alloc_bootmem_limit((x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS), (limit)) 64 + #define alloc_bootmem_low_pages_limit(x, limit) \ 65 + __alloc_bootmem_limit((x), PAGE_SIZE, 0, (limit)) 66 + 57 67 #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ 58 68 extern unsigned long __init free_all_bootmem (void); 59 69 ··· 71 61 extern void __init reserve_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size); 72 62 extern void __init free_bootmem_node (pg_data_t *pgdat, unsigned long addr, unsigned long size); 73 63 extern unsigned long __init free_all_bootmem_node (pg_data_t *pgdat); 74 - extern void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal); 64 + extern void * __init __alloc_bootmem_node_limit (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal, unsigned long limit); 75 65 #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE 76 66 #define alloc_bootmem_node(pgdat, x) \ 77 67 __alloc_bootmem_node((pgdat), (x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)) ··· 79 69 __alloc_bootmem_node((pgdat), (x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS)) 80 70 #define alloc_bootmem_low_pages_node(pgdat, x) \ 81 71 __alloc_bootmem_node((pgdat), (x), PAGE_SIZE, 0) 72 + 73 + #define alloc_bootmem_node_limit(pgdat, x, limit) \ 74 + __alloc_bootmem_node_limit((pgdat), (x), SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS), (limit)) 75 + #define alloc_bootmem_pages_node_limit(pgdat, x, limit) \ 76 + __alloc_bootmem_node_limit((pgdat), (x), PAGE_SIZE, __pa(MAX_DMA_ADDRESS), (limit)) 77 + #define alloc_bootmem_low_pages_node_limit(pgdat, x, limit) \ 78 + __alloc_bootmem_node_limit((pgdat), (x), PAGE_SIZE, 0, (limit)) 79 + 82 80 #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ 83 81 84 82 #ifdef CONFIG_HAVE_ARCH_ALLOC_REMAP ··· 123 105 #endif 124 106 extern int __initdata hashdist; /* Distribute hashes across NUMA nodes? */ 125 107 108 + static inline void *__alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal) 109 + { 110 + return __alloc_bootmem_limit(size, align, goal, 0); 111 + } 112 + 113 + static inline void *__alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, 114 + unsigned long goal) 115 + { 116 + return __alloc_bootmem_node_limit(pgdat, size, align, goal, 0); 117 + } 126 118 127 119 #endif /* _LINUX_BOOTMEM_H */
+21 -10
mm/bootmem.c
··· 154 154 */ 155 155 static void * __init 156 156 __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, 157 - unsigned long align, unsigned long goal) 157 + unsigned long align, unsigned long goal, unsigned long limit) 158 158 { 159 159 unsigned long offset, remaining_size, areasize, preferred; 160 - unsigned long i, start = 0, incr, eidx; 160 + unsigned long i, start = 0, incr, eidx, end_pfn = bdata->node_low_pfn; 161 161 void *ret; 162 162 163 163 if(!size) { ··· 166 166 } 167 167 BUG_ON(align & (align-1)); 168 168 169 - eidx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); 169 + if (limit && bdata->node_boot_start >= limit) 170 + return NULL; 171 + 172 + limit >>=PAGE_SHIFT; 173 + if (limit && end_pfn > limit) 174 + end_pfn = limit; 175 + 176 + eidx = end_pfn - (bdata->node_boot_start >> PAGE_SHIFT); 170 177 offset = 0; 171 178 if (align && 172 179 (bdata->node_boot_start & (align - 1UL)) != 0) ··· 185 178 * first, then we try to allocate lower pages. 186 179 */ 187 180 if (goal && (goal >= bdata->node_boot_start) && 188 - ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) { 181 + ((goal >> PAGE_SHIFT) < end_pfn)) { 189 182 preferred = goal - bdata->node_boot_start; 190 183 191 184 if (bdata->last_success >= preferred) 192 - preferred = bdata->last_success; 185 + if (!limit || (limit && limit > bdata->last_success)) 186 + preferred = bdata->last_success; 193 187 } else 194 188 preferred = 0; 195 189 ··· 390 382 return(free_all_bootmem_core(NODE_DATA(0))); 391 383 } 392 384 393 - void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal) 385 + void * __init __alloc_bootmem_limit (unsigned long size, unsigned long align, unsigned long goal, 386 + unsigned long limit) 394 387 { 395 388 pg_data_t *pgdat = pgdat_list; 396 389 void *ptr; 397 390 398 391 for_each_pgdat(pgdat) 399 392 if ((ptr = __alloc_bootmem_core(pgdat->bdata, size, 400 - align, goal))) 393 + align, goal, limit))) 401 394 return(ptr); 402 395 403 396 /* ··· 409 400 return NULL; 410 401 } 411 402 412 - void * __init __alloc_bootmem_node (pg_data_t *pgdat, unsigned long size, unsigned long align, unsigned long goal) 403 + 404 + void * __init __alloc_bootmem_node_limit (pg_data_t *pgdat, unsigned long size, unsigned long align, 405 + unsigned long goal, unsigned long limit) 413 406 { 414 407 void *ptr; 415 408 416 - ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal); 409 + ptr = __alloc_bootmem_core(pgdat->bdata, size, align, goal, limit); 417 410 if (ptr) 418 411 return (ptr); 419 412 420 - return __alloc_bootmem(size, align, goal); 413 + return __alloc_bootmem_limit(size, align, goal, limit); 421 414 } 422 415