diff options
author | Imre Kaloz <kaloz@openwrt.org> | 2009-06-23 21:04:37 +0000 |
---|---|---|
committer | Imre Kaloz <kaloz@openwrt.org> | 2009-06-23 21:04:37 +0000 |
commit | ec03ced5fa6eb25eee164839268b538abb965e99 (patch) | |
tree | 6d3382662fa3ad4119d3a3cda223c53949ca4894 /target/linux/coldfire/patches/007-mcfv4e_arch_mm_mods_1.patch | |
parent | 777de3a39c4b92ad53b2b9363f405d0c4c28847a (diff) | |
download | master-187ad058-ec03ced5fa6eb25eee164839268b538abb965e99.tar.gz master-187ad058-ec03ced5fa6eb25eee164839268b538abb965e99.tar.bz2 master-187ad058-ec03ced5fa6eb25eee164839268b538abb965e99.zip |
use broken-out patches for the coldfire to make it easier to follow differences against the bsp
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@16547 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/coldfire/patches/007-mcfv4e_arch_mm_mods_1.patch')
-rw-r--r-- | target/linux/coldfire/patches/007-mcfv4e_arch_mm_mods_1.patch | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/target/linux/coldfire/patches/007-mcfv4e_arch_mm_mods_1.patch b/target/linux/coldfire/patches/007-mcfv4e_arch_mm_mods_1.patch new file mode 100644 index 0000000000..2abd477465 --- /dev/null +++ b/target/linux/coldfire/patches/007-mcfv4e_arch_mm_mods_1.patch @@ -0,0 +1,513 @@ +From 2bef1f8ce148cce9e782f75f9537767c1d8c0eea Mon Sep 17 00:00:00 2001 +From: Kurt Mahan <kmahan@freescale.com> +Date: Wed, 31 Oct 2007 16:58:27 -0600 +Subject: [PATCH] Core Coldfire/MCF5445x arch/mm changes. + +LTIBName: mcfv4e-arch-mm-mods-1 +Signed-off-by: Kurt Mahan <kmahan@freescale.com> +--- + arch/m68k/mm/Makefile | 1 + + arch/m68k/mm/cache.c | 41 ++++++++ + arch/m68k/mm/cf-mmu.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++++ + arch/m68k/mm/hwtest.c | 2 + + arch/m68k/mm/init.c | 3 +- + arch/m68k/mm/kmap.c | 13 +++ + arch/m68k/mm/memory.c | 66 +++++++++++++- + 7 files changed, 373 insertions(+), 4 deletions(-) + create mode 100644 arch/m68k/mm/cf-mmu.c + +--- a/arch/m68k/mm/Makefile ++++ b/arch/m68k/mm/Makefile +@@ -6,3 +6,4 @@ obj-y := cache.o init.o fault.o hwtest. + + obj-$(CONFIG_MMU_MOTOROLA) += kmap.o memory.o motorola.o + obj-$(CONFIG_MMU_SUN3) += sun3kmap.o sun3mmu.o ++obj-$(CONFIG_MMU_CFV4E) += cf-mmu.o kmap.o memory.o +--- a/arch/m68k/mm/cache.c ++++ b/arch/m68k/mm/cache.c +@@ -10,7 +10,11 @@ + #include <asm/pgalloc.h> + #include <asm/traps.h> + ++#ifdef CONFIG_COLDFIRE ++#include <asm/cfcache.h> ++#endif /* CONFIG_COLDFIRE */ + ++#ifndef CONFIG_COLDFIRE + static unsigned long virt_to_phys_slow(unsigned long vaddr) + { + if (CPU_IS_060) { +@@ -69,11 +73,45 @@ static unsigned long virt_to_phys_slow(u + } + return 0; + } ++#endif /* CONFIG_COLDFIRE */ ++ + + /* Push n pages at kernel virtual address and clear the icache */ + /* RZ: use cpush %bc instead of cpush %dc, cinv %ic */ + void flush_icache_range(unsigned long address, unsigned long endaddr) + { ++#ifdef CONFIG_COLDFIRE ++ unsigned long set; ++ unsigned long start_set; ++ unsigned long end_set; ++ ++ start_set = address & _ICACHE_SET_MASK; ++ end_set = endaddr & _ICACHE_SET_MASK; ++ ++ if (start_set > end_set) { ++ /* from the begining to the lowest address */ ++ for (set = 0; set <= end_set; set += (0x10 - 3)) ++ asm volatile ("cpushl %%ic,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%ic,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%ic,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%ic,(%0)" : : "a" (set)); ++ ++ /* next loop will finish the cache ie pass the hole */ ++ end_set = LAST_ICACHE_ADDR; ++ } ++ for (set = start_set; set <= end_set; set += (0x10 - 3)) ++ asm volatile ("cpushl %%ic,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%ic,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%ic,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%ic,(%0)" : : "a" (set)); ++ ++#else /* !CONFIG_COLDFIRE */ + + if (CPU_IS_040_OR_060) { + address &= PAGE_MASK; +@@ -94,9 +132,11 @@ void flush_icache_range(unsigned long ad + : "=&d" (tmp) + : "di" (FLUSH_I)); + } ++#endif /* CONFIG_COLDFIRE */ + } + EXPORT_SYMBOL(flush_icache_range); + ++#ifndef CONFIG_COLDFIRE + void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, + unsigned long addr, int len) + { +@@ -115,4 +155,5 @@ void flush_icache_user_range(struct vm_a + : "di" (FLUSH_I)); + } + } ++#endif /* CONFIG_COLDFIRE */ + +--- /dev/null ++++ b/arch/m68k/mm/cf-mmu.c +@@ -0,0 +1,251 @@ ++/* ++ * linux/arch/m68k/mm/cf-mmu.c ++ * ++ * Based upon linux/arch/m68k/mm/sun3mmu.c ++ * Based upon linux/arch/ppc/mm/mmu_context.c ++ * ++ * Implementations of mm routines specific to the Coldfire MMU. ++ * ++ * Copyright (c) 2008 Freescale Semiconductor, Inc. ++ */ ++ ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/mm.h> ++#include <linux/swap.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#ifdef CONFIG_BLK_DEV_RAM ++#include <linux/blkdev.h> ++#endif ++#include <linux/bootmem.h> ++ ++#include <asm/setup.h> ++#include <asm/uaccess.h> ++#include <asm/page.h> ++#include <asm/pgtable.h> ++#include <asm/system.h> ++#include <asm/machdep.h> ++#include <asm/io.h> ++#include <asm/mmu_context.h> ++#include <asm/cf_pgalloc.h> ++ ++#include <asm/coldfire.h> ++#include <asm/tlbflush.h> ++ ++mm_context_t next_mmu_context; ++unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1]; ++ ++atomic_t nr_free_contexts; ++struct mm_struct *context_mm[LAST_CONTEXT+1]; ++void steal_context(void); ++ ++ ++const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; ++ ++extern unsigned long empty_bad_page_table; ++extern unsigned long empty_bad_page; ++extern unsigned long num_pages; ++ ++extern char __init_begin, __init_end; ++ ++void free_initmem(void) ++{ ++ unsigned long addr; ++ unsigned long start = (unsigned long)&__init_begin; ++ unsigned long end = (unsigned long)&__init_end; ++ ++ printk(KERN_INFO "free_initmem: __init_begin = 0x%lx __init_end = 0x%lx\n", start, end); ++ ++ addr = (unsigned long)&__init_begin; ++ for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) { ++ /* not currently used */ ++ virt_to_page(addr)->flags &= ~(1 << PG_reserved); ++ init_page_count(virt_to_page(addr)); ++ free_page(addr); ++ totalram_pages++; ++ } ++} ++ ++/* Coldfire paging_init derived from sun3 */ ++void __init paging_init(void) ++{ ++ pgd_t * pg_dir; ++ pte_t * pg_table; ++ int i; ++ unsigned long address; ++ unsigned long next_pgtable; ++ unsigned long bootmem_end; ++ unsigned long zones_size[MAX_NR_ZONES]; ++ unsigned long size; ++ enum zone_type zone; ++ ++ empty_zero_page = (void *)alloc_bootmem_pages(PAGE_SIZE); ++ memset((void *)empty_zero_page, 0, PAGE_SIZE); ++ ++ pg_dir = swapper_pg_dir; ++ memset(swapper_pg_dir, 0, sizeof (swapper_pg_dir)); ++ ++ size = num_pages * sizeof(pte_t); ++ size = (size + PAGE_SIZE) & ~(PAGE_SIZE-1); ++ next_pgtable = (unsigned long)alloc_bootmem_pages(size); ++ ++ bootmem_end = (next_pgtable + size + PAGE_SIZE) & PAGE_MASK; ++ pg_dir += PAGE_OFFSET >> PGDIR_SHIFT; ++ ++ address = PAGE_OFFSET; ++ while (address < (unsigned long)high_memory) ++ { ++ pg_table = (pte_t *)next_pgtable; ++ next_pgtable += PTRS_PER_PTE * sizeof (pte_t); ++ pgd_val(*pg_dir) = (unsigned long) pg_table; ++ pg_dir++; ++ ++ /* now change pg_table to kernel virtual addresses */ ++ for (i=0; i<PTRS_PER_PTE; ++i, ++pg_table) ++ { ++ pte_t pte = pfn_pte(virt_to_pfn(address), PAGE_INIT); ++ if (address >= (unsigned long)high_memory) ++ pte_val (pte) = 0; ++ ++ set_pte (pg_table, pte); ++ address += PAGE_SIZE; ++ } ++ } ++ ++ current->mm = NULL; ++ ++ /* clear zones */ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) ++ zones_size[zone] = 0x0; ++ ++ /* allocate the bottom 32M (0x40x 0x41x) to DMA - head.S marks them NO CACHE */ ++ /* JKM - this should be changed to allocate from the TOP (0x4f,0x4e) but the ++ * allocator is being a bit challenging */ ++ zones_size[ZONE_DMA] = (32*1024*1024) >> PAGE_SHIFT; ++ ++ /* allocate the rest to NORMAL - head.S marks them CACHE */ ++ zones_size[ZONE_NORMAL] = (((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT) - zones_size[0]; ++ ++ free_area_init(zones_size); ++} ++ ++ ++int cf_tlb_miss(struct pt_regs *regs, int write, int dtlb, int extension_word) ++{ ++ struct mm_struct *mm; ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ unsigned long mmuar; ++ int asid; ++ int flags; ++ ++ local_save_flags(flags); ++ local_irq_disable(); ++ ++ mmuar = ( dtlb ) ? regs->mmuar ++ : regs->pc + (extension_word * sizeof(long)); ++ ++ mm = (!user_mode(regs) && (mmuar >= PAGE_OFFSET)) ? &init_mm ++ : current->mm; ++ if (!mm) { ++ local_irq_restore(flags); ++ return (-1); ++ } ++ ++ pgd = pgd_offset(mm, mmuar); ++ if (pgd_none(*pgd)) { ++ local_irq_restore(flags); ++ return (-1); ++ } ++ ++ pmd = pmd_offset(pgd, mmuar); ++ if (pmd_none(*pmd)) { ++ local_irq_restore(flags); ++ return (-1); ++ } ++ ++ pte = (mmuar >= PAGE_OFFSET) ? pte_offset_kernel(pmd, mmuar) ++ : pte_offset_map(pmd, mmuar); ++ if (pte_none(*pte) || !pte_present(*pte)) { ++ local_irq_restore(flags); ++ return (-1); ++ } ++ ++ if (write) { ++ if (!pte_write(*pte)) { ++ local_irq_restore(flags); ++ return (-1); ++ } ++ set_pte(pte, pte_mkdirty(*pte)); ++ } ++ ++ set_pte(pte, pte_mkyoung(*pte)); ++ asid = mm->context & 0xff; ++ if (!pte_dirty(*pte) && mmuar<=PAGE_OFFSET) ++ set_pte(pte, pte_wrprotect(*pte)); ++ ++ *MMUTR = (mmuar & PAGE_MASK) | (asid << CF_ASID_MMU_SHIFT) ++ | (((int)(pte->pte) & (int)CF_PAGE_MMUTR_MASK ) >> CF_PAGE_MMUTR_SHIFT) ++ | MMUTR_V; ++ ++ *MMUDR = (pte_val(*pte) & PAGE_MASK) ++ | ((pte->pte) & CF_PAGE_MMUDR_MASK) ++ | MMUDR_SZ8K | MMUDR_X; ++ ++ if ( dtlb ) ++ *MMUOR = MMUOR_ACC | MMUOR_UAA; ++ else ++ *MMUOR = MMUOR_ITLB | MMUOR_ACC | MMUOR_UAA; ++ ++ asm ("nop"); ++ /*printk("cf_tlb_miss: va=%lx, pa=%lx\n", (mmuar & PAGE_MASK), ++ (pte_val(*pte) & PAGE_MASK));*/ ++ local_irq_restore(flags); ++ return (0); ++} ++ ++ ++/* The following was taken from arch/ppc/mmu_context.c ++ * ++ * Initialize the context management stuff. ++ */ ++void __init mmu_context_init(void) ++{ ++ /* ++ * Some processors have too few contexts to reserve one for ++ * init_mm, and require using context 0 for a normal task. ++ * Other processors reserve the use of context zero for the kernel. ++ * This code assumes FIRST_CONTEXT < 32. ++ */ ++ context_map[0] = (1 << FIRST_CONTEXT) - 1; ++ next_mmu_context = FIRST_CONTEXT; ++ atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1); ++} ++ ++/* ++ * Steal a context from a task that has one at the moment. ++ * This is only used on 8xx and 4xx and we presently assume that ++ * they don't do SMP. If they do then thicfpgalloc.hs will have to check ++ * whether the MM we steal is in use. ++ * We also assume that this is only used on systems that don't ++ * use an MMU hash table - this is true for 8xx and 4xx. ++ * This isn't an LRU system, it just frees up each context in ++ * turn (sort-of pseudo-random replacement :). This would be the ++ * place to implement an LRU scheme if anyone was motivated to do it. ++ * -- paulus ++ */ ++void steal_context(void) ++{ ++ struct mm_struct *mm; ++ /* free up context `next_mmu_context' */ ++ /* if we shouldn't free context 0, don't... */ ++ if (next_mmu_context < FIRST_CONTEXT) ++ next_mmu_context = FIRST_CONTEXT; ++ mm = context_mm[next_mmu_context]; ++ flush_tlb_mm(mm); ++ destroy_context(mm); ++} +--- a/arch/m68k/mm/hwtest.c ++++ b/arch/m68k/mm/hwtest.c +@@ -25,6 +25,7 @@ + + #include <linux/module.h> + ++#ifndef CONFIG_COLDFIRE + int hwreg_present( volatile void *regp ) + { + int ret = 0; +@@ -82,4 +83,5 @@ int hwreg_write( volatile void *regp, un + return( ret ); + } + EXPORT_SYMBOL(hwreg_write); ++#endif + +--- a/arch/m68k/mm/init.c ++++ b/arch/m68k/mm/init.c +@@ -122,7 +122,6 @@ void __init mem_init(void) + if (MACH_IS_ATARI) + atari_stram_mem_init_hook(); + #endif +- + /* this will put all memory onto the freelists */ + totalram_pages = num_physpages = 0; + for_each_online_pgdat(pgdat) { +@@ -146,7 +145,7 @@ void __init mem_init(void) + } + } + +-#ifndef CONFIG_SUN3 ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE) + /* insert pointer tables allocated so far into the tablelist */ + init_pointer_table((unsigned long)kernel_pg_dir); + for (i = 0; i < PTRS_PER_PGD; i++) { +--- a/arch/m68k/mm/kmap.c ++++ b/arch/m68k/mm/kmap.c +@@ -24,7 +24,11 @@ + + #undef DEBUG + ++#ifndef CONFIG_COLDFIRE + #define PTRTREESIZE (256*1024) ++#else ++#define PTRTREESIZE PAGE_SIZE ++#endif + + /* + * For 040/060 we can use the virtual memory area like other architectures, +@@ -50,7 +54,11 @@ static inline void free_io_area(void *ad + + #else + ++#ifdef CONFIG_COLDFIRE ++#define IO_SIZE PAGE_SIZE ++#else + #define IO_SIZE (256*1024) ++#endif + + static struct vm_struct *iolist; + +@@ -170,7 +178,12 @@ void __iomem *__ioremap(unsigned long ph + break; + } + } else { ++#ifndef CONFIG_COLDFIRE + physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); ++#else ++ physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | \ ++ _PAGE_READWRITE); ++#endif + switch (cacheflag) { + case IOMAP_NOCACHE_SER: + case IOMAP_NOCACHE_NONSER: +--- a/arch/m68k/mm/memory.c ++++ b/arch/m68k/mm/memory.c +@@ -203,7 +203,38 @@ static inline void pushcl040(unsigned lo + + void cache_clear (unsigned long paddr, int len) + { +- if (CPU_IS_040_OR_060) { ++ if (CPU_IS_CFV4E) { ++ unsigned long set; ++ unsigned long start_set; ++ unsigned long end_set; ++ ++ start_set = paddr & _ICACHE_SET_MASK; ++ end_set = (paddr+len-1) & _ICACHE_SET_MASK; ++ ++ if (start_set > end_set) { ++ /* from the begining to the lowest address */ ++ for (set = 0; set <= end_set; set += (0x10 - 3)) ++ asm volatile("cpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)" : : "a" (set)); ++ ++ /* next loop will finish the cache ie pass the hole */ ++ end_set = LAST_ICACHE_ADDR; ++ } ++ for (set = start_set; set <= end_set; set += (0x10 - 3)) ++ asm volatile("cpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)" : : "a" (set)); ++ ++ } else if (CPU_IS_040_OR_060) { + int tmp; + + /* +@@ -250,7 +281,38 @@ EXPORT_SYMBOL(cache_clear); + + void cache_push (unsigned long paddr, int len) + { +- if (CPU_IS_040_OR_060) { ++ if (CPU_IS_CFV4E) { ++ unsigned long set; ++ unsigned long start_set; ++ unsigned long end_set; ++ ++ start_set = paddr & _ICACHE_SET_MASK; ++ end_set = (paddr+len-1) & _ICACHE_SET_MASK; ++ ++ if (start_set > end_set) { ++ /* from the begining to the lowest address */ ++ for (set = 0; set <= end_set; set += (0x10 - 3)) ++ asm volatile("cpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)" : : "a" (set)); ++ ++ /* next loop will finish the cache ie pass the hole */ ++ end_set = LAST_ICACHE_ADDR; ++ } ++ for (set = start_set; set <= end_set; set += (0x10 - 3)) ++ asm volatile("cpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)\n" ++ "\taddq%.l #1,%0\n" ++ "\tcpushl %%bc,(%0)" : : "a" (set)); ++ ++ } else if (CPU_IS_040_OR_060) { + int tmp = PAGE_SIZE; + + /* |