Skip to content

Commit

Permalink
Merge branch 'sh/ioremap-fixed'
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Mundt committed Jan 18, 2010
2 parents 4291b73 + 78bf04f commit 8faba61
Show file tree
Hide file tree
Showing 18 changed files with 458 additions and 299 deletions.
11 changes: 9 additions & 2 deletions arch/sh/boards/board-sh7785lcr.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,15 @@ static void __init sh7785lcr_setup(char **cmdline_p)
pm_power_off = sh7785lcr_power_off;

/* sm501 DRAM configuration */
sm501_reg = (void __iomem *)0xb3e00000 + SM501_DRAM_CONTROL;
writel(0x000307c2, sm501_reg);
sm501_reg = ioremap_fixed(SM107_REG_ADDR, SM501_DRAM_CONTROL,
PAGE_KERNEL);
if (!sm501_reg) {
printk(KERN_ERR "%s: ioremap error.\n", __func__);
return;
}

writel(0x000307c2, sm501_reg + SM501_DRAM_CONTROL);
iounmap_fixed(sm501_reg);
}

/* Return the board specific boot mode pin configuration */
Expand Down
9 changes: 9 additions & 0 deletions arch/sh/include/asm/fixmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,20 @@ 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
};

extern void __set_fixmap(enum fixed_addresses idx,
unsigned long phys, pgprot_t flags);
extern void __clear_fixmap(enum fixed_addresses idx, pgprot_t flags);

#define set_fixmap(idx, phys) \
__set_fixmap(idx, phys, PAGE_KERNEL)
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
2 changes: 1 addition & 1 deletion arch/sh/include/asm/page.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ typedef struct { unsigned long pgd; } pgd_t;
#define __pte(x) ((pte_t) { (x) } )
#else
typedef struct { unsigned long long pte_low; } pte_t;
typedef struct { unsigned long pgprot; } pgprot_t;
typedef struct { unsigned long long pgprot; } pgprot_t;
typedef struct { unsigned long pgd; } pgd_t;
#define pte_val(x) ((x).pte_low)
#define __pte(x) ((pte_t) { (x) } )
Expand Down
4 changes: 4 additions & 0 deletions arch/sh/include/asm/pgtable_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
#define _PAGE_EXT_KERN_WRITE 0x1000 /* EPR4-bit: Kernel space writable */
#define _PAGE_EXT_KERN_READ 0x2000 /* EPR5-bit: Kernel space readable */

#define _PAGE_EXT_WIRED 0x4000 /* software: Wire TLB entry */

/* Wrapper for extended mode pgprot twiddling */
#define _PAGE_EXT(x) ((unsigned long long)(x) << 32)

Expand Down Expand Up @@ -164,6 +166,8 @@ static inline unsigned long copy_ptea_attributes(unsigned long x)
(PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | \
_PAGE_DIRTY | _PAGE_SPECIAL)

#define _PAGE_WIRED (_PAGE_EXT(_PAGE_EXT_WIRED))

#ifndef __ASSEMBLY__

#if defined(CONFIG_X2TLB) /* SH-X2 TLB */
Expand Down
15 changes: 14 additions & 1 deletion arch/sh/include/asm/pgtable_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,21 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
#define _PAGE_DIRTY 0x400 /* software: page accessed in write */
#define _PAGE_ACCESSED 0x800 /* software: page referenced */

/* Wrapper for extended mode pgprot twiddling */
#define _PAGE_EXT(x) ((unsigned long long)(x) << 32)

/*
* We can use the sign-extended bits in the PTEL to get 32 bits of
* software flags. This works for now because no implementations uses
* anything above the PPN field.
*/
#define _PAGE_WIRED _PAGE_EXT(0x001) /* software: wire the tlb entry */

#define _PAGE_CLEAR_FLAGS (_PAGE_PRESENT | _PAGE_FILE | _PAGE_SHARED | \
_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_WIRED)

/* Mask which drops software flags */
#define _PAGE_FLAGS_HARDWARE_MASK 0xfffffffffffff3dbLL
#define _PAGE_FLAGS_HARDWARE_MASK (NEFF_MASK & ~(_PAGE_CLEAR_FLAGS))

