Skip to content

Commit

Permalink
sh: Add fixed ioremap support
Browse files Browse the repository at this point in the history
Some devices need to be ioremap'd and accessed very early in the boot
process. It is not possible to use the standard ioremap() function in
this case because that requires kmalloc()'ing some virtual address space
and kmalloc() may not be available so early in boot.

This patch provides fixmap mappings that allow physical address ranges
to be remapped into the kernel address space during the early boot
stages.

Signed-off-by: Matt Fleming <matt@console-pimps.org>
  • Loading branch information
Matt Fleming committed Jan 16, 2010
1 parent 07cad4d commit 4d35b93
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 3 deletions.
8 changes: 8 additions & 0 deletions arch/sh/include/asm/fixmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ enum fixed_addresses {
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
#endif
/*
* FIX_IOREMAP entries are useful for mapping physical address
* space before ioremap() is useable, e.g. really early in boot
* before kmalloc() is working.
*/
#define FIX_N_IOREMAPS 32
FIX_IOREMAP_BEGIN,
FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS,
__end_of_fixed_addresses
};

Expand Down
6 changes: 6 additions & 0 deletions arch/sh/include/asm/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ void __iomem *__ioremap_caller(unsigned long offset, unsigned long size,
unsigned long flags, void *caller);
void __iounmap(void __iomem *addr);

#ifdef CONFIG_IOREMAP_FIXED
extern void __iomem *ioremap_fixed(resource_size_t, unsigned long, pgprot_t);
extern void iounmap_fixed(void __iomem *);
extern void ioremap_fixed_init(void);
#endif

static inline void __iomem *
__ioremap(unsigned long offset, unsigned long size, unsigned long flags)
{
Expand Down
7 changes: 4 additions & 3 deletions arch/sh/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,14 +449,15 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
paging_init();
pmb_init();

ioremap_fixed_init();

/* Perform the machine specific initialisation */
if (likely(sh_mv.mv_setup))
sh_mv.mv_setup(cmdline_p);

paging_init();
pmb_init();

#ifdef CONFIG_SMP
plat_smp_setup();
#endif
Expand Down
4 changes: 4 additions & 0 deletions arch/sh/mm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ config ARCH_MEMORY_PROBE
def_bool y
depends on MEMORY_HOTPLUG

config IOREMAP_FIXED
def_bool y
depends on X2TLB || SUPERH64

choice
prompt "Kernel page size"
default PAGE_SIZE_4KB
Expand Down
1 change: 1 addition & 0 deletions arch/sh/mm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ endif
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
obj-$(CONFIG_PMB) += pmb.o
obj-$(CONFIG_NUMA) += numa.o
obj-$(CONFIG_IOREMAP_FIXED) += ioremap_fixed.o

# Special flags for fault_64.o. This puts restrictions on the number of
# caller-save registers that the compiler can target when building this file.
Expand Down
144 changes: 144 additions & 0 deletions arch/sh/mm/ioremap_fixed.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Re-map IO memory to kernel address space so that we can access it.
*
* These functions should only be used when it is necessary to map a
* physical address space into the kernel address space before ioremap()
* can be used, e.g. early in boot before paging_init().
*
* Copyright (C) 2009 Matt Fleming
*/

#include <linux/vmalloc.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/bootmem.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <asm/fixmap.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/addrspace.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/mmu.h>
#include <asm/mmu_context.h>

struct ioremap_map {
void __iomem *addr;
unsigned long size;
unsigned long fixmap_addr;
};

static struct ioremap_map ioremap_maps[FIX_N_IOREMAPS];

void __init ioremap_fixed_init(void)
{
struct ioremap_map *map;
int i;

for (i = 0; i < FIX_N_IOREMAPS; i++) {
map = &ioremap_maps[i];
map->fixmap_addr = __fix_to_virt(FIX_IOREMAP_BEGIN + i);
}
}

void __init __iomem *
ioremap_fixed(resource_size_t phys_addr, unsigned long size, pgprot_t prot)
{
enum fixed_addresses idx0, idx;
resource_size_t last_addr;
struct ioremap_map *map;
unsigned long offset;
unsigned int nrpages;
int i, slot;

slot = -1;
for (i = 0; i < FIX_N_IOREMAPS; i++) {
map = &ioremap_maps[i];
if (!map->addr) {
map->size = size;
slot = i;
break;
}
}

if (slot < 0)
return NULL;

/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
if (!size || last_addr < phys_addr)
return NULL;

/*
* Fixmap mappings have to be page-aligned
*/
offset = phys_addr & ~PAGE_MASK;
phys_addr &= PAGE_MASK;
size = PAGE_ALIGN(last_addr + 1) - phys_addr;

/*
* Mappings have to fit in the FIX_IOREMAP area.
*/
nrpages = size >> PAGE_SHIFT;
if (nrpages > FIX_N_IOREMAPS)
return NULL;

/*
* Ok, go for it..
*/
idx0 = FIX_IOREMAP_BEGIN + slot;
idx = idx0;
while (nrpages > 0) {
pgprot_val(prot) |= _PAGE_WIRED;
__set_fixmap(idx, phys_addr, prot);
phys_addr += PAGE_SIZE;
idx++;
--nrpages;
}

map->addr = (void __iomem *)(offset + map->fixmap_addr);
return map->addr;
}

void __init iounmap_fixed(void __iomem *addr)
{
enum fixed_addresses idx;
unsigned long virt_addr;
struct ioremap_map *map;
unsigned long offset;
unsigned int nrpages;
int i, slot;
pgprot_t prot;

slot = -1;
for (i = 0; i < FIX_N_IOREMAPS; i++) {
map = &ioremap_maps[i];
if (map->addr == addr) {
slot = i;
break;
}
}

if (slot < 0)
return;

virt_addr = (unsigned long)addr;

offset = virt_addr & ~PAGE_MASK;
nrpages = PAGE_ALIGN(offset + map->size - 1) >> PAGE_SHIFT;

pgprot_val(prot) = _PAGE_WIRED;

idx = FIX_IOREMAP_BEGIN + slot + nrpages;
while (nrpages > 0) {
__clear_fixmap(idx, prot);
--idx;
--nrpages;
}

map->size = 0;
map->addr = NULL;
}

0 comments on commit 4d35b93

Please sign in to comment.