diff options
Diffstat (limited to 'arch/sh/mm')
-rw-r--r-- | arch/sh/mm/Kconfig | 3 | ||||
-rw-r--r-- | arch/sh/mm/Makefile_32 | 11 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh2.c | 45 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh2a.c | 129 | ||||
-rw-r--r-- | arch/sh/mm/consistent.c | 31 | ||||
-rw-r--r-- | arch/sh/mm/fault_64.c | 2 | ||||
-rw-r--r-- | arch/sh/mm/tlb-sh5.c | 20 |
7 files changed, 210 insertions, 31 deletions
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 56d0a7daa34..8a03926ea84 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -181,10 +181,12 @@ config ENTRY_OFFSET choice prompt "HugeTLB page size" depends on HUGETLB_PAGE && (CPU_SH4 || CPU_SH5) && MMU + default HUGETLB_PAGE_SIZE_1MB if PAGE_SIZE_64KB default HUGETLB_PAGE_SIZE_64K config HUGETLB_PAGE_SIZE_64K bool "64kB" + depends on !PAGE_SIZE_64KB config HUGETLB_PAGE_SIZE_256K bool "256kB" @@ -237,7 +239,6 @@ choice config CACHE_WRITEBACK bool "Write-back" - depends on CPU_SH2A || CPU_SH3 || CPU_SH4 || CPU_SH5 config CACHE_WRITETHROUGH bool "Write-through" diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32 index e295db60b91..70e0906023c 100644 --- a/arch/sh/mm/Makefile_32 +++ b/arch/sh/mm/Makefile_32 @@ -5,12 +5,15 @@ obj-y := init.o extable_32.o consistent.o ifndef CONFIG_CACHE_OFF -obj-$(CONFIG_CPU_SH2) += cache-sh2.o -obj-$(CONFIG_CPU_SH3) += cache-sh3.o -obj-$(CONFIG_CPU_SH4) += cache-sh4.o -obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o +cache-$(CONFIG_CPU_SH2) := cache-sh2.o +cache-$(CONFIG_CPU_SH2A) := cache-sh2a.o +cache-$(CONFIG_CPU_SH3) := cache-sh3.o +cache-$(CONFIG_CPU_SH4) := cache-sh4.o +cache-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o endif +obj-y += $(cache-y) + mmu-y := tlb-nommu.o pg-nommu.o mmu-$(CONFIG_MMU) := fault_32.o tlbflush_32.o ioremap_32.o diff --git a/arch/sh/mm/cache-sh2.c b/arch/sh/mm/cache-sh2.c index 6614033f6be..c4e80d2b764 100644 --- a/arch/sh/mm/cache-sh2.c +++ b/arch/sh/mm/cache-sh2.c @@ -2,6 +2,7 @@ * arch/sh/mm/cache-sh2.c * * Copyright (C) 2002 Paul Mundt + * Copyright (C) 2008 Yoshinori Sato * * Released under the terms of the GNU GPL v2.0. */ @@ -24,8 +25,15 @@ void __flush_wback_region(void *start, int size) end = ((unsigned long)start + size + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); for (v = begin; v < end; v+=L1_CACHE_BYTES) { - /* FIXME cache purge */ - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); + unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0); + int way; + for (way = 0; way < 4; way++) { + unsigned long data = ctrl_inl(addr | (way << 12)); + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { + data &= ~SH_CACHE_UPDATED; + ctrl_outl(data, addr | (way << 12)); + } + } } } @@ -37,21 +45,40 @@ void __flush_purge_region(void *start, int size) begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); end = ((unsigned long)start + size + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); - for (v = begin; v < end; v+=L1_CACHE_BYTES) { - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); - } + + for (v = begin; v < end; v+=L1_CACHE_BYTES) + ctrl_outl((v & CACHE_PHYSADDR_MASK), + CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); } void __flush_invalidate_region(void *start, int size) { +#ifdef CONFIG_CACHE_WRITEBACK + /* + * SH-2 does not support individual line invalidation, only a + * global invalidate. + */ + unsigned long ccr; + unsigned long flags; + local_irq_save(flags); + jump_to_uncached(); + + ccr = ctrl_inl(CCR); + ccr |= CCR_CACHE_INVALIDATE; + ctrl_outl(ccr, CCR); + + back_to_cached(); + local_irq_restore(flags); +#else unsigned long v; unsigned long begin, end; begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); end = ((unsigned long)start + size + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); - for (v = begin; v < end; v+=L1_CACHE_BYTES) { - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008); - } -} + for (v = begin; v < end; v+=L1_CACHE_BYTES) + ctrl_outl((v & CACHE_PHYSADDR_MASK), + CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); +#endif +} diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c new file mode 100644 index 00000000000..62c0c5f3512 --- /dev/null +++ b/arch/sh/mm/cache-sh2a.c @@ -0,0 +1,129 @@ +/* + * arch/sh/mm/cache-sh2a.c + * + * Copyright (C) 2008 Yoshinori Sato + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include <linux/init.h> +#include <linux/mm.h> + +#include <asm/cache.h> +#include <asm/addrspace.h> +#include <asm/processor.h> +#include <asm/cacheflush.h> +#include <asm/io.h> + +void __flush_wback_region(void *start, int size) +{ + unsigned long v; + unsigned long begin, end; + unsigned long flags; + + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) + & ~(L1_CACHE_BYTES-1); + + local_irq_save(flags); + jump_to_uncached(); + + for (v = begin; v < end; v+=L1_CACHE_BYTES) { + unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0); + int way; + for (way = 0; way < 4; way++) { + unsigned long data = ctrl_inl(addr | (way << 11)); + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { + data &= ~SH_CACHE_UPDATED; + ctrl_outl(data, addr | (way << 11)); + } + } + } + + back_to_cached(); + local_irq_restore(flags); +} + +void __flush_purge_region(void *start, int size) +{ + unsigned long v; + unsigned long begin, end; + unsigned long flags; + + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) + & ~(L1_CACHE_BYTES-1); + + local_irq_save(flags); + jump_to_uncached(); + + for (v = begin; v < end; v+=L1_CACHE_BYTES) { + ctrl_outl((v & CACHE_PHYSADDR_MASK), + CACHE_OC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); + } + back_to_cached(); + local_irq_restore(flags); +} + +void __flush_invalidate_region(void *start, int size) +{ + unsigned long v; + unsigned long begin, end; + unsigned long flags; + + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); + end = ((unsigned long)start + size + L1_CACHE_BYTES-1) + & ~(L1_CACHE_BYTES-1); + local_irq_save(flags); + jump_to_uncached(); + +#ifdef CONFIG_CACHE_WRITEBACK + ctrl_outl(ctrl_inl(CCR) | CCR_OCACHE_INVALIDATE, CCR); + /* I-cache invalidate */ + for (v = begin; v < end; v+=L1_CACHE_BYTES) { + ctrl_outl((v & CACHE_PHYSADDR_MASK), + CACHE_IC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); + } +#else + for (v = begin; v < end; v+=L1_CACHE_BYTES) { + ctrl_outl((v & CACHE_PHYSADDR_MASK), + CACHE_IC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); + ctrl_outl((v & CACHE_PHYSADDR_MASK), + CACHE_OC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008); + } +#endif + back_to_cached(); + local_irq_restore(flags); +} + +/* WBack O-Cache and flush I-Cache */ +void flush_icache_range(unsigned long start, unsigned long end) +{ + unsigned long v; + unsigned long flags; + + start = start & ~(L1_CACHE_BYTES-1); + end = (end + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); + + local_irq_save(flags); + jump_to_uncached(); + + for (v = start; v < end; v+=L1_CACHE_BYTES) { + unsigned long addr = (v & 0x000007f0); + int way; + /* O-Cache writeback */ + for (way = 0; way < 4; way++) { + unsigned long data = ctrl_inl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { + data &= ~SH_CACHE_UPDATED; + ctrl_outl(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); + } + } + /* I-Cache invalidate */ + ctrl_outl(addr, + CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); + } + + back_to_cached(); + local_irq_restore(flags); +} diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index b2ce014401b..64b8f7f96f9 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -95,8 +95,31 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size, } EXPORT_SYMBOL(dma_cache_sync); -int platform_resource_setup_memory(struct platform_device *pdev, - char *name, unsigned long memsize) +static int __init memchunk_setup(char *str) +{ + return 1; /* accept anything that begins with "memchunk." */ +} +__setup("memchunk.", memchunk_setup); + +static void __init memchunk_cmdline_override(char *name, unsigned long *sizep) +{ + char *p = boot_command_line; + int k = strlen(name); + + while ((p = strstr(p, "memchunk."))) { + p += 9; /* strlen("memchunk.") */ + if (!strncmp(name, p, k) && p[k] == '=') { + p += k + 1; + *sizep = memparse(p, NULL); + pr_info("%s: forcing memory chunk size to 0x%08lx\n", + name, *sizep); + break; + } + } +} + +int __init platform_resource_setup_memory(struct platform_device *pdev, + char *name, unsigned long memsize) { struct resource *r; dma_addr_t dma_handle; @@ -109,6 +132,10 @@ int platform_resource_setup_memory(struct platform_device *pdev, return -EINVAL; } + memchunk_cmdline_override(name, &memsize); + if (!memsize) + return 0; + buf = dma_alloc_coherent(NULL, memsize, &dma_handle, GFP_KERNEL); if (!buf) { pr_warning("%s: unable to allocate memory\n", name); diff --git a/arch/sh/mm/fault_64.c b/arch/sh/mm/fault_64.c index 399d53710d2..bd63b961b2a 100644 --- a/arch/sh/mm/fault_64.c +++ b/arch/sh/mm/fault_64.c @@ -39,7 +39,7 @@ #include <asm/uaccess.h> #include <asm/pgalloc.h> #include <asm/mmu_context.h> -#include <asm/cpu/registers.h> +#include <cpu/registers.h> /* Callable from fault.c, so not static */ inline void __do_tlb_refill(unsigned long address, diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c index f34274a1ded..dae131243bc 100644 --- a/arch/sh/mm/tlb-sh5.c +++ b/arch/sh/mm/tlb-sh5.c @@ -15,9 +15,7 @@ #include <asm/mmu_context.h> /** - * sh64_tlb_init - * - * Perform initial setup for the DTLB and ITLB. + * sh64_tlb_init - Perform initial setup for the DTLB and ITLB. */ int __init sh64_tlb_init(void) { @@ -46,9 +44,7 @@ int __init sh64_tlb_init(void) } /** - * sh64_next_free_dtlb_entry - * - * Find the next available DTLB entry + * sh64_next_free_dtlb_entry - Find the next available DTLB entry */ unsigned long long sh64_next_free_dtlb_entry(void) { @@ -56,9 +52,7 @@ unsigned long long sh64_next_free_dtlb_entry(void) } /** - * sh64_get_wired_dtlb_entry - * - * Allocate a wired (locked-in) entry in the DTLB + * sh64_get_wired_dtlb_entry - Allocate a wired (locked-in) entry in the DTLB */ unsigned long long sh64_get_wired_dtlb_entry(void) { @@ -71,12 +65,10 @@ unsigned long long sh64_get_wired_dtlb_entry(void) } /** - * sh64_put_wired_dtlb_entry + * sh64_put_wired_dtlb_entry - Free a wired (locked-in) entry in the DTLB. * * @entry: Address of TLB slot. * - * Free a wired (locked-in) entry in the DTLB. - * * Works like a stack, last one to allocate must be first one to free. */ int sh64_put_wired_dtlb_entry(unsigned long long entry) @@ -115,7 +107,7 @@ int sh64_put_wired_dtlb_entry(unsigned long long entry) } /** - * sh64_setup_tlb_slot + * sh64_setup_tlb_slot - Load up a translation in a wired slot. * * @config_addr: Address of TLB slot. * @eaddr: Virtual address. @@ -154,7 +146,7 @@ inline void sh64_setup_tlb_slot(unsigned long long config_addr, } /** - * sh64_teardown_tlb_slot + * sh64_teardown_tlb_slot - Teardown a translation. * * @config_addr: Address of TLB slot. * |