19e5c33d7SMark Salter /* 29e5c33d7SMark Salter * Provide common bits of early_ioremap() support for architectures needing 39e5c33d7SMark Salter * temporary mappings during boot before ioremap() is available. 49e5c33d7SMark Salter * 59e5c33d7SMark Salter * This is mostly a direct copy of the x86 early_ioremap implementation. 69e5c33d7SMark Salter * 79e5c33d7SMark Salter * (C) Copyright 1995 1996, 2014 Linus Torvalds 89e5c33d7SMark Salter * 99e5c33d7SMark Salter */ 109e5c33d7SMark Salter #include <linux/kernel.h> 119e5c33d7SMark Salter #include <linux/init.h> 129e5c33d7SMark Salter #include <linux/io.h> 139e5c33d7SMark Salter #include <linux/module.h> 149e5c33d7SMark Salter #include <linux/slab.h> 159e5c33d7SMark Salter #include <linux/mm.h> 169e5c33d7SMark Salter #include <linux/vmalloc.h> 179e5c33d7SMark Salter #include <asm/fixmap.h> 189e5c33d7SMark Salter 199e5c33d7SMark Salter #ifdef CONFIG_MMU 209e5c33d7SMark Salter static int early_ioremap_debug __initdata; 219e5c33d7SMark Salter 229e5c33d7SMark Salter static int __init early_ioremap_debug_setup(char *str) 239e5c33d7SMark Salter { 249e5c33d7SMark Salter early_ioremap_debug = 1; 259e5c33d7SMark Salter 269e5c33d7SMark Salter return 0; 279e5c33d7SMark Salter } 289e5c33d7SMark Salter early_param("early_ioremap_debug", early_ioremap_debug_setup); 299e5c33d7SMark Salter 309e5c33d7SMark Salter static int after_paging_init __initdata; 319e5c33d7SMark Salter 329e5c33d7SMark Salter void __init __weak early_ioremap_shutdown(void) 339e5c33d7SMark Salter { 349e5c33d7SMark Salter } 359e5c33d7SMark Salter 369e5c33d7SMark Salter void __init early_ioremap_reset(void) 379e5c33d7SMark Salter { 389e5c33d7SMark Salter early_ioremap_shutdown(); 399e5c33d7SMark Salter after_paging_init = 1; 409e5c33d7SMark Salter } 419e5c33d7SMark Salter 429e5c33d7SMark Salter /* 439e5c33d7SMark Salter * Generally, ioremap() is available after paging_init() has been called. 449e5c33d7SMark Salter * Architectures wanting to allow early_ioremap after paging_init() can 459e5c33d7SMark Salter * define __late_set_fixmap and __late_clear_fixmap to do the right thing. 469e5c33d7SMark Salter */ 479e5c33d7SMark Salter #ifndef __late_set_fixmap 489e5c33d7SMark Salter static inline void __init __late_set_fixmap(enum fixed_addresses idx, 499e5c33d7SMark Salter phys_addr_t phys, pgprot_t prot) 509e5c33d7SMark Salter { 519e5c33d7SMark Salter BUG(); 529e5c33d7SMark Salter } 539e5c33d7SMark Salter #endif 549e5c33d7SMark Salter 559e5c33d7SMark Salter #ifndef __late_clear_fixmap 569e5c33d7SMark Salter static inline void __init __late_clear_fixmap(enum fixed_addresses idx) 579e5c33d7SMark Salter { 589e5c33d7SMark Salter BUG(); 599e5c33d7SMark Salter } 609e5c33d7SMark Salter #endif 619e5c33d7SMark Salter 629e5c33d7SMark Salter static void __iomem *prev_map[FIX_BTMAPS_SLOTS] __initdata; 639e5c33d7SMark Salter static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata; 649e5c33d7SMark Salter static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata; 659e5c33d7SMark Salter 669e5c33d7SMark Salter void __init early_ioremap_setup(void) 679e5c33d7SMark Salter { 689e5c33d7SMark Salter int i; 699e5c33d7SMark Salter 709e5c33d7SMark Salter for (i = 0; i < FIX_BTMAPS_SLOTS; i++) 719e5c33d7SMark Salter if (WARN_ON(prev_map[i])) 729e5c33d7SMark Salter break; 739e5c33d7SMark Salter 749e5c33d7SMark Salter for (i = 0; i < FIX_BTMAPS_SLOTS; i++) 759e5c33d7SMark Salter slot_virt[i] = __fix_to_virt(FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*i); 769e5c33d7SMark Salter } 779e5c33d7SMark Salter 789e5c33d7SMark Salter static int __init check_early_ioremap_leak(void) 799e5c33d7SMark Salter { 809e5c33d7SMark Salter int count = 0; 819e5c33d7SMark Salter int i; 829e5c33d7SMark Salter 839e5c33d7SMark Salter for (i = 0; i < FIX_BTMAPS_SLOTS; i++) 849e5c33d7SMark Salter if (prev_map[i]) 859e5c33d7SMark Salter count++; 869e5c33d7SMark Salter 879e5c33d7SMark Salter if (WARN(count, KERN_WARNING 889e5c33d7SMark Salter "Debug warning: early ioremap leak of %d areas detected.\n" 899e5c33d7SMark Salter "please boot with early_ioremap_debug and report the dmesg.\n", 909e5c33d7SMark Salter count)) 919e5c33d7SMark Salter return 1; 929e5c33d7SMark Salter return 0; 939e5c33d7SMark Salter } 949e5c33d7SMark Salter late_initcall(check_early_ioremap_leak); 959e5c33d7SMark Salter 969e5c33d7SMark Salter static void __init __iomem * 979e5c33d7SMark Salter __early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot) 989e5c33d7SMark Salter { 999e5c33d7SMark Salter unsigned long offset; 1009e5c33d7SMark Salter resource_size_t last_addr; 1019e5c33d7SMark Salter unsigned int nrpages; 1029e5c33d7SMark Salter enum fixed_addresses idx; 1039e5c33d7SMark Salter int i, slot; 1049e5c33d7SMark Salter 1059e5c33d7SMark Salter WARN_ON(system_state != SYSTEM_BOOTING); 1069e5c33d7SMark Salter 1079e5c33d7SMark Salter slot = -1; 1089e5c33d7SMark Salter for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { 1099e5c33d7SMark Salter if (!prev_map[i]) { 1109e5c33d7SMark Salter slot = i; 1119e5c33d7SMark Salter break; 1129e5c33d7SMark Salter } 1139e5c33d7SMark Salter } 1149e5c33d7SMark Salter 1159e5c33d7SMark Salter if (WARN(slot < 0, "%s(%08llx, %08lx) not found slot\n", 1169e5c33d7SMark Salter __func__, (u64)phys_addr, size)) 1179e5c33d7SMark Salter return NULL; 1189e5c33d7SMark Salter 1199e5c33d7SMark Salter /* Don't allow wraparound or zero size */ 1209e5c33d7SMark Salter last_addr = phys_addr + size - 1; 1219e5c33d7SMark Salter if (WARN_ON(!size || last_addr < phys_addr)) 1229e5c33d7SMark Salter return NULL; 1239e5c33d7SMark Salter 1249e5c33d7SMark Salter prev_size[slot] = size; 1259e5c33d7SMark Salter /* 1269e5c33d7SMark Salter * Mappings have to be page-aligned 1279e5c33d7SMark Salter */ 1289e5c33d7SMark Salter offset = phys_addr & ~PAGE_MASK; 1299e5c33d7SMark Salter phys_addr &= PAGE_MASK; 1309e5c33d7SMark Salter size = PAGE_ALIGN(last_addr + 1) - phys_addr; 1319e5c33d7SMark Salter 1329e5c33d7SMark Salter /* 1339e5c33d7SMark Salter * Mappings have to fit in the FIX_BTMAP area. 1349e5c33d7SMark Salter */ 1359e5c33d7SMark Salter nrpages = size >> PAGE_SHIFT; 1369e5c33d7SMark Salter if (WARN_ON(nrpages > NR_FIX_BTMAPS)) 1379e5c33d7SMark Salter return NULL; 1389e5c33d7SMark Salter 1399e5c33d7SMark Salter /* 1409e5c33d7SMark Salter * Ok, go for it.. 1419e5c33d7SMark Salter */ 1429e5c33d7SMark Salter idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot; 1439e5c33d7SMark Salter while (nrpages > 0) { 1449e5c33d7SMark Salter if (after_paging_init) 1459e5c33d7SMark Salter __late_set_fixmap(idx, phys_addr, prot); 1469e5c33d7SMark Salter else 1479e5c33d7SMark Salter __early_set_fixmap(idx, phys_addr, prot); 1489e5c33d7SMark Salter phys_addr += PAGE_SIZE; 1499e5c33d7SMark Salter --idx; 1509e5c33d7SMark Salter --nrpages; 1519e5c33d7SMark Salter } 1529e5c33d7SMark Salter WARN(early_ioremap_debug, "%s(%08llx, %08lx) [%d] => %08lx + %08lx\n", 1539e5c33d7SMark Salter __func__, (u64)phys_addr, size, slot, offset, slot_virt[slot]); 1549e5c33d7SMark Salter 1559e5c33d7SMark Salter prev_map[slot] = (void __iomem *)(offset + slot_virt[slot]); 1569e5c33d7SMark Salter return prev_map[slot]; 1579e5c33d7SMark Salter } 1589e5c33d7SMark Salter 1599e5c33d7SMark Salter void __init early_iounmap(void __iomem *addr, unsigned long size) 1609e5c33d7SMark Salter { 1619e5c33d7SMark Salter unsigned long virt_addr; 1629e5c33d7SMark Salter unsigned long offset; 1639e5c33d7SMark Salter unsigned int nrpages; 1649e5c33d7SMark Salter enum fixed_addresses idx; 1659e5c33d7SMark Salter int i, slot; 1669e5c33d7SMark Salter 1679e5c33d7SMark Salter slot = -1; 1689e5c33d7SMark Salter for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { 1699e5c33d7SMark Salter if (prev_map[i] == addr) { 1709e5c33d7SMark Salter slot = i; 1719e5c33d7SMark Salter break; 1729e5c33d7SMark Salter } 1739e5c33d7SMark Salter } 1749e5c33d7SMark Salter 1759e5c33d7SMark Salter if (WARN(slot < 0, "early_iounmap(%p, %08lx) not found slot\n", 1769e5c33d7SMark Salter addr, size)) 1779e5c33d7SMark Salter return; 1789e5c33d7SMark Salter 1799e5c33d7SMark Salter if (WARN(prev_size[slot] != size, 1809e5c33d7SMark Salter "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n", 1819e5c33d7SMark Salter addr, size, slot, prev_size[slot])) 1829e5c33d7SMark Salter return; 1839e5c33d7SMark Salter 1849e5c33d7SMark Salter WARN(early_ioremap_debug, "early_iounmap(%p, %08lx) [%d]\n", 1859e5c33d7SMark Salter addr, size, slot); 1869e5c33d7SMark Salter 1879e5c33d7SMark Salter virt_addr = (unsigned long)addr; 1889e5c33d7SMark Salter if (WARN_ON(virt_addr < fix_to_virt(FIX_BTMAP_BEGIN))) 1899e5c33d7SMark Salter return; 1909e5c33d7SMark Salter 1919e5c33d7SMark Salter offset = virt_addr & ~PAGE_MASK; 1929e5c33d7SMark Salter nrpages = PAGE_ALIGN(offset + size) >> PAGE_SHIFT; 1939e5c33d7SMark Salter 1949e5c33d7SMark Salter idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot; 1959e5c33d7SMark Salter while (nrpages > 0) { 1969e5c33d7SMark Salter if (after_paging_init) 1979e5c33d7SMark Salter __late_clear_fixmap(idx); 1989e5c33d7SMark Salter else 1999e5c33d7SMark Salter __early_set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR); 2009e5c33d7SMark Salter --idx; 2019e5c33d7SMark Salter --nrpages; 2029e5c33d7SMark Salter } 2039e5c33d7SMark Salter prev_map[slot] = NULL; 2049e5c33d7SMark Salter } 2059e5c33d7SMark Salter 2069e5c33d7SMark Salter /* Remap an IO device */ 2079e5c33d7SMark Salter void __init __iomem * 2089e5c33d7SMark Salter early_ioremap(resource_size_t phys_addr, unsigned long size) 2099e5c33d7SMark Salter { 2109e5c33d7SMark Salter return __early_ioremap(phys_addr, size, FIXMAP_PAGE_IO); 2119e5c33d7SMark Salter } 2129e5c33d7SMark Salter 2139e5c33d7SMark Salter /* Remap memory */ 2149e5c33d7SMark Salter void __init * 2159e5c33d7SMark Salter early_memremap(resource_size_t phys_addr, unsigned long size) 2169e5c33d7SMark Salter { 2179e5c33d7SMark Salter return (__force void *)__early_ioremap(phys_addr, size, 2189e5c33d7SMark Salter FIXMAP_PAGE_NORMAL); 2199e5c33d7SMark Salter } 220*6b0f68e3SMark Salter 221*6b0f68e3SMark Salter #define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT) 222*6b0f68e3SMark Salter 223*6b0f68e3SMark Salter void __init copy_from_early_mem(void *dest, phys_addr_t src, unsigned long size) 224*6b0f68e3SMark Salter { 225*6b0f68e3SMark Salter unsigned long slop, clen; 226*6b0f68e3SMark Salter char *p; 227*6b0f68e3SMark Salter 228*6b0f68e3SMark Salter while (size) { 229*6b0f68e3SMark Salter slop = src & ~PAGE_MASK; 230*6b0f68e3SMark Salter clen = size; 231*6b0f68e3SMark Salter if (clen > MAX_MAP_CHUNK - slop) 232*6b0f68e3SMark Salter clen = MAX_MAP_CHUNK - slop; 233*6b0f68e3SMark Salter p = early_memremap(src & PAGE_MASK, clen + slop); 234*6b0f68e3SMark Salter memcpy(dest, p + slop, clen); 235*6b0f68e3SMark Salter early_memunmap(p, clen + slop); 236*6b0f68e3SMark Salter dest += clen; 237*6b0f68e3SMark Salter src += clen; 238*6b0f68e3SMark Salter size -= clen; 239*6b0f68e3SMark Salter } 240*6b0f68e3SMark Salter } 241*6b0f68e3SMark Salter 2429e5c33d7SMark Salter #else /* CONFIG_MMU */ 2439e5c33d7SMark Salter 2449e5c33d7SMark Salter void __init __iomem * 2459e5c33d7SMark Salter early_ioremap(resource_size_t phys_addr, unsigned long size) 2469e5c33d7SMark Salter { 2479e5c33d7SMark Salter return (__force void __iomem *)phys_addr; 2489e5c33d7SMark Salter } 2499e5c33d7SMark Salter 2509e5c33d7SMark Salter /* Remap memory */ 2519e5c33d7SMark Salter void __init * 2529e5c33d7SMark Salter early_memremap(resource_size_t phys_addr, unsigned long size) 2539e5c33d7SMark Salter { 2549e5c33d7SMark Salter return (void *)phys_addr; 2559e5c33d7SMark Salter } 2569e5c33d7SMark Salter 2579e5c33d7SMark Salter void __init early_iounmap(void __iomem *addr, unsigned long size) 2589e5c33d7SMark Salter { 2599e5c33d7SMark Salter } 2609e5c33d7SMark Salter 2619e5c33d7SMark Salter #endif /* CONFIG_MMU */ 2629e5c33d7SMark Salter 2639e5c33d7SMark Salter 2649e5c33d7SMark Salter void __init early_memunmap(void *addr, unsigned long size) 2659e5c33d7SMark Salter { 2669e5c33d7SMark Salter early_iounmap((__force void __iomem *)addr, size); 2679e5c33d7SMark Salter } 268