/*
* HugeTLB support
Expand Down
57 changes: 57 additions & 0 deletions arch/sh/include/asm/tlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#ifdef CONFIG_MMU
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>

/*
* TLB handling. This allows us to remove pages from the page
Expand Down Expand Up @@ -97,6 +98,62 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)

#define tlb_migrate_finish(mm) do { } while (0)

#ifdef CONFIG_CPU_SH4
extern void tlb_wire_entry(struct vm_area_struct *, unsigned long, pte_t);
extern void tlb_unwire_entry(void);
#elif defined(CONFIG_SUPERH64)
static int dtlb_entry;
static unsigned long long dtlb_entries[64];

static inline void tlb_wire_entry(struct vm_area_struct *vma,
unsigned long addr, pte_t pte)
{
unsigned long long entry;
unsigned long paddr, flags;

BUG_ON(dtlb_entry == 64);

local_irq_save(flags);

entry = sh64_get_wired_dtlb_entry();
dtlb_entries[dtlb_entry++] = entry;

paddr = pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK;
paddr &= ~PAGE_MASK;

sh64_setup_tlb_slot(entry, addr, get_asid(), paddr);

local_irq_restore(flags);
}

static inline void tlb_unwire_entry(void)
{
unsigned long long entry;
unsigned long flags;

BUG_ON(!dtlb_entry);

local_irq_save(flags);
entry = dtlb_entries[dtlb_entry--];

sh64_teardown_tlb_slot(entry);
sh64_put_wired_dtlb_entry(entry);

local_irq_restore(flags);
}
#else
static inline void tlb_wire_entry(struct vm_area_struct *vma ,
unsigned long addr, pte_t pte)
{
BUG();
}

static inline void tlb_unwire_entry(void)
{
BUG();
}
#endif /* CONFIG_CPU_SH4 */

#else /* CONFIG_MMU */

#define tlb_start_vma(tlb, vma) do { } while (0)
Expand Down
4 changes: 4 additions & 0 deletions arch/sh/include/cpu-sh4/cpu/mmu_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@

#define MMUCR_TI (1<<2)

#define MMUCR_URB 0x00FC0000
#define MMUCR_URB_SHIFT 18
#define MMUCR_URB_NENTRIES 64

#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_SUBTYPE_ST40)
#define MMUCR_SE (1 << 4)
#else
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
44 changes: 40 additions & 4 deletions arch/sh/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ unsigned long cached_to_uncached = P2SEG - P1SEG;
#endif

#ifdef CONFIG_MMU
static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
static pte_t *__get_pte_phys(unsigned long addr)
{
pgd_t *pgd;
pud_t *pud;
Expand All @@ -49,29 +49,53 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
pgd = pgd_offset_k(addr);
if (pgd_none(*pgd)) {
pgd_ERROR(*pgd);
return;
return NULL;
}

pud = pud_alloc(NULL, pgd, addr);
if (unlikely(!pud)) {
pud_ERROR(*pud);
return;
return NULL;
}

pmd = pmd_alloc(NULL, pud, addr);
if (unlikely(!pmd)) {
pmd_ERROR(*pmd);
return;
return NULL;
}

pte = pte_offset_kernel(pmd, addr);
return pte;
}

static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
{
pte_t *pte;

pte = __get_pte_phys(addr);
if (!pte_none(*pte)) {
pte_ERROR(*pte);
return;
}

set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot));
local_flush_tlb_one(get_asid(), addr);

if (pgprot_val(prot) & _PAGE_WIRED)
tlb_wire_entry(NULL, addr, *pte);
}

static void clear_pte_phys(unsigned long addr, pgprot_t prot)
{
pte_t *pte;

pte = __get_pte_phys(addr);

if (pgprot_val(prot) & _PAGE_WIRED)
tlb_unwire_entry();

set_pte(pte, pfn_pte(0, __pgprot(0)));
local_flush_tlb_one(get_asid(), addr);
}

/*
Expand Down Expand Up @@ -101,6 +125,18 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
set_pte_phys(address, phys, prot);
}

void __clear_fixmap(enum fixed_addresses idx, pgprot_t prot)
{
unsigned long address = __fix_to_virt(idx);

if (idx >= __end_of_fixed_addresses) {
BUG();
return;
}

clear_pte_phys(address, prot);
}

void __init page_table_range_init(unsigned long start, unsigned long end,
pgd_t *pgd_base)
{
Expand Down
28 changes: 24 additions & 4 deletions arch/sh/mm/ioremap_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,35 @@ void __iomem *__ioremap_caller(unsigned long phys_addr, unsigned long size,
}
EXPORT_SYMBOL(__ioremap_caller);

/*
* Simple checks for non-translatable mappings.
*/
static inline int iomapping_nontranslatable(unsigned long offset)
{
#ifdef CONFIG_29BIT
/*
* In 29-bit mode this includes the fixed P1/P2 areas, as well as
* parts of P3.
*/
if (PXSEG(offset) < P3SEG || offset >= P3_ADDR_MAX)
return 1;
#endif

if (is_pci_memory_fixed_range(offset, 0))
return 1;

return 0;
}

void __iounmap(void __iomem *addr)
{
unsigned long vaddr = (unsigned long __force)addr;
unsigned long seg = PXSEG(vaddr);
struct vm_struct *p;

if (seg < P3SEG || vaddr >= P3_ADDR_MAX)
return;
if (is_pci_memory_fixed_range(vaddr, 0))
/*
* Nothing to do if there is no translatable mapping.
*/
if (iomapping_nontranslatable(vaddr))
return;

#ifdef CONFIG_PMB
Expand Down
Loading

0 comments on commit 8faba61

Please sign in to comment.