1*4d35b93aSMatt Fleming /* 2*4d35b93aSMatt Fleming * Re-map IO memory to kernel address space so that we can access it. 3*4d35b93aSMatt Fleming * 4*4d35b93aSMatt Fleming * These functions should only be used when it is necessary to map a 5*4d35b93aSMatt Fleming * physical address space into the kernel address space before ioremap() 6*4d35b93aSMatt Fleming * can be used, e.g. early in boot before paging_init(). 7*4d35b93aSMatt Fleming * 8*4d35b93aSMatt Fleming * Copyright (C) 2009 Matt Fleming 9*4d35b93aSMatt Fleming */ 10*4d35b93aSMatt Fleming 11*4d35b93aSMatt Fleming #include <linux/vmalloc.h> 12*4d35b93aSMatt Fleming #include <linux/ioport.h> 13*4d35b93aSMatt Fleming #include <linux/module.h> 14*4d35b93aSMatt Fleming #include <linux/mm.h> 15*4d35b93aSMatt Fleming #include <linux/io.h> 16*4d35b93aSMatt Fleming #include <linux/bootmem.h> 17*4d35b93aSMatt Fleming #include <linux/proc_fs.h> 18*4d35b93aSMatt Fleming #include <linux/slab.h> 19*4d35b93aSMatt Fleming #include <asm/fixmap.h> 20*4d35b93aSMatt Fleming #include <asm/page.h> 21*4d35b93aSMatt Fleming #include <asm/pgalloc.h> 22*4d35b93aSMatt Fleming #include <asm/addrspace.h> 23*4d35b93aSMatt Fleming #include <asm/cacheflush.h> 24*4d35b93aSMatt Fleming #include <asm/tlbflush.h> 25*4d35b93aSMatt Fleming #include <asm/mmu.h> 26*4d35b93aSMatt Fleming #include <asm/mmu_context.h> 27*4d35b93aSMatt Fleming 28*4d35b93aSMatt Fleming struct ioremap_map { 29*4d35b93aSMatt Fleming void __iomem *addr; 30*4d35b93aSMatt Fleming unsigned long size; 31*4d35b93aSMatt Fleming unsigned long fixmap_addr; 32*4d35b93aSMatt Fleming }; 33*4d35b93aSMatt Fleming 34*4d35b93aSMatt Fleming static struct ioremap_map ioremap_maps[FIX_N_IOREMAPS]; 35*4d35b93aSMatt Fleming 36*4d35b93aSMatt Fleming void __init ioremap_fixed_init(void) 37*4d35b93aSMatt Fleming { 38*4d35b93aSMatt Fleming struct ioremap_map *map; 39*4d35b93aSMatt Fleming int i; 40*4d35b93aSMatt Fleming 41*4d35b93aSMatt Fleming for (i = 0; i < FIX_N_IOREMAPS; i++) { 42*4d35b93aSMatt Fleming map = &ioremap_maps[i]; 43*4d35b93aSMatt Fleming map->fixmap_addr = __fix_to_virt(FIX_IOREMAP_BEGIN + i); 44*4d35b93aSMatt Fleming } 45*4d35b93aSMatt Fleming } 46*4d35b93aSMatt Fleming 47*4d35b93aSMatt Fleming void __init __iomem * 48*4d35b93aSMatt Fleming ioremap_fixed(resource_size_t phys_addr, unsigned long size, pgprot_t prot) 49*4d35b93aSMatt Fleming { 50*4d35b93aSMatt Fleming enum fixed_addresses idx0, idx; 51*4d35b93aSMatt Fleming resource_size_t last_addr; 52*4d35b93aSMatt Fleming struct ioremap_map *map; 53*4d35b93aSMatt Fleming unsigned long offset; 54*4d35b93aSMatt Fleming unsigned int nrpages; 55*4d35b93aSMatt Fleming int i, slot; 56*4d35b93aSMatt Fleming 57*4d35b93aSMatt Fleming slot = -1; 58*4d35b93aSMatt Fleming for (i = 0; i < FIX_N_IOREMAPS; i++) { 59*4d35b93aSMatt Fleming map = &ioremap_maps[i]; 60*4d35b93aSMatt Fleming if (!map->addr) { 61*4d35b93aSMatt Fleming map->size = size; 62*4d35b93aSMatt Fleming slot = i; 63*4d35b93aSMatt Fleming break; 64*4d35b93aSMatt Fleming } 65*4d35b93aSMatt Fleming } 66*4d35b93aSMatt Fleming 67*4d35b93aSMatt Fleming if (slot < 0) 68*4d35b93aSMatt Fleming return NULL; 69*4d35b93aSMatt Fleming 70*4d35b93aSMatt Fleming /* Don't allow wraparound or zero size */ 71*4d35b93aSMatt Fleming last_addr = phys_addr + size - 1; 72*4d35b93aSMatt Fleming if (!size || last_addr < phys_addr) 73*4d35b93aSMatt Fleming return NULL; 74*4d35b93aSMatt Fleming 75*4d35b93aSMatt Fleming /* 76*4d35b93aSMatt Fleming * Fixmap mappings have to be page-aligned 77*4d35b93aSMatt Fleming */ 78*4d35b93aSMatt Fleming offset = phys_addr & ~PAGE_MASK; 79*4d35b93aSMatt Fleming phys_addr &= PAGE_MASK; 80*4d35b93aSMatt Fleming size = PAGE_ALIGN(last_addr + 1) - phys_addr; 81*4d35b93aSMatt Fleming 82*4d35b93aSMatt Fleming /* 83*4d35b93aSMatt Fleming * Mappings have to fit in the FIX_IOREMAP area. 84*4d35b93aSMatt Fleming */ 85*4d35b93aSMatt Fleming nrpages = size >> PAGE_SHIFT; 86*4d35b93aSMatt Fleming if (nrpages > FIX_N_IOREMAPS) 87*4d35b93aSMatt Fleming return NULL; 88*4d35b93aSMatt Fleming 89*4d35b93aSMatt Fleming /* 90*4d35b93aSMatt Fleming * Ok, go for it.. 91*4d35b93aSMatt Fleming */ 92*4d35b93aSMatt Fleming idx0 = FIX_IOREMAP_BEGIN + slot; 93*4d35b93aSMatt Fleming idx = idx0; 94*4d35b93aSMatt Fleming while (nrpages > 0) { 95*4d35b93aSMatt Fleming pgprot_val(prot) |= _PAGE_WIRED; 96*4d35b93aSMatt Fleming __set_fixmap(idx, phys_addr, prot); 97*4d35b93aSMatt Fleming phys_addr += PAGE_SIZE; 98*4d35b93aSMatt Fleming idx++; 99*4d35b93aSMatt Fleming --nrpages; 100*4d35b93aSMatt Fleming } 101*4d35b93aSMatt Fleming 102*4d35b93aSMatt Fleming map->addr = (void __iomem *)(offset + map->fixmap_addr); 103*4d35b93aSMatt Fleming return map->addr; 104*4d35b93aSMatt Fleming } 105*4d35b93aSMatt Fleming 106*4d35b93aSMatt Fleming void __init iounmap_fixed(void __iomem *addr) 107*4d35b93aSMatt Fleming { 108*4d35b93aSMatt Fleming enum fixed_addresses idx; 109*4d35b93aSMatt Fleming unsigned long virt_addr; 110*4d35b93aSMatt Fleming struct ioremap_map *map; 111*4d35b93aSMatt Fleming unsigned long offset; 112*4d35b93aSMatt Fleming unsigned int nrpages; 113*4d35b93aSMatt Fleming int i, slot; 114*4d35b93aSMatt Fleming pgprot_t prot; 115*4d35b93aSMatt Fleming 116*4d35b93aSMatt Fleming slot = -1; 117*4d35b93aSMatt Fleming for (i = 0; i < FIX_N_IOREMAPS; i++) { 118*4d35b93aSMatt Fleming map = &ioremap_maps[i]; 119*4d35b93aSMatt Fleming if (map->addr == addr) { 120*4d35b93aSMatt Fleming slot = i; 121*4d35b93aSMatt Fleming break; 122*4d35b93aSMatt Fleming } 123*4d35b93aSMatt Fleming } 124*4d35b93aSMatt Fleming 125*4d35b93aSMatt Fleming if (slot < 0) 126*4d35b93aSMatt Fleming return; 127*4d35b93aSMatt Fleming 128*4d35b93aSMatt Fleming virt_addr = (unsigned long)addr; 129*4d35b93aSMatt Fleming 130*4d35b93aSMatt Fleming offset = virt_addr & ~PAGE_MASK; 131*4d35b93aSMatt Fleming nrpages = PAGE_ALIGN(offset + map->size - 1) >> PAGE_SHIFT; 132*4d35b93aSMatt Fleming 133*4d35b93aSMatt Fleming pgprot_val(prot) = _PAGE_WIRED; 134*4d35b93aSMatt Fleming 135*4d35b93aSMatt Fleming idx = FIX_IOREMAP_BEGIN + slot + nrpages; 136*4d35b93aSMatt Fleming while (nrpages > 0) { 137*4d35b93aSMatt Fleming __clear_fixmap(idx, prot); 138*4d35b93aSMatt Fleming --idx; 139*4d35b93aSMatt Fleming --nrpages; 140*4d35b93aSMatt Fleming } 141*4d35b93aSMatt Fleming 142*4d35b93aSMatt Fleming map->size = 0; 143*4d35b93aSMatt Fleming map->addr = NULL; 144*4d35b93aSMatt Fleming } 145