aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm/mem.c
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-08-08 19:40:42 -0400
committerScott Wood <scottwood@freescale.com>2014-09-03 18:58:21 -0400
commit1c98025c6c95bc057a25e2c6596de23288c68160 (patch)
tree37475259871168c9835b78ecd3d233f870945fa1 /arch/powerpc/mm/mem.c
parent78eb9094ca08a40b8f9d3e113a2b88e0b7dbad1d (diff)
powerpc: Dynamic DMA zone limits
Platform code can call limit_zone_pfn() to set appropriate limits for ZONE_DMA and ZONE_DMA32, and dma_direct_alloc_coherent() will select a suitable zone based on a device's mask and the pfn limits that platform code has configured. Signed-off-by: Scott Wood <scottwood@freescale.com> Cc: Shaohui Xie <Shaohui.Xie@freescale.com>
Diffstat (limited to 'arch/powerpc/mm/mem.c')
-rw-r--r--arch/powerpc/mm/mem.c61
1 files changed, 56 insertions, 5 deletions
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 2c8e90f5789e..687e7f7f7751 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -260,6 +260,54 @@ static int __init mark_nonram_nosave(void)
260 return 0; 260 return 0;
261} 261}
262 262
263static bool zone_limits_final;
264
265static unsigned long max_zone_pfns[MAX_NR_ZONES] = {
266 [0 ... MAX_NR_ZONES - 1] = ~0UL
267};
268
269/*
270 * Restrict the specified zone and all more restrictive zones
271 * to be below the specified pfn. May not be called after
272 * paging_init().
273 */
274void __init limit_zone_pfn(enum zone_type zone, unsigned long pfn_limit)
275{
276 int i;
277
278 if (WARN_ON(zone_limits_final))
279 return;
280
281 for (i = zone; i >= 0; i--) {
282 if (max_zone_pfns[i] > pfn_limit)
283 max_zone_pfns[i] = pfn_limit;
284 }
285}
286
287/*
288 * Find the least restrictive zone that is entirely below the
289 * specified pfn limit. Returns < 0 if no suitable zone is found.
290 *
291 * pfn_limit must be u64 because it can exceed 32 bits even on 32-bit
292 * systems -- the DMA limit can be higher than any possible real pfn.
293 */
294int dma_pfn_limit_to_zone(u64 pfn_limit)
295{
296 enum zone_type top_zone = ZONE_NORMAL;
297 int i;
298
299#ifdef CONFIG_HIGHMEM
300 top_zone = ZONE_HIGHMEM;
301#endif
302
303 for (i = top_zone; i >= 0; i--) {
304 if (max_zone_pfns[i] <= pfn_limit)
305 return i;
306 }
307
308 return -EPERM;
309}
310
263/* 311/*
264 * paging_init() sets up the page tables - in fact we've already done this. 312 * paging_init() sets up the page tables - in fact we've already done this.
265 */ 313 */
@@ -267,7 +315,7 @@ void __init paging_init(void)
267{ 315{
268 unsigned long long total_ram = memblock_phys_mem_size(); 316 unsigned long long total_ram = memblock_phys_mem_size();
269 phys_addr_t top_of_ram = memblock_end_of_DRAM(); 317 phys_addr_t top_of_ram = memblock_end_of_DRAM();
270 unsigned long max_zone_pfns[MAX_NR_ZONES]; 318 enum zone_type top_zone;
271 319
272#ifdef CONFIG_PPC32 320#ifdef CONFIG_PPC32
273 unsigned long v = __fix_to_virt(__end_of_fixed_addresses - 1); 321 unsigned long v = __fix_to_virt(__end_of_fixed_addresses - 1);
@@ -289,13 +337,16 @@ void __init paging_init(void)
289 (unsigned long long)top_of_ram, total_ram); 337 (unsigned long long)top_of_ram, total_ram);
290 printk(KERN_DEBUG "Memory hole size: %ldMB\n", 338 printk(KERN_DEBUG "Memory hole size: %ldMB\n",
291 (long int)((top_of_ram - total_ram) >> 20)); 339 (long int)((top_of_ram - total_ram) >> 20));
292 memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); 340
293#ifdef CONFIG_HIGHMEM 341#ifdef CONFIG_HIGHMEM
294 max_zone_pfns[ZONE_DMA] = lowmem_end_addr >> PAGE_SHIFT; 342 top_zone = ZONE_HIGHMEM;
295 max_zone_pfns[ZONE_HIGHMEM] = top_of_ram >> PAGE_SHIFT; 343 limit_zone_pfn(ZONE_NORMAL, lowmem_end_addr >> PAGE_SHIFT);
296#else 344#else
297 max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT; 345 top_zone = ZONE_NORMAL;
298#endif 346#endif
347
348 limit_zone_pfn(top_zone, top_of_ram >> PAGE_SHIFT);
349 zone_limits_final = true;
299 free_area_init_nodes(max_zone_pfns); 350 free_area_init_nodes(max_zone_pfns);
300 351
301 mark_nonram_nosave(); 352 mark_nonram_nosave();