From 5084f61a4d6c9c7bfd3be07fbb5253c1a08cd568 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 3 Jul 2009 23:34:51 +0100 Subject: sh: Use bootmem ontop of lmb for NUMA Like the UP case, use lmb as the foundation of memory resource management on NUMA. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/mm/numa.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/numa.c b/arch/sh/mm/numa.c index 095d93bec7cd..9b784fdb947c 100644 --- a/arch/sh/mm/numa.c +++ b/arch/sh/mm/numa.c @@ -9,6 +9,7 @@ */ #include #include +#include #include #include #include @@ -26,6 +27,15 @@ EXPORT_SYMBOL_GPL(node_data); void __init setup_memory(void) { unsigned long free_pfn = PFN_UP(__pa(_end)); + u64 base = min_low_pfn << PAGE_SHIFT; + u64 size = (max_low_pfn << PAGE_SHIFT) - min_low_pfn; + + lmb_add(base, size); + + /* Reserve the LMB regions used by the kernel, initrd, etc.. */ + lmb_reserve(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET, + (PFN_PHYS(free_pfn) + PAGE_SIZE - 1) - + (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET)); /* * Node 0 sets up its pgdat at the first available pfn, @@ -45,24 +55,23 @@ void __init setup_memory(void) void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end) { - unsigned long bootmap_pages, bootmap_start, bootmap_size; - unsigned long start_pfn, free_pfn, end_pfn; + unsigned long bootmap_pages; + unsigned long start_pfn, end_pfn; + unsigned long bootmem_paddr; /* Don't allow bogus node assignment */ BUG_ON(nid > MAX_NUMNODES || nid == 0); - /* - * The free pfn starts at the beginning of the range, and is - * advanced as necessary for pgdat and node map allocations. - */ - free_pfn = start_pfn = start >> PAGE_SHIFT; + start_pfn = start >> PAGE_SHIFT; end_pfn = end >> PAGE_SHIFT; + lmb_add(start, end - start); + __add_active_range(nid, start_pfn, end_pfn); /* Node-local pgdat */ - NODE_DATA(nid) = pfn_to_kaddr(free_pfn); - free_pfn += PFN_UP(sizeof(struct pglist_data)); + NODE_DATA(nid) = __va(lmb_alloc_base(sizeof(struct pglist_data), + SMP_CACHE_BYTES, end_pfn)); memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); NODE_DATA(nid)->bdata = &bootmem_node_data[nid]; @@ -71,16 +80,17 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end) /* Node-local bootmap */ bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); - bootmap_start = (unsigned long)pfn_to_kaddr(free_pfn); - bootmap_size = init_bootmem_node(NODE_DATA(nid), free_pfn, start_pfn, - end_pfn); + bootmem_paddr = lmb_alloc_base(bootmap_pages << PAGE_SHIFT, + PAGE_SIZE, end_pfn); + init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT, + start_pfn, end_pfn); free_bootmem_with_active_regions(nid, end_pfn); /* Reserve the pgdat and bootmap space with the bootmem allocator */ reserve_bootmem_node(NODE_DATA(nid), start_pfn << PAGE_SHIFT, sizeof(struct pglist_data), BOOTMEM_DEFAULT); - reserve_bootmem_node(NODE_DATA(nid), free_pfn << PAGE_SHIFT, + reserve_bootmem_node(NODE_DATA(nid), bootmem_paddr, bootmap_pages << PAGE_SHIFT, BOOTMEM_DEFAULT); /* It's up */ -- cgit From c63c3105e4991b2991ba73a742b8b59bfdbe4acd Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sun, 5 Jul 2009 02:50:10 +0900 Subject: sh: use kprobes_built_in() for notify_page_fault(). Kill off the KPROBES ifdef, as per x86. Signed-off-by: Paul Mundt --- arch/sh/mm/fault_32.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index 71925946f1e1..ce75b8882efb 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -25,14 +25,12 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap) { int ret = 0; -#ifdef CONFIG_KPROBES - if (!user_mode(regs)) { + if (kprobes_built_in() && !user_mode(regs)) { preempt_disable(); if (kprobe_running() && kprobe_fault_handler(regs, trap)) ret = 1; preempt_enable(); } -#endif return ret; } -- cgit From 0f60bb25b4036d30fd795709be09626c58c52464 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sun, 5 Jul 2009 03:18:47 +0900 Subject: sh: Tidy up vmalloc fault handling. This rewrites the vmalloc fault handling as per x86, which subsequently allows for easy future tie-in for vmalloc_sync_all(). Signed-off-by: Paul Mundt --- arch/sh/mm/fault_32.c | 153 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 97 insertions(+), 56 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index ce75b8882efb..08d0117d90fa 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -2,7 +2,7 @@ * Page fault handler for SH with an MMU. * * Copyright (C) 1999 Niibe Yutaka - * Copyright (C) 2003 - 2008 Paul Mundt + * Copyright (C) 2003 - 2009 Paul Mundt * * Based on linux/arch/i386/mm/fault.c: * Copyright (C) 1995 Linus Torvalds @@ -35,6 +35,74 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap) return ret; } +static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) +{ + unsigned index = pgd_index(address); + pgd_t *pgd_k; + pud_t *pud, *pud_k; + pmd_t *pmd, *pmd_k; + + pgd += index; + pgd_k = init_mm.pgd + index; + + if (!pgd_present(*pgd_k)) + return NULL; + + pud = pud_offset(pgd, address); + pud_k = pud_offset(pgd_k, address); + if (!pud_present(*pud_k)) + return NULL; + + pmd = pmd_offset(pud, address); + pmd_k = pmd_offset(pud_k, address); + if (!pmd_present(*pmd_k)) + return NULL; + + if (!pmd_present(*pmd)) + set_pmd(pmd, *pmd_k); + else + BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); + + return pmd_k; +} + +/* + * Handle a fault on the vmalloc or module mapping area + */ +static noinline int vmalloc_fault(unsigned long address) +{ + pgd_t *pgd_k; + pmd_t *pmd_k; + pte_t *pte_k; + + /* Make sure we are in vmalloc area: */ + if (!(address >= VMALLOC_START && address < VMALLOC_END)) + return -1; + + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. + * + * Do _not_ use "current" here. We might be inside + * an interrupt in the middle of a task switch.. + */ + pgd_k = get_TTB(); + pmd_k = vmalloc_sync_one(__va((unsigned long)pgd_k), address); + if (!pmd_k) + return -1; + + pte_k = pte_offset_kernel(pmd_k, address); + if (!pte_present(*pte_k)) + return -1; + + return 0; +} + +static int fault_in_kernel_space(unsigned long address) +{ + return address >= TASK_SIZE; +} + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -44,6 +112,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writeaccess, unsigned long address) { + unsigned long vec; struct task_struct *tsk; struct mm_struct *mm; struct vm_area_struct * vma; @@ -51,59 +120,30 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, int fault; siginfo_t info; - /* - * We don't bother with any notifier callbacks here, as they are - * all handled through the __do_page_fault() fast-path. - */ - tsk = current; + mm = tsk->mm; si_code = SEGV_MAPERR; + vec = lookup_exception_vector(); - if (unlikely(address >= TASK_SIZE)) { - /* - * Synchronize this task's top level page-table - * with the 'reference' page table. - * - * Do _not_ use "tsk" here. We might be inside - * an interrupt in the middle of a task switch.. - */ - int offset = pgd_index(address); - pgd_t *pgd, *pgd_k; - pud_t *pud, *pud_k; - pmd_t *pmd, *pmd_k; - - pgd = get_TTB() + offset; - pgd_k = swapper_pg_dir + offset; - - if (!pgd_present(*pgd)) { - if (!pgd_present(*pgd_k)) - goto bad_area_nosemaphore; - set_pgd(pgd, *pgd_k); + /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + */ + if (unlikely(fault_in_kernel_space(address))) { + if (vmalloc_fault(address) >= 0) return; - } - - pud = pud_offset(pgd, address); - pud_k = pud_offset(pgd_k, address); - - if (!pud_present(*pud)) { - if (!pud_present(*pud_k)) - goto bad_area_nosemaphore; - set_pud(pud, *pud_k); + if (notify_page_fault(regs, vec)) return; - } - - pmd = pmd_offset(pud, address); - pmd_k = pmd_offset(pud_k, address); - if (pmd_present(*pmd) || !pmd_present(*pmd_k)) - goto bad_area_nosemaphore; - set_pmd(pmd, *pmd_k); - return; + goto bad_area_nosemaphore; } - mm = tsk->mm; - - if (unlikely(notify_page_fault(regs, lookup_exception_vector()))) + if (unlikely(notify_page_fault(regs, vec))) return; /* Only enable interrupts if they were on before the fault */ @@ -113,8 +153,8 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, perf_swcounter_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); /* - * If we're in an interrupt or have no user - * context, we must not take the fault.. + * If we're in an interrupt, have no user context or are running + * in an atomic region then we must not take the fault: */ if (in_atomic() || !mm) goto no_context; @@ -130,10 +170,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, goto bad_area; if (expand_stack(vma, address)) goto bad_area; -/* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ + + /* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ good_area: si_code = SEGV_ACCERR; if (writeaccess) { @@ -171,10 +212,10 @@ survive: up_read(&mm->mmap_sem); return; -/* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ + /* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ bad_area: up_read(&mm->mmap_sem); -- cgit From 05dd2cd3bb3299540e33ff60c5b401dd88f273bd Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Mon, 13 Jul 2009 11:38:04 +0000 Subject: sh: Restore previous behaviour on kernel fault The last commit changed the behaviour on kernel faults when we were doing something other than syncing the page tables. vmalloc_sync_one() needs to return NULL if the page tables are up to date, because the reason for the fault was not a missing/inconsitent page table entry. By returning NULL if the page tables are sync'd we signal to the calling function that further work must be done to resolve this fault. Also, remove the superfluous __va() around the first argument to vmalloc_sync_one(). The value of pgd_k is already a virtual address and using it wth __va() causes a NULL dereference. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/mm/fault_32.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index 08d0117d90fa..dbbdeba2cee5 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -60,8 +60,15 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) if (!pmd_present(*pmd)) set_pmd(pmd, *pmd_k); - else + else { + /* + * The page tables are fully synchronised so there must + * be another reason for the fault. Return NULL here to + * signal that we have not taken care of the fault. + */ BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); + return NULL; + } return pmd_k; } @@ -87,7 +94,7 @@ static noinline int vmalloc_fault(unsigned long address) * an interrupt in the middle of a task switch.. */ pgd_k = get_TTB(); - pmd_k = vmalloc_sync_one(__va((unsigned long)pgd_k), address); + pmd_k = vmalloc_sync_one(pgd_k, address); if (!pmd_k) return -1; -- cgit From 2277ab4a1df50e05bc732fe9488d4e902bb8399a Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 22 Jul 2009 19:20:49 +0900 Subject: sh: Migrate from PG_mapped to PG_dcache_dirty. This inverts the delayed dcache flush a bit to be more in line with other platforms. At the same time this also gives us the ability to do some more optimizations and cleanup. Now that the update_mmu_cache() callsite only tests for the bit, the implementation can gradually be split out and made generic, rather than relying on special implementations for each of the peculiar CPU types. SH7705 in 32kB mode and SH-4 still need slightly different handling, but this is something that can remain isolated in the varying page copy/clear routines. On top of that, SH-X3 is dcache coherent, so there is no need to bother with any of these tests in the PTEAEX version of update_mmu_cache(), so we kill that off too. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 10 ++++++- arch/sh/mm/cache-sh7705.c | 7 ++++- arch/sh/mm/pg-sh4.c | 74 +++++++++++++++++++---------------------------- arch/sh/mm/pg-sh7705.c | 52 +++++---------------------------- arch/sh/mm/tlb-pteaex.c | 17 ----------- arch/sh/mm/tlb-sh3.c | 20 ++++++------- arch/sh/mm/tlb-sh4.c | 23 +++++++-------- 7 files changed, 73 insertions(+), 130 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 5cfe08dbb59e..c3a09b27f8d5 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -246,7 +247,14 @@ static inline void flush_cache_4096(unsigned long start, */ void flush_dcache_page(struct page *page) { - if (test_bit(PG_mapped, &page->flags)) { + struct address_space *mapping = page_mapping(page); + +#ifndef CONFIG_SMP + if (mapping && !mapping_mapped(mapping)) + set_bit(PG_dcache_dirty, &page->flags); + else +#endif + { unsigned long phys = PHYSADDR(page_address(page)); unsigned long addr = CACHE_OC_ADDRESS_ARRAY; int i, n; diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 22dacc778823..fa37bff306b9 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -128,7 +129,11 @@ static void __uses_jump_to_uncached __flush_dcache_page(unsigned long phys) */ void flush_dcache_page(struct page *page) { - if (test_bit(PG_mapped, &page->flags)) + struct address_space *mapping = page_mapping(page); + + if (mapping && !mapping_mapped(mapping)) + set_bit(PG_dcache_dirty, &page->flags); + else __flush_dcache_page(PHYSADDR(page_address(page))); } diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c index 2fe14da1f839..f3c4b2a54fc7 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c @@ -15,8 +15,6 @@ #include #include -#define CACHE_ALIAS (current_cpu_data.dcache.alias_mask) - #define kmap_get_fixmap_pte(vaddr) \ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)) @@ -68,10 +66,9 @@ static inline void kunmap_coherent(struct page *page) */ void clear_user_page(void *to, unsigned long address, struct page *page) { - __set_bit(PG_mapped, &page->flags); - clear_page(to); - if ((((address & PAGE_MASK) ^ (unsigned long)to) & CACHE_ALIAS)) + + if (pages_do_alias((unsigned long)to, address & PAGE_MASK)) __flush_wback_region(to, PAGE_SIZE); } @@ -79,13 +76,14 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) { - void *vto; - - __set_bit(PG_mapped, &page->flags); - - vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); - memcpy(vto, src, len); - kunmap_coherent(vto); + if (page_mapped(page) && !test_bit(PG_dcache_dirty, &page->flags)) { + void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(vto, src, len); + kunmap_coherent(vto); + } else { + memcpy(dst, src, len); + set_bit(PG_dcache_dirty, &page->flags); + } if (vma->vm_flags & VM_EXEC) flush_cache_page(vma, vaddr, page_to_pfn(page)); @@ -95,13 +93,14 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) { - void *vfrom; - - __set_bit(PG_mapped, &page->flags); - - vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); - memcpy(dst, vfrom, len); - kunmap_coherent(vfrom); + if (page_mapped(page) && !test_bit(PG_dcache_dirty, &page->flags)) { + void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(dst, vfrom, len); + kunmap_coherent(vfrom); + } else { + memcpy(dst, src, len); + set_bit(PG_dcache_dirty, &page->flags); + } } void copy_user_highpage(struct page *to, struct page *from, @@ -109,14 +108,19 @@ void copy_user_highpage(struct page *to, struct page *from, { void *vfrom, *vto; - __set_bit(PG_mapped, &to->flags); - vto = kmap_atomic(to, KM_USER1); - vfrom = kmap_coherent(from, vaddr); - copy_page(vto, vfrom); - kunmap_coherent(vfrom); - if (((vaddr ^ (unsigned long)vto) & CACHE_ALIAS)) + if (page_mapped(from) && !test_bit(PG_dcache_dirty, &from->flags)) { + vfrom = kmap_coherent(from, vaddr); + copy_page(vto, vfrom); + kunmap_coherent(vfrom); + } else { + vfrom = kmap_atomic(from, KM_USER0); + copy_page(vto, vfrom); + kunmap_atomic(vfrom, KM_USER0); + } + + if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) __flush_wback_region(vto, PAGE_SIZE); kunmap_atomic(vto, KM_USER1); @@ -124,23 +128,3 @@ void copy_user_highpage(struct page *to, struct page *from, smp_wmb(); } EXPORT_SYMBOL(copy_user_highpage); - -/* - * For SH-4, we have our own implementation for ptep_get_and_clear - */ -pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) -{ - pte_t pte = *ptep; - - pte_clear(mm, addr, ptep); - if (!pte_not_present(pte)) { - unsigned long pfn = pte_pfn(pte); - if (pfn_valid(pfn)) { - struct page *page = pfn_to_page(pfn); - struct address_space *mapping = page_mapping(page); - if (!mapping || !mapping_writably_mapped(mapping)) - __clear_bit(PG_mapped, &page->flags); - } - } - return pte; -} diff --git a/arch/sh/mm/pg-sh7705.c b/arch/sh/mm/pg-sh7705.c index eaf25147194c..684891b5c8c0 100644 --- a/arch/sh/mm/pg-sh7705.c +++ b/arch/sh/mm/pg-sh7705.c @@ -26,7 +26,7 @@ #include #include -static inline void __flush_purge_virtual_region(void *p1, void *virt, int size) +static void __flush_purge_virtual_region(void *p1, void *virt, int size) { unsigned long v; unsigned long begin, end; @@ -75,19 +75,13 @@ static inline void __flush_purge_virtual_region(void *p1, void *virt, int size) */ void clear_user_page(void *to, unsigned long address, struct page *pg) { - struct page *page = virt_to_page(to); - - __set_bit(PG_mapped, &page->flags); - if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { - clear_page(to); - __flush_wback_region(to, PAGE_SIZE); - } else { + if (pages_do_alias(address, (unsigned long)to)) __flush_purge_virtual_region(to, (void *)(address & 0xfffff000), PAGE_SIZE); - clear_page(to); - __flush_wback_region(to, PAGE_SIZE); - } + + clear_page(to); + __flush_wback_region(to, PAGE_SIZE); } /* @@ -98,41 +92,11 @@ void clear_user_page(void *to, unsigned long address, struct page *pg) */ void copy_user_page(void *to, void *from, unsigned long address, struct page *pg) { - struct page *page = virt_to_page(to); - - - __set_bit(PG_mapped, &page->flags); - if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) { - copy_page(to, from); - __flush_wback_region(to, PAGE_SIZE); - } else { + if (pages_do_alias(address, (unsigned long)to)) __flush_purge_virtual_region(to, (void *)(address & 0xfffff000), PAGE_SIZE); - copy_page(to, from); - __flush_wback_region(to, PAGE_SIZE); - } -} -/* - * For SH7705, we have our own implementation for ptep_get_and_clear - * Copied from pg-sh4.c - */ -pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) -{ - pte_t pte = *ptep; - - pte_clear(mm, addr, ptep); - if (!pte_not_present(pte)) { - unsigned long pfn = pte_pfn(pte); - if (pfn_valid(pfn)) { - struct page *page = pfn_to_page(pfn); - struct address_space *mapping = page_mapping(page); - if (!mapping || !mapping_writably_mapped(mapping)) - __clear_bit(PG_mapped, &page->flags); - } - } - - return pte; + copy_page(to, from); + __flush_wback_region(to, PAGE_SIZE); } - diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c index 2aab3ea934d7..c39b77363352 100644 --- a/arch/sh/mm/tlb-pteaex.c +++ b/arch/sh/mm/tlb-pteaex.c @@ -27,23 +27,6 @@ void update_mmu_cache(struct vm_area_struct * vma, if (vma && current->active_mm != vma->vm_mm) return; -#ifndef CONFIG_CACHE_OFF - { - unsigned long pfn = pte_pfn(pte); - - if (pfn_valid(pfn)) { - struct page *page = pfn_to_page(pfn); - - if (!test_bit(PG_mapped, &page->flags)) { - unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; - __flush_wback_region((void *)P1SEGADDR(phys), - PAGE_SIZE); - __set_bit(PG_mapped, &page->flags); - } - } - } -#endif - local_irq_save(flags); /* Set PTEH register */ diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index 17cb7c3adf22..9b8459c74abd 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c @@ -33,25 +33,25 @@ void update_mmu_cache(struct vm_area_struct * vma, unsigned long flags; unsigned long pteval; unsigned long vpn; + unsigned long pfn = pte_pfn(pte); + struct page *page; /* Ptrace may call this routine. */ if (vma && current->active_mm != vma->vm_mm) return; + page = pfn_to_page(pfn); + if (pfn_valid(pfn) && page_mapping(page)) { #if defined(CONFIG_SH7705_CACHE_32KB) - { - struct page *page = pte_page(pte); - unsigned long pfn = pte_pfn(pte); + int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); + if (dirty) { + unsigned long addr = (unsigned long)page_address(page); - if (pfn_valid(pfn) && !test_bit(PG_mapped, &page->flags)) { - unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; - - __flush_wback_region((void *)P1SEGADDR(phys), - PAGE_SIZE); - __set_bit(PG_mapped, &page->flags); + if (pages_do_alias(addr, address & PAGE_MASK)) + __flush_wback_region((void *)addr, PAGE_SIZE); } - } #endif + } local_irq_save(flags); diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index f0c7b7397fa6..cf50082d2435 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -21,27 +21,26 @@ void update_mmu_cache(struct vm_area_struct * vma, unsigned long flags; unsigned long pteval; unsigned long vpn; + unsigned long pfn = pte_pfn(pte); + struct page *page; /* Ptrace may call this routine. */ if (vma && current->active_mm != vma->vm_mm) return; -#ifndef CONFIG_CACHE_OFF - { - unsigned long pfn = pte_pfn(pte); + page = pfn_to_page(pfn); + if (pfn_valid(pfn) && page_mapping(page)) { +#ifndef CONFIG_SMP + int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); + if (dirty) { - if (pfn_valid(pfn)) { - struct page *page = pfn_to_page(pfn); + unsigned long addr = (unsigned long)page_address(page); - if (!test_bit(PG_mapped, &page->flags)) { - unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; - __flush_wback_region((void *)P1SEGADDR(phys), - PAGE_SIZE); - __set_bit(PG_mapped, &page->flags); - } + if (pages_do_alias(addr, address & PAGE_MASK)) + __flush_wback_region((void *)addr, PAGE_SIZE); } - } #endif + } local_irq_save(flags); -- cgit From dfff0fa65ab15db45acd64b3189787d37ab163cd Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 27 Jul 2009 20:53:22 +0900 Subject: sh: wire up clear_user_highpage() for sh4, convert sh7705. This wires up clear_user_highpage() on SH-4 and subsequently converts the SH7705 32kB cache mode over to using it. Now that the SH-4 implementation handles all of the dcache purging directly in the aliasing case, there is no need to do this in the default clear_page() implementation. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile_32 | 2 +- arch/sh/mm/pg-nommu.c | 7 +--- arch/sh/mm/pg-sh4.c | 29 +++++++------- arch/sh/mm/pg-sh7705.c | 102 ------------------------------------------------- 4 files changed, 16 insertions(+), 124 deletions(-) delete mode 100644 arch/sh/mm/pg-sh7705.c (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32 index 986a1e055834..5c04bbb08d36 100644 --- a/arch/sh/mm/Makefile_32 +++ b/arch/sh/mm/Makefile_32 @@ -31,7 +31,7 @@ tlb-$(CONFIG_CPU_HAS_PTEAEX) := tlb-pteaex.o obj-y += $(tlb-y) ifndef CONFIG_CACHE_OFF obj-$(CONFIG_CPU_SH4) += pg-sh4.o -obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o +obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh4.o endif endif diff --git a/arch/sh/mm/pg-nommu.c b/arch/sh/mm/pg-nommu.c index 91ed4e695ff7..7e33b486b7e9 100644 --- a/arch/sh/mm/pg-nommu.c +++ b/arch/sh/mm/pg-nommu.c @@ -1,7 +1,7 @@ /* * arch/sh/mm/pg-nommu.c * - * clear_page()/copy_page() implementation for MMUless SH. + * copy_page()/__copy_user()/__clear_user() implementations for MMUless SH. * * Copyright (C) 2003 Paul Mundt * @@ -20,11 +20,6 @@ void copy_page(void *to, void *from) memcpy(to, from, PAGE_SIZE); } -void clear_page(void *to) -{ - memset(to, 0, PAGE_SIZE); -} - __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n) { memcpy(to, from, n); diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c index f3c4b2a54fc7..4d93070b8220 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c @@ -2,7 +2,7 @@ * arch/sh/mm/pg-sh4.c * * Copyright (C) 1999, 2000, 2002 Niibe Yutaka - * Copyright (C) 2002 - 2007 Paul Mundt + * Copyright (C) 2002 - 2009 Paul Mundt * * Released under the terms of the GNU GPL v2.0. */ @@ -58,20 +58,6 @@ static inline void kunmap_coherent(struct page *page) preempt_check_resched(); } -/* - * clear_user_page - * @to: P1 address - * @address: U0 address to be mapped - * @page: page (virt_to_page(to)) - */ -void clear_user_page(void *to, unsigned long address, struct page *page) -{ - clear_page(to); - - if (pages_do_alias((unsigned long)to, address & PAGE_MASK)) - __flush_wback_region(to, PAGE_SIZE); -} - void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) @@ -128,3 +114,16 @@ void copy_user_highpage(struct page *to, struct page *from, smp_wmb(); } EXPORT_SYMBOL(copy_user_highpage); + +void clear_user_highpage(struct page *page, unsigned long vaddr) +{ + void *kaddr = kmap_atomic(page, KM_USER0); + + clear_page(kaddr); + + if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) + __flush_wback_region(kaddr, PAGE_SIZE); + + kunmap_atomic(kaddr, KM_USER0); +} +EXPORT_SYMBOL(clear_user_highpage); diff --git a/arch/sh/mm/pg-sh7705.c b/arch/sh/mm/pg-sh7705.c deleted file mode 100644 index 684891b5c8c0..000000000000 --- a/arch/sh/mm/pg-sh7705.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * arch/sh/mm/pg-sh7705.c - * - * Copyright (C) 1999, 2000 Niibe Yutaka - * Copyright (C) 2004 Alex Song - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void __flush_purge_virtual_region(void *p1, void *virt, int size) -{ - unsigned long v; - unsigned long begin, end; - unsigned long p1_begin; - - - begin = L1_CACHE_ALIGN((unsigned long)virt); - end = L1_CACHE_ALIGN((unsigned long)virt + size); - - p1_begin = (unsigned long)p1 & ~(L1_CACHE_BYTES - 1); - - /* do this the slow way as we may not have TLB entries - * for virt yet. */ - for (v = begin; v < end; v += L1_CACHE_BYTES) { - unsigned long p; - unsigned long ways, addr; - - p = __pa(p1_begin); - - ways = current_cpu_data.dcache.ways; - addr = CACHE_OC_ADDRESS_ARRAY; - - do { - unsigned long data; - - addr |= (v & current_cpu_data.dcache.entry_mask); - - data = ctrl_inl(addr); - if ((data & CACHE_PHYSADDR_MASK) == - (p & CACHE_PHYSADDR_MASK)) { - data &= ~(SH_CACHE_UPDATED|SH_CACHE_VALID); - ctrl_outl(data, addr); - } - - addr += current_cpu_data.dcache.way_incr; - } while (--ways); - - p1_begin += L1_CACHE_BYTES; - } -} - -/* - * clear_user_page - * @to: P1 address - * @address: U0 address to be mapped - */ -void clear_user_page(void *to, unsigned long address, struct page *pg) -{ - if (pages_do_alias(address, (unsigned long)to)) - __flush_purge_virtual_region(to, - (void *)(address & 0xfffff000), - PAGE_SIZE); - - clear_page(to); - __flush_wback_region(to, PAGE_SIZE); -} - -/* - * copy_user_page - * @to: P1 address - * @from: P1 address - * @address: U0 address to be mapped - */ -void copy_user_page(void *to, void *from, unsigned long address, struct page *pg) -{ - if (pages_do_alias(address, (unsigned long)to)) - __flush_purge_virtual_region(to, - (void *)(address & 0xfffff000), - PAGE_SIZE); - - copy_page(to, from); - __flush_wback_region(to, PAGE_SIZE); -} -- cgit From 0dfae7d5a21901b28ec0452d71be64adf5ea323e Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 27 Jul 2009 21:30:17 +0900 Subject: sh: Use the now generic SH-4 clear/copy page ops for all MMU platforms. Now that the SH-4 page clear/copy ops are generic, they can be used for all platforms with CONFIG_MMU=y. SH-5 remains the odd one out, but it too will gradually be converted over to using this interface. SH-3 platforms which do not contain aliases will see no impact from this change, while aliasing SH-3 platforms will get the same interface as SH-4. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile_32 | 6 +-- arch/sh/mm/cache-sh5.c | 17 +++++++ arch/sh/mm/pg-mmu.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ arch/sh/mm/pg-sh4.c | 129 ---------------------------------------------- 4 files changed, 154 insertions(+), 134 deletions(-) create mode 100644 arch/sh/mm/pg-mmu.c delete mode 100644 arch/sh/mm/pg-sh4.c (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32 index 5c04bbb08d36..62e280734dcb 100644 --- a/arch/sh/mm/Makefile_32 +++ b/arch/sh/mm/Makefile_32 @@ -15,7 +15,7 @@ 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 +mmu-$(CONFIG_MMU) := fault_32.o tlbflush_32.o ioremap_32.o pg-mmu.o obj-y += $(mmu-y) obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o @@ -29,10 +29,6 @@ tlb-$(CONFIG_CPU_SH3) := tlb-sh3.o tlb-$(CONFIG_CPU_SH4) := tlb-sh4.o tlb-$(CONFIG_CPU_HAS_PTEAEX) := tlb-pteaex.o obj-y += $(tlb-y) -ifndef CONFIG_CACHE_OFF -obj-$(CONFIG_CPU_SH4) += pg-sh4.o -obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh4.o -endif endif obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 86762092508c..3e2d7321b636 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -831,4 +831,21 @@ void clear_user_page(void *to, unsigned long address, struct page *page) else sh64_clear_user_page_coloured(to, address); } + +void copy_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + flush_cache_page(vma, vaddr, page_to_pfn(page)); + memcpy(dst, src, len); + flush_icache_user_range(vma, page, vaddr, len); +} + +void copy_from_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + flush_cache_page(vma, vaddr, page_to_pfn(page)); + memcpy(dst, src, len); +} #endif diff --git a/arch/sh/mm/pg-mmu.c b/arch/sh/mm/pg-mmu.c new file mode 100644 index 000000000000..356d2cdcb209 --- /dev/null +++ b/arch/sh/mm/pg-mmu.c @@ -0,0 +1,136 @@ +/* + * arch/sh/mm/pg-mmu.c + * + * Copyright (C) 1999, 2000, 2002 Niibe Yutaka + * Copyright (C) 2002 - 2009 Paul Mundt + * + * Released under the terms of the GNU GPL v2.0. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)) + +static pte_t *kmap_coherent_pte; + +void __init kmap_coherent_init(void) +{ +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) + unsigned long vaddr; + + /* cache the first coherent kmap pte */ + vaddr = __fix_to_virt(FIX_CMAP_BEGIN); + kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); +#endif +} + +static inline void *kmap_coherent(struct page *page, unsigned long addr) +{ + enum fixed_addresses idx; + unsigned long vaddr, flags; + pte_t pte; + + inc_preempt_count(); + + idx = (addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT; + vaddr = __fix_to_virt(FIX_CMAP_END - idx); + pte = mk_pte(page, PAGE_KERNEL); + + local_irq_save(flags); + flush_tlb_one(get_asid(), vaddr); + local_irq_restore(flags); + + update_mmu_cache(NULL, vaddr, pte); + + set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte); + + return (void *)vaddr; +} + +static inline void kunmap_coherent(struct page *page) +{ + dec_preempt_count(); + preempt_check_resched(); +} + +void copy_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && + !test_bit(PG_dcache_dirty, &page->flags)) { + void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(vto, src, len); + kunmap_coherent(vto); + } else { + memcpy(dst, src, len); + if (boot_cpu_data.dcache.n_aliases) + set_bit(PG_dcache_dirty, &page->flags); + } + + if (vma->vm_flags & VM_EXEC) + flush_cache_page(vma, vaddr, page_to_pfn(page)); +} + +void copy_from_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && + !test_bit(PG_dcache_dirty, &page->flags)) { + void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(dst, vfrom, len); + kunmap_coherent(vfrom); + } else { + memcpy(dst, src, len); + if (boot_cpu_data.dcache.n_aliases) + set_bit(PG_dcache_dirty, &page->flags); + } +} + +void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma) +{ + void *vfrom, *vto; + + vto = kmap_atomic(to, KM_USER1); + + if (boot_cpu_data.dcache.n_aliases && page_mapped(from) && + !test_bit(PG_dcache_dirty, &from->flags)) { + vfrom = kmap_coherent(from, vaddr); + copy_page(vto, vfrom); + kunmap_coherent(vfrom); + } else { + vfrom = kmap_atomic(from, KM_USER0); + copy_page(vto, vfrom); + kunmap_atomic(vfrom, KM_USER0); + } + + if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) + __flush_wback_region(vto, PAGE_SIZE); + + kunmap_atomic(vto, KM_USER1); + /* Make sure this page is cleared on other CPU's too before using it */ + smp_wmb(); +} +EXPORT_SYMBOL(copy_user_highpage); + +void clear_user_highpage(struct page *page, unsigned long vaddr) +{ + void *kaddr = kmap_atomic(page, KM_USER0); + + clear_page(kaddr); + + if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) + __flush_wback_region(kaddr, PAGE_SIZE); + + kunmap_atomic(kaddr, KM_USER0); +} +EXPORT_SYMBOL(clear_user_highpage); diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c deleted file mode 100644 index 4d93070b8220..000000000000 --- a/arch/sh/mm/pg-sh4.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * arch/sh/mm/pg-sh4.c - * - * Copyright (C) 1999, 2000, 2002 Niibe Yutaka - * Copyright (C) 2002 - 2009 Paul Mundt - * - * Released under the terms of the GNU GPL v2.0. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define kmap_get_fixmap_pte(vaddr) \ - pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)) - -static pte_t *kmap_coherent_pte; - -void __init kmap_coherent_init(void) -{ - unsigned long vaddr; - - /* cache the first coherent kmap pte */ - vaddr = __fix_to_virt(FIX_CMAP_BEGIN); - kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); -} - -static inline void *kmap_coherent(struct page *page, unsigned long addr) -{ - enum fixed_addresses idx; - unsigned long vaddr, flags; - pte_t pte; - - inc_preempt_count(); - - idx = (addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT; - vaddr = __fix_to_virt(FIX_CMAP_END - idx); - pte = mk_pte(page, PAGE_KERNEL); - - local_irq_save(flags); - flush_tlb_one(get_asid(), vaddr); - local_irq_restore(flags); - - update_mmu_cache(NULL, vaddr, pte); - - set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte); - - return (void *)vaddr; -} - -static inline void kunmap_coherent(struct page *page) -{ - dec_preempt_count(); - preempt_check_resched(); -} - -void copy_to_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, const void *src, - unsigned long len) -{ - if (page_mapped(page) && !test_bit(PG_dcache_dirty, &page->flags)) { - void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); - memcpy(vto, src, len); - kunmap_coherent(vto); - } else { - memcpy(dst, src, len); - set_bit(PG_dcache_dirty, &page->flags); - } - - if (vma->vm_flags & VM_EXEC) - flush_cache_page(vma, vaddr, page_to_pfn(page)); -} - -void copy_from_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, const void *src, - unsigned long len) -{ - if (page_mapped(page) && !test_bit(PG_dcache_dirty, &page->flags)) { - void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); - memcpy(dst, vfrom, len); - kunmap_coherent(vfrom); - } else { - memcpy(dst, src, len); - set_bit(PG_dcache_dirty, &page->flags); - } -} - -void copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr, struct vm_area_struct *vma) -{ - void *vfrom, *vto; - - vto = kmap_atomic(to, KM_USER1); - - if (page_mapped(from) && !test_bit(PG_dcache_dirty, &from->flags)) { - vfrom = kmap_coherent(from, vaddr); - copy_page(vto, vfrom); - kunmap_coherent(vfrom); - } else { - vfrom = kmap_atomic(from, KM_USER0); - copy_page(vto, vfrom); - kunmap_atomic(vfrom, KM_USER0); - } - - if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) - __flush_wback_region(vto, PAGE_SIZE); - - kunmap_atomic(vto, KM_USER1); - /* Make sure this page is cleared on other CPU's too before using it */ - smp_wmb(); -} -EXPORT_SYMBOL(copy_user_highpage); - -void clear_user_highpage(struct page *page, unsigned long vaddr) -{ - void *kaddr = kmap_atomic(page, KM_USER0); - - clear_page(kaddr); - - if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) - __flush_wback_region(kaddr, PAGE_SIZE); - - kunmap_atomic(kaddr, KM_USER0); -} -EXPORT_SYMBOL(clear_user_highpage); -- cgit From 9cef7492696a416663b4edb953a4eade8517ebeb Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 29 Jul 2009 00:12:17 +0900 Subject: sh: update_mmu_cache() consolidation. This splits out a separate __update_cache()/__update_tlb() for update_mmu_cache() to wrap in to. This lets us share the common __update_cache() bits while keeping special __update_tlb() handling broken out. Signed-off-by: Paul Mundt --- arch/sh/mm/pg-mmu.c | 21 +++++++++++++++++++++ arch/sh/mm/tlb-nommu.c | 9 ++++++--- arch/sh/mm/tlb-pteaex.c | 13 ++++++------- arch/sh/mm/tlb-sh3.c | 29 ++++++----------------------- arch/sh/mm/tlb-sh4.c | 29 ++++++----------------------- arch/sh/mm/tlbflush_64.c | 25 +++++++++---------------- 6 files changed, 54 insertions(+), 72 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/pg-mmu.c b/arch/sh/mm/pg-mmu.c index 356d2cdcb209..8602f68af4c8 100644 --- a/arch/sh/mm/pg-mmu.c +++ b/arch/sh/mm/pg-mmu.c @@ -134,3 +134,24 @@ void clear_user_highpage(struct page *page, unsigned long vaddr) kunmap_atomic(kaddr, KM_USER0); } EXPORT_SYMBOL(clear_user_highpage); + +void __update_cache(struct vm_area_struct *vma, + unsigned long address, pte_t pte) +{ + struct page *page; + unsigned long pfn = pte_pfn(pte); + + if (!boot_cpu_data.dcache.n_aliases) + return; + + page = pfn_to_page(pfn); + if (pfn_valid(pfn) && page_mapping(page)) { + int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); + if (dirty) { + unsigned long addr = (unsigned long)page_address(page); + + if (pages_do_alias(addr, address & PAGE_MASK)) + __flush_wback_region((void *)addr, PAGE_SIZE); + } + } +} diff --git a/arch/sh/mm/tlb-nommu.c b/arch/sh/mm/tlb-nommu.c index 71c742b5aee3..0ef5429943df 100644 --- a/arch/sh/mm/tlb-nommu.c +++ b/arch/sh/mm/tlb-nommu.c @@ -46,10 +46,13 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) BUG(); } -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) +void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) +{ +} + +void __update_cache(struct vm_area_struct *vma, + unsigned long address, pte_t pte) { - BUG(); } void __init page_table_range_init(unsigned long start, unsigned long end, diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c index c39b77363352..9aabd313cede 100644 --- a/arch/sh/mm/tlb-pteaex.c +++ b/arch/sh/mm/tlb-pteaex.c @@ -16,15 +16,14 @@ #include #include -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) +void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) { - unsigned long flags; - unsigned long pteval; - unsigned long vpn; + unsigned long flags, pteval, vpn; - /* Ptrace may call this routine. */ - if (vma && current->active_mm != vma->vm_mm) + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) return; local_irq_save(flags); diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index 9b8459c74abd..425f1f23cf93 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c @@ -27,32 +27,16 @@ #include #include -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) +void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) { - unsigned long flags; - unsigned long pteval; - unsigned long vpn; - unsigned long pfn = pte_pfn(pte); - struct page *page; + unsigned long flags, pteval, vpn; - /* Ptrace may call this routine. */ - if (vma && current->active_mm != vma->vm_mm) + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) return; - page = pfn_to_page(pfn); - if (pfn_valid(pfn) && page_mapping(page)) { -#if defined(CONFIG_SH7705_CACHE_32KB) - int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); - if (dirty) { - unsigned long addr = (unsigned long)page_address(page); - - if (pages_do_alias(addr, address & PAGE_MASK)) - __flush_wback_region((void *)addr, PAGE_SIZE); - } -#endif - } - local_irq_save(flags); /* Set PTEH register */ @@ -93,4 +77,3 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) for (i = 0; i < ways; i++) ctrl_outl(data, addr + (i << 8)); } - diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index cf50082d2435..81199f1e5945 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -15,33 +15,16 @@ #include #include -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) +void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) { - unsigned long flags; - unsigned long pteval; - unsigned long vpn; - unsigned long pfn = pte_pfn(pte); - struct page *page; + unsigned long flags, pteval, vpn; - /* Ptrace may call this routine. */ - if (vma && current->active_mm != vma->vm_mm) + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) return; - page = pfn_to_page(pfn); - if (pfn_valid(pfn) && page_mapping(page)) { -#ifndef CONFIG_SMP - int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); - if (dirty) { - - unsigned long addr = (unsigned long)page_address(page); - - if (pages_do_alias(addr, address & PAGE_MASK)) - __flush_wback_region((void *)addr, PAGE_SIZE); - } -#endif - } - local_irq_save(flags); /* Set PTEH register */ diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c index 3ce40ea34824..f2e44e9ffb75 100644 --- a/arch/sh/mm/tlbflush_64.c +++ b/arch/sh/mm/tlbflush_64.c @@ -329,22 +329,6 @@ do_sigbus: goto no_context; } -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - /* - * This appears to get called once for every pte entry that gets - * established => I don't think it's efficient to try refilling the - * TLBs with the pages - some may not get accessed even. Also, for - * executable pages, it is impossible to determine reliably here which - * TLB they should be mapped into (or both even). - * - * So, just do nothing here and handle faults on demand. In the - * TLBMISS handling case, the refill is now done anyway after the pte - * has been fixed up, so that deals with most useful cases. - */ -} - void local_flush_tlb_one(unsigned long asid, unsigned long page) { unsigned long long match, pteh=0, lpage; @@ -482,3 +466,12 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) /* FIXME: Optimize this later.. */ flush_tlb_all(); } + +void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) +{ +} + +void __update_cache(struct vm_area_struct *vma, + unsigned long address, pte_t pte) +{ +} -- cgit From 3ed6e129390fb872c3b7e05a232e5d380fbdfb48 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 29 Jul 2009 22:06:58 +0900 Subject: sh: Handle a NULL vma in __update_tlb() for the fast-path. The TLB miss fast-path presently calls in to update_mmu_cache() to set up the entry, and does so with a NULL vma. Check for vma validity in the __update_tlb() ptrace checks. Signed-off-by: Paul Mundt --- arch/sh/mm/tlb-pteaex.c | 2 +- arch/sh/mm/tlb-sh3.c | 2 +- arch/sh/mm/tlb-sh4.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c index 9aabd313cede..409b7c2b4b9d 100644 --- a/arch/sh/mm/tlb-pteaex.c +++ b/arch/sh/mm/tlb-pteaex.c @@ -23,7 +23,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) /* * Handle debugger faulting in for debugee. */ - if (current->active_mm != vma->vm_mm) + if (vma && current->active_mm != vma->vm_mm) return; local_irq_save(flags); diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index 425f1f23cf93..ace8e6d2f59d 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c @@ -34,7 +34,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) /* * Handle debugger faulting in for debugee. */ - if (current->active_mm != vma->vm_mm) + if (vma && current->active_mm != vma->vm_mm) return; local_irq_save(flags); diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index 81199f1e5945..7d3c63e707a5 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -22,7 +22,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) /* * Handle debugger faulting in for debugee. */ - if (current->active_mm != vma->vm_mm) + if (vma && current->active_mm != vma->vm_mm) return; local_irq_save(flags); -- cgit From 700487c158163f14e6ff10de770b565c1c993c69 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 4 Aug 2009 15:57:44 +0900 Subject: sh: Add a PG_dcache_dirty sanity check in kmap_coherent(). This plugs in a BUG_ON() in kmap_coherent() for PG_dcache_dirty pages to catch when things go horribly wrong. Copied from the MIPS implementation. Signed-off-by: Paul Mundt --- arch/sh/mm/pg-mmu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/pg-mmu.c b/arch/sh/mm/pg-mmu.c index 8602f68af4c8..32351206edd3 100644 --- a/arch/sh/mm/pg-mmu.c +++ b/arch/sh/mm/pg-mmu.c @@ -37,6 +37,8 @@ static inline void *kmap_coherent(struct page *page, unsigned long addr) unsigned long vaddr, flags; pte_t pte; + BUG_ON(test_bit(PG_dcache_dirty, &page->flags)); + inc_preempt_count(); idx = (addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT; -- cgit From 222db3e5f21fca563f5f692e000afcc01cb4395c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 4 Aug 2009 15:59:15 +0900 Subject: sh: Bring kmap_coherent() out-of-line. kmap_coherent() has gotten too big to leave as an inline, so we bring it out-of-line. Signed-off-by: Paul Mundt --- arch/sh/mm/pg-mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/pg-mmu.c b/arch/sh/mm/pg-mmu.c index 32351206edd3..e5c5122f4d62 100644 --- a/arch/sh/mm/pg-mmu.c +++ b/arch/sh/mm/pg-mmu.c @@ -31,7 +31,7 @@ void __init kmap_coherent_init(void) #endif } -static inline void *kmap_coherent(struct page *page, unsigned long addr) +static void *kmap_coherent(struct page *page, unsigned long addr) { enum fixed_addresses idx; unsigned long vaddr, flags; -- cgit From b5eb10ae901fa797c19accb684825f0e36ecbe0f Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 4 Aug 2009 16:00:36 +0900 Subject: sh: Drop unused arguments for kunmap_coherent(). kunmap_coherent() doesn't do anything with its arguments, so just kill them off. Signed-off-by: Paul Mundt --- arch/sh/mm/pg-mmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/pg-mmu.c b/arch/sh/mm/pg-mmu.c index e5c5122f4d62..a9ede7bae520 100644 --- a/arch/sh/mm/pg-mmu.c +++ b/arch/sh/mm/pg-mmu.c @@ -56,7 +56,7 @@ static void *kmap_coherent(struct page *page, unsigned long addr) return (void *)vaddr; } -static inline void kunmap_coherent(struct page *page) +static inline void kunmap_coherent(void) { dec_preempt_count(); preempt_check_resched(); @@ -70,7 +70,7 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page, !test_bit(PG_dcache_dirty, &page->flags)) { void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(vto, src, len); - kunmap_coherent(vto); + kunmap_coherent(); } else { memcpy(dst, src, len); if (boot_cpu_data.dcache.n_aliases) @@ -89,7 +89,7 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page, !test_bit(PG_dcache_dirty, &page->flags)) { void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(dst, vfrom, len); - kunmap_coherent(vfrom); + kunmap_coherent(); } else { memcpy(dst, src, len); if (boot_cpu_data.dcache.n_aliases) @@ -108,7 +108,7 @@ void copy_user_highpage(struct page *to, struct page *from, !test_bit(PG_dcache_dirty, &from->flags)) { vfrom = kmap_coherent(from, vaddr); copy_page(vto, vfrom); - kunmap_coherent(vfrom); + kunmap_coherent(); } else { vfrom = kmap_atomic(from, KM_USER0); copy_page(vto, vfrom); -- cgit From c0fe478dbb14fd32e71d1383dbe302b54ce94134 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 4 Aug 2009 16:02:43 +0900 Subject: sh: Provide __flush_anon_page(). This provides a __flush_anon_page() that handles both the aliasing and non-aliasing cases. This fixes up some crashes with heavy get_user_pages() users. Signed-off-by: Paul Mundt --- arch/sh/mm/pg-mmu.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/pg-mmu.c b/arch/sh/mm/pg-mmu.c index a9ede7bae520..027c4d83fb8e 100644 --- a/arch/sh/mm/pg-mmu.c +++ b/arch/sh/mm/pg-mmu.c @@ -157,3 +157,20 @@ void __update_cache(struct vm_area_struct *vma, } } } + +void __flush_anon_page(struct page *page, unsigned long vmaddr) +{ + unsigned long addr = (unsigned long) page_address(page); + + if (pages_do_alias(addr, vmaddr)) { + if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && + !test_bit(PG_dcache_dirty, &page->flags)) { + void *kaddr; + + kaddr = kmap_coherent(page, vmaddr); + __flush_wback_region((void *)kaddr, PAGE_SIZE); + kunmap_coherent(); + } else + __flush_wback_region((void *)addr, PAGE_SIZE); + } +} -- cgit From c7914834ef3b8a396b7e82ea34ac07cdcfe6f868 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 4 Aug 2009 17:14:39 +0900 Subject: sh: Tidy up NEFF-based sign extension for SH-5. This consolidates all of the NEFF-based sign extension for SH-5. In the future the other SH code will need to make use of this as well, so make it generic in preparation for more 32/64 consolidation. Signed-off-by: Paul Mundt --- arch/sh/mm/fault_64.c | 11 +---------- arch/sh/mm/tlb-sh5.c | 21 +++++---------------- arch/sh/mm/tlbflush_64.c | 2 +- 3 files changed, 7 insertions(+), 27 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/fault_64.c b/arch/sh/mm/fault_64.c index bd63b961b2a9..2b356cec2489 100644 --- a/arch/sh/mm/fault_64.c +++ b/arch/sh/mm/fault_64.c @@ -56,16 +56,7 @@ inline void __do_tlb_refill(unsigned long address, /* * Set PTEH register */ - pteh = address & MMU_VPN_MASK; - - /* Sign extend based on neff. */ -#if (NEFF == 32) - /* Faster sign extension */ - pteh = (unsigned long long)(signed long long)(signed long)pteh; -#else - /* General case */ - pteh = (pteh & NEFF_SIGN) ? (pteh | NEFF_MASK) : pteh; -#endif + pteh = neff_sign_extend(address & MMU_VPN_MASK); /* Set the ASID. */ pteh |= get_asid() << PTEH_ASID_SHIFT; diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c index dae131243bcc..fdb64e41ec50 100644 --- a/arch/sh/mm/tlb-sh5.c +++ b/arch/sh/mm/tlb-sh5.c @@ -117,26 +117,15 @@ int sh64_put_wired_dtlb_entry(unsigned long long entry) * Load up a virtual<->physical translation for @eaddr<->@paddr in the * pre-allocated TLB slot @config_addr (see sh64_get_wired_dtlb_entry). */ -inline void sh64_setup_tlb_slot(unsigned long long config_addr, - unsigned long eaddr, - unsigned long asid, - unsigned long paddr) +void sh64_setup_tlb_slot(unsigned long long config_addr, unsigned long eaddr, + unsigned long asid, unsigned long paddr) { unsigned long long pteh, ptel; - /* Sign extension */ -#if (NEFF == 32) - pteh = (unsigned long long)(signed long long)(signed long) eaddr; -#else -#error "Can't sign extend more than 32 bits yet" -#endif + pteh = neff_sign_extend(eaddr); pteh &= PAGE_MASK; pteh |= (asid << PTEH_ASID_SHIFT) | PTEH_VALID; -#if (NEFF == 32) - ptel = (unsigned long long)(signed long long)(signed long) paddr; -#else -#error "Can't sign extend more than 32 bits yet" -#endif + ptel = neff_sign_extend(paddr); ptel &= PAGE_MASK; ptel |= (_PAGE_CACHABLE | _PAGE_READ | _PAGE_WRITE); @@ -152,5 +141,5 @@ inline void sh64_setup_tlb_slot(unsigned long long config_addr, * * Teardown any existing mapping in the TLB slot @config_addr. */ -inline void sh64_teardown_tlb_slot(unsigned long long config_addr) +void sh64_teardown_tlb_slot(unsigned long long config_addr) __attribute__ ((alias("__flush_tlb_slot"))); diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c index f2e44e9ffb75..fa5a95a062d0 100644 --- a/arch/sh/mm/tlbflush_64.c +++ b/arch/sh/mm/tlbflush_64.c @@ -337,7 +337,7 @@ void local_flush_tlb_one(unsigned long asid, unsigned long page) /* * Sign-extend based on neff. */ - lpage = (page & NEFF_SIGN) ? (page | NEFF_MASK) : page; + lpage = neff_sign_extend(page); match = (asid << PTEH_ASID_SHIFT) | PTEH_VALID; match |= lpage; -- cgit From 817425275271f2514f0dc6952182aa057ce80973 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 4 Aug 2009 18:06:01 +0900 Subject: sh: Split out SH-4 __flush_xxx_region() ops. This splits out the SH-4 __flush_xxx_region() functions and defines them as weak symbols. This allows us to provide optimized versions without having to ifdef cache-sh4.c to death. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile_32 | 2 +- arch/sh/mm/cache-sh4.c | 60 ----------------------------------------------- arch/sh/mm/flush-sh4.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 61 deletions(-) create mode 100644 arch/sh/mm/flush-sh4.c (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32 index 62e280734dcb..17b02522214f 100644 --- a/arch/sh/mm/Makefile_32 +++ b/arch/sh/mm/Makefile_32 @@ -8,7 +8,7 @@ ifndef CONFIG_CACHE_OFF 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_CPU_SH4) := cache-sh4.o flush-sh4.o cache-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o endif diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index c3a09b27f8d5..dfc1d0379479 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -118,66 +118,6 @@ void __init p3_cache_init(void) emit_cache_params(); } -/* - * Write back the dirty D-caches, but not invalidate them. - * - * START: Virtual Address (U0, P1, or P3) - * SIZE: Size of the region. - */ -void __flush_wback_region(void *start, int size) -{ - 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) { - asm volatile("ocbwb %0" - : /* no output */ - : "m" (__m(v))); - } -} - -/* - * Write back the dirty D-caches and invalidate them. - * - * START: Virtual Address (U0, P1, or P3) - * SIZE: Size of the region. - */ -void __flush_purge_region(void *start, int size) -{ - 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) { - asm volatile("ocbp %0" - : /* no output */ - : "m" (__m(v))); - } -} - -/* - * No write back please - */ -void __flush_invalidate_region(void *start, int size) -{ - 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) { - asm volatile("ocbi %0" - : /* no output */ - : "m" (__m(v))); - } -} - /* * Write back the range of D-cache, and purge the I-cache. * diff --git a/arch/sh/mm/flush-sh4.c b/arch/sh/mm/flush-sh4.c new file mode 100644 index 000000000000..e6d918f6ec0b --- /dev/null +++ b/arch/sh/mm/flush-sh4.c @@ -0,0 +1,63 @@ +#include +#include +#include + +/* + * Write back the dirty D-caches, but not invalidate them. + * + * START: Virtual Address (U0, P1, or P3) + * SIZE: Size of the region. + */ +void __weak __flush_wback_region(void *start, int size) +{ + 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) { + asm volatile("ocbwb %0" + : /* no output */ + : "m" (__m(v))); + } +} + +/* + * Write back the dirty D-caches and invalidate them. + * + * START: Virtual Address (U0, P1, or P3) + * SIZE: Size of the region. + */ +void __weak __flush_purge_region(void *start, int size) +{ + 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) { + asm volatile("ocbp %0" + : /* no output */ + : "m" (__m(v))); + } +} + +/* + * No write back please + */ +void __weak __flush_invalidate_region(void *start, int size) +{ + 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) { + asm volatile("ocbi %0" + : /* no output */ + : "m" (__m(v))); + } +} -- cgit From 0837f52463583f76670ab2350e0f1541cb0351f5 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 4 Aug 2009 18:09:54 +0900 Subject: sh: Partially unroll the SH-4 __flush_xxx_region() flushers. This does a bit of unrolling for the SH-4 region flushers. Based on an earlier patch by SUGIOKA Toshinobu. Signed-off-by: Paul Mundt --- arch/sh/mm/flush-sh4.c | 104 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 21 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/flush-sh4.c b/arch/sh/mm/flush-sh4.c index e6d918f6ec0b..edefc53891a8 100644 --- a/arch/sh/mm/flush-sh4.c +++ b/arch/sh/mm/flush-sh4.c @@ -10,16 +10,37 @@ */ void __weak __flush_wback_region(void *start, int size) { - unsigned long v; - unsigned long begin, end; + unsigned long v, cnt, end; - begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); + v = (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) { - asm volatile("ocbwb %0" - : /* no output */ - : "m" (__m(v))); + cnt = (end - v) / L1_CACHE_BYTES; + + while (cnt >= 8) { + asm volatile("ocbwb @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbwb @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbwb @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbwb @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbwb @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbwb @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbwb @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbwb @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + cnt -= 8; + } + + while (cnt) { + asm volatile("ocbwb @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + cnt--; } } @@ -31,16 +52,36 @@ void __weak __flush_wback_region(void *start, int size) */ void __weak __flush_purge_region(void *start, int size) { - unsigned long v; - unsigned long begin, end; + unsigned long v, cnt, end; - begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); + v = (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) { - asm volatile("ocbp %0" - : /* no output */ - : "m" (__m(v))); + cnt = (end - v) / L1_CACHE_BYTES; + + while (cnt >= 8) { + asm volatile("ocbp @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbp @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbp @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbp @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbp @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbp @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbp @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbp @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + cnt -= 8; + } + while (cnt) { + asm volatile("ocbp @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + cnt--; } } @@ -49,15 +90,36 @@ void __weak __flush_purge_region(void *start, int size) */ void __weak __flush_invalidate_region(void *start, int size) { - unsigned long v; - unsigned long begin, end; + unsigned long v, cnt, end; - begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); + v = (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) { - asm volatile("ocbi %0" - : /* no output */ - : "m" (__m(v))); + cnt = (end - v) / L1_CACHE_BYTES; + + while (cnt >= 8) { + asm volatile("ocbi @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbi @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbi @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbi @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbi @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbi @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbi @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + asm volatile("ocbi @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + cnt -= 8; + } + + while (cnt) { + asm volatile("ocbi @%0" : : "r" (v)); + v += L1_CACHE_BYTES; + cnt--; } } -- cgit From 922b0dc59bb43f7ff3bb8b9558ffeb3ad6af528e Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 9 Aug 2009 19:53:59 +0000 Subject: sh: use printk_once Signed-off-by: Marcin Slusarz Cc: linux-sh@vger.kernel.org Signed-off-by: Paul Mundt --- arch/sh/mm/ioremap_64.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/ioremap_64.c b/arch/sh/mm/ioremap_64.c index 828c8597219d..b16843d02b76 100644 --- a/arch/sh/mm/ioremap_64.c +++ b/arch/sh/mm/ioremap_64.c @@ -94,7 +94,6 @@ static struct resource *shmedia_find_resource(struct resource *root, static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size, const char *name, unsigned long flags) { - static int printed_full; struct xresource *xres; struct resource *res; char *tack; @@ -108,11 +107,8 @@ static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size, tack = xres->xname; res = &xres->xres; } else { - if (!printed_full) { - printk(KERN_NOTICE "%s: done with statics, " + printk_once(KERN_NOTICE "%s: done with statics, " "switching to kmalloc\n", __func__); - printed_full = 1; - } tlen = strlen(name); tack = kmalloc(sizeof(struct resource) + tlen + 1, GFP_KERNEL); if (!tack) -- cgit From 43bc61d86f8ea6edef2e02d1dc47617883fa9a9c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 01:57:36 +0900 Subject: sh: Add register alignment helpers for shared flushers. This plugs in some register alignment helpers for the shared flushers, allowing them to also be used on SH-5. The main rationale here is that in the SH-5 case we have a variable ABI, where the pointer size may not equal the register width. This register extension is taken care of by the SH-5 code already today, and is otherwise unused on the SH-4 code. This combines the two and allows us to kill off the SH-5 implementation. Signed-off-by: Paul Mundt --- arch/sh/mm/flush-sh4.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/flush-sh4.c b/arch/sh/mm/flush-sh4.c index edefc53891a8..1b6b6a12a99b 100644 --- a/arch/sh/mm/flush-sh4.c +++ b/arch/sh/mm/flush-sh4.c @@ -10,10 +10,11 @@ */ void __weak __flush_wback_region(void *start, int size) { - unsigned long v, cnt, end; + reg_size_t aligned_start, v, cnt, end; - v = (unsigned long)start & ~(L1_CACHE_BYTES-1); - end = ((unsigned long)start + size + L1_CACHE_BYTES-1) + aligned_start = register_align(start); + v = aligned_start & ~(L1_CACHE_BYTES-1); + end = (aligned_start + size + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); cnt = (end - v) / L1_CACHE_BYTES; @@ -52,10 +53,11 @@ void __weak __flush_wback_region(void *start, int size) */ void __weak __flush_purge_region(void *start, int size) { - unsigned long v, cnt, end; + reg_size_t aligned_start, v, cnt, end; - v = (unsigned long)start & ~(L1_CACHE_BYTES-1); - end = ((unsigned long)start + size + L1_CACHE_BYTES-1) + aligned_start = register_align(start); + v = aligned_start & ~(L1_CACHE_BYTES-1); + end = (aligned_start + size + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); cnt = (end - v) / L1_CACHE_BYTES; @@ -90,10 +92,11 @@ void __weak __flush_purge_region(void *start, int size) */ void __weak __flush_invalidate_region(void *start, int size) { - unsigned long v, cnt, end; + reg_size_t aligned_start, v, cnt, end; - v = (unsigned long)start & ~(L1_CACHE_BYTES-1); - end = ((unsigned long)start + size + L1_CACHE_BYTES-1) + aligned_start = register_align(start); + v = aligned_start & ~(L1_CACHE_BYTES-1); + end = (aligned_start + size + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); cnt = (end - v) / L1_CACHE_BYTES; -- cgit From 795687265d1b6f666d02ff56f6c1679a8db160a9 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 02:00:54 +0900 Subject: sh64: Wire up the shared __flush_xxx_region() flushers. Now with all of the prep work out of the way, kill off the SH-5 variants and use the SH-4 version directly. This also takes advantage of the unrolling that was previously done for the new version. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile_64 | 2 +- arch/sh/mm/cache-sh5.c | 48 ------------------------------------------------ 2 files changed, 1 insertion(+), 49 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile_64 b/arch/sh/mm/Makefile_64 index 2863ffb7006d..66c39106d0a8 100644 --- a/arch/sh/mm/Makefile_64 +++ b/arch/sh/mm/Makefile_64 @@ -9,7 +9,7 @@ mmu-$(CONFIG_MMU) := fault_64.o ioremap_64.o tlbflush_64.o tlb-sh5.o \ extable_64.o ifndef CONFIG_CACHE_OFF -obj-y += cache-sh5.o +obj-y += cache-sh5.o flush-sh4.o endif obj-y += $(mmu-y) diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 3e2d7321b636..698113fce814 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -539,54 +539,6 @@ static void sh64_dcache_purge_user_range(struct mm_struct *mm, sh64_dcache_purge_user_pages(mm, start, end); } } - -/* - * Purge the range of addresses from the D-cache. - * - * The addresses lie in the superpage mapping. There's no harm if we - * overpurge at either end - just a small performance loss. - */ -void __flush_purge_region(void *start, int size) -{ - unsigned long long ullend, addr, aligned_start; - - aligned_start = (unsigned long long)(signed long long)(signed long) start; - addr = L1_CACHE_ALIGN(aligned_start); - ullend = (unsigned long long) (signed long long) (signed long) start + size; - - while (addr <= ullend) { - __asm__ __volatile__ ("ocbp %0, 0" : : "r" (addr)); - addr += L1_CACHE_BYTES; - } -} - -void __flush_wback_region(void *start, int size) -{ - unsigned long long ullend, addr, aligned_start; - - aligned_start = (unsigned long long)(signed long long)(signed long) start; - addr = L1_CACHE_ALIGN(aligned_start); - ullend = (unsigned long long) (signed long long) (signed long) start + size; - - while (addr < ullend) { - __asm__ __volatile__ ("ocbwb %0, 0" : : "r" (addr)); - addr += L1_CACHE_BYTES; - } -} - -void __flush_invalidate_region(void *start, int size) -{ - unsigned long long ullend, addr, aligned_start; - - aligned_start = (unsigned long long)(signed long long)(signed long) start; - addr = L1_CACHE_ALIGN(aligned_start); - ullend = (unsigned long long) (signed long long) (signed long) start + size; - - while (addr < ullend) { - __asm__ __volatile__ ("ocbi %0, 0" : : "r" (addr)); - addr += L1_CACHE_BYTES; - } -} #endif /* !CONFIG_DCACHE_DISABLED */ /* -- cgit From e7b8b7f16edc9b363573eadf2ab2683473626071 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 02:21:16 +0900 Subject: sh: NO_CONTEXT ASID optimizations for SH-4 cache flush. This optimizes for the cases when a CPU does not yet have a valid ASID context associated with it, as in this case there is no work for any of flush_cache_mm()/flush_cache_page()/flush_cache_range() to do. Based on the the MIPS implementation. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index dfc1d0379479..92f87a460a81 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -330,6 +330,9 @@ loop_exit: */ void flush_cache_mm(struct mm_struct *mm) { + if (cpu_context(smp_processor_id(), mm) == NO_CONTEXT) + return; + /* * If cache is only 4k-per-way, there are never any 'aliases'. Since * the cache is physically tagged, the data can just be left in there. @@ -371,6 +374,9 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long phys = pfn << PAGE_SHIFT; unsigned int alias_mask; + if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT) + return; + alias_mask = boot_cpu_data.dcache.alias_mask; /* We only need to flush D-cache when we have alias */ @@ -413,6 +419,9 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address, void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { + if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT) + return; + /* * If cache is only 4k-per-way, there are never any 'aliases'. Since * the cache is physically tagged, the data can just be left in there. -- cgit From 112e58471de3431fbd03dee514777ad4a66a77b2 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 02:49:40 +0900 Subject: sh: TLB protection violation exception optimizations. This adds a bit of rework to have the TLB protection violations skip the TLB miss fastpath and go directly in to do_page_fault(), as these require slow path handling. Based on an earlier patch by SUGIOKA Toshinobu. Signed-off-by: Paul Mundt --- arch/sh/mm/fault_32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index dbbdeba2cee5..41840647f65f 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -318,9 +318,9 @@ do_sigbus: /* * Called with interrupts disabled. */ -asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs, - unsigned long writeaccess, - unsigned long address) +asmlinkage int __kprobes +handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess, + unsigned long address) { pgd_t *pgd; pud_t *pud; -- cgit From 8010fbe7a67c2f993cbb11b9d8b7e98528256dd1 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 03:06:41 +0900 Subject: sh: TLB fast path optimizations for load/store exceptions. This only bothers with the TLB entry flush in the case of the initial page write exception, as it is unecessary in the case of the load/store exceptions. Signed-off-by: Paul Mundt --- arch/sh/mm/fault_32.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index 41840647f65f..f1c93c880ed4 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -327,7 +327,6 @@ handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess, pmd_t *pmd; pte_t *pte; pte_t entry; - int ret = 1; /* * We don't take page faults for P1, P2, and parts of P4, these @@ -338,40 +337,41 @@ handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess, pgd = pgd_offset_k(address); } else { if (unlikely(address >= TASK_SIZE || !current->mm)) - goto out; + return 1; pgd = pgd_offset(current->mm, address); } pud = pud_offset(pgd, address); if (pud_none_or_clear_bad(pud)) - goto out; + return 1; pmd = pmd_offset(pud, address); if (pmd_none_or_clear_bad(pmd)) - goto out; + return 1; pte = pte_offset_kernel(pmd, address); entry = *pte; if (unlikely(pte_none(entry) || pte_not_present(entry))) - goto out; + return 1; if (unlikely(writeaccess && !pte_write(entry))) - goto out; + return 1; if (writeaccess) entry = pte_mkdirty(entry); entry = pte_mkyoung(entry); + set_pte(pte, entry); + #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP) /* - * ITLB is not affected by "ldtlb" instruction. - * So, we need to flush the entry by ourselves. + * SH-4 does not set MMUCR.RC to the corresponding TLB entry in + * the case of an initial page write exception, so we need to + * flush it in order to avoid potential TLB entry duplication. */ - local_flush_tlb_one(get_asid(), address & PAGE_MASK); + if (writeaccess == 2) + local_flush_tlb_one(get_asid(), address & PAGE_MASK); #endif - set_pte(pte, entry); update_mmu_cache(NULL, address, entry); - ret = 0; -out: - return ret; + return 0; } -- cgit From 8edcfcbbd131a3580db666ed1034c24d56eb6f5d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 09:03:59 +0900 Subject: sh: Bail from kmap_coherent_init() if we have no dcache aliases. This kills off the ifdef from kmap_coherent_init() and just bails if there are no cache aliases. This permits the kmap coherent code to be used on other CPUs. Signed-off-by: Paul Mundt --- arch/sh/mm/pg-mmu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/pg-mmu.c b/arch/sh/mm/pg-mmu.c index 027c4d83fb8e..7a6ef34bd499 100644 --- a/arch/sh/mm/pg-mmu.c +++ b/arch/sh/mm/pg-mmu.c @@ -22,13 +22,14 @@ static pte_t *kmap_coherent_pte; void __init kmap_coherent_init(void) { -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) unsigned long vaddr; + if (!boot_cpu_data.dcache.n_aliases) + return; + /* cache the first coherent kmap pte */ vaddr = __fix_to_virt(FIX_CMAP_BEGIN); kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); -#endif } static void *kmap_coherent(struct page *page, unsigned long addr) -- cgit From 2739742c24f1a55365e71f0722bfdce8994e9c4e Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 09:19:19 +0900 Subject: sh: Provide the kmap_coherent() interface generically. This plugs in kmap_coherent() for the non-SH4 cases to permit the pg-mmu.c bits to be used generically across all CPUs. SH-5 is still in the TODO state, but will move over to fixmap and the generic interface gradually. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile_32 | 2 +- arch/sh/mm/cache-sh5.c | 15 ++++++++++++ arch/sh/mm/kmap.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ arch/sh/mm/pg-mmu.c | 48 ------------------------------------- arch/sh/mm/tlb-nommu.c | 15 ++++++++++++ 5 files changed, 95 insertions(+), 49 deletions(-) create mode 100644 arch/sh/mm/kmap.c (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32 index 17b02522214f..30771b137f48 100644 --- a/arch/sh/mm/Makefile_32 +++ b/arch/sh/mm/Makefile_32 @@ -15,7 +15,7 @@ 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 pg-mmu.o +mmu-$(CONFIG_MMU) := fault_32.o kmap.o tlbflush_32.o ioremap_32.o pg-mmu.o obj-y += $(mmu-y) obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 698113fce814..28f3c8fb1b99 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -29,6 +29,21 @@ void __init p3_cache_init(void) dtlb_cache_slot = sh64_get_wired_dtlb_entry(); } +void __init kmap_coherent_init(void) +{ + /* XXX ... */ +} + +void *kmap_coherent(struct page *page, unsigned long addr) +{ + /* XXX ... */ + return NULL; +} + +void kunmap_coherent(void) +{ +} + #ifdef CONFIG_DCACHE_DISABLED #define sh64_dcache_purge_all() do { } while (0) #define sh64_dcache_purge_coloured_phy_page(paddr, eaddr) do { } while (0) diff --git a/arch/sh/mm/kmap.c b/arch/sh/mm/kmap.c new file mode 100644 index 000000000000..3eecf0d42f1a --- /dev/null +++ b/arch/sh/mm/kmap.c @@ -0,0 +1,64 @@ +/* + * arch/sh/mm/kmap.c + * + * Copyright (C) 1999, 2000, 2002 Niibe Yutaka + * Copyright (C) 2002 - 2009 Paul Mundt + * + * Released under the terms of the GNU GPL v2.0. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)) + +static pte_t *kmap_coherent_pte; + +void __init kmap_coherent_init(void) +{ + unsigned long vaddr; + + if (!boot_cpu_data.dcache.n_aliases) + return; + + /* cache the first coherent kmap pte */ + vaddr = __fix_to_virt(FIX_CMAP_BEGIN); + kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); +} + +void *kmap_coherent(struct page *page, unsigned long addr) +{ + enum fixed_addresses idx; + unsigned long vaddr, flags; + pte_t pte; + + BUG_ON(test_bit(PG_dcache_dirty, &page->flags)); + + inc_preempt_count(); + + idx = (addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT; + vaddr = __fix_to_virt(FIX_CMAP_END - idx); + pte = mk_pte(page, PAGE_KERNEL); + + local_irq_save(flags); + flush_tlb_one(get_asid(), vaddr); + local_irq_restore(flags); + + update_mmu_cache(NULL, vaddr, pte); + + set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte); + + return (void *)vaddr; +} + +void kunmap_coherent(void) +{ + dec_preempt_count(); + preempt_check_resched(); +} diff --git a/arch/sh/mm/pg-mmu.c b/arch/sh/mm/pg-mmu.c index 7a6ef34bd499..f51d0a4eb3ba 100644 --- a/arch/sh/mm/pg-mmu.c +++ b/arch/sh/mm/pg-mmu.c @@ -15,54 +15,6 @@ #include #include -#define kmap_get_fixmap_pte(vaddr) \ - pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)) - -static pte_t *kmap_coherent_pte; - -void __init kmap_coherent_init(void) -{ - unsigned long vaddr; - - if (!boot_cpu_data.dcache.n_aliases) - return; - - /* cache the first coherent kmap pte */ - vaddr = __fix_to_virt(FIX_CMAP_BEGIN); - kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); -} - -static void *kmap_coherent(struct page *page, unsigned long addr) -{ - enum fixed_addresses idx; - unsigned long vaddr, flags; - pte_t pte; - - BUG_ON(test_bit(PG_dcache_dirty, &page->flags)); - - inc_preempt_count(); - - idx = (addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT; - vaddr = __fix_to_virt(FIX_CMAP_END - idx); - pte = mk_pte(page, PAGE_KERNEL); - - local_irq_save(flags); - flush_tlb_one(get_asid(), vaddr); - local_irq_restore(flags); - - update_mmu_cache(NULL, vaddr, pte); - - set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte); - - return (void *)vaddr; -} - -static inline void kunmap_coherent(void) -{ - dec_preempt_count(); - preempt_check_resched(); -} - void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) diff --git a/arch/sh/mm/tlb-nommu.c b/arch/sh/mm/tlb-nommu.c index 0ef5429943df..c49e9d24c2e6 100644 --- a/arch/sh/mm/tlb-nommu.c +++ b/arch/sh/mm/tlb-nommu.c @@ -55,6 +55,21 @@ void __update_cache(struct vm_area_struct *vma, { } +void __init kmap_coherent_init(void) +{ +} + +void *kmap_coherent(struct page *page, unsigned long addr) +{ + BUG(); + return NULL; +} + +void kunmap_coherent(void) +{ + BUG(); +} + void __init page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd_base) { -- cgit From cbbe2f68f678a90bebeb30b8a7fcd8aed0614879 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 09:30:39 +0900 Subject: sh: rename pg-mmu.c -> cache.c, enable generically. This builds in the newly created cache.c (renamed from pg-mmu.c) for both MMU and NOMMU configurations. The kmap_coherent() stubs and alias information recorded by each CPU family takes care of doing the right thing while enabling the code to be commonly shared. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile_32 | 16 +++--- arch/sh/mm/cache.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++ arch/sh/mm/pg-mmu.c | 129 ------------------------------------------------- 3 files changed, 137 insertions(+), 137 deletions(-) create mode 100644 arch/sh/mm/cache.c delete mode 100644 arch/sh/mm/pg-mmu.c (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32 index 30771b137f48..affcc9a15cea 100644 --- a/arch/sh/mm/Makefile_32 +++ b/arch/sh/mm/Makefile_32 @@ -2,20 +2,20 @@ # Makefile for the Linux SuperH-specific parts of the memory manager. # -obj-y := init.o extable_32.o consistent.o mmap.o +obj-y := cache.o init.o extable_32.o consistent.o mmap.o ifndef CONFIG_CACHE_OFF -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 flush-sh4.o -cache-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o +cacheops-$(CONFIG_CPU_SH2) := cache-sh2.o +cacheops-$(CONFIG_CPU_SH2A) := cache-sh2a.o +cacheops-$(CONFIG_CPU_SH3) := cache-sh3.o +cacheops-$(CONFIG_CPU_SH4) := cache-sh4.o flush-sh4.o +cacheops-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o endif -obj-y += $(cache-y) +obj-y += $(cacheops-y) mmu-y := tlb-nommu.o pg-nommu.o -mmu-$(CONFIG_MMU) := fault_32.o kmap.o tlbflush_32.o ioremap_32.o pg-mmu.o +mmu-$(CONFIG_MMU) := fault_32.o kmap.o tlbflush_32.o ioremap_32.o obj-y += $(mmu-y) obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c new file mode 100644 index 000000000000..f51d0a4eb3ba --- /dev/null +++ b/arch/sh/mm/cache.c @@ -0,0 +1,129 @@ +/* + * arch/sh/mm/pg-mmu.c + * + * Copyright (C) 1999, 2000, 2002 Niibe Yutaka + * Copyright (C) 2002 - 2009 Paul Mundt + * + * Released under the terms of the GNU GPL v2.0. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +void copy_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && + !test_bit(PG_dcache_dirty, &page->flags)) { + void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(vto, src, len); + kunmap_coherent(); + } else { + memcpy(dst, src, len); + if (boot_cpu_data.dcache.n_aliases) + set_bit(PG_dcache_dirty, &page->flags); + } + + if (vma->vm_flags & VM_EXEC) + flush_cache_page(vma, vaddr, page_to_pfn(page)); +} + +void copy_from_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && + !test_bit(PG_dcache_dirty, &page->flags)) { + void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(dst, vfrom, len); + kunmap_coherent(); + } else { + memcpy(dst, src, len); + if (boot_cpu_data.dcache.n_aliases) + set_bit(PG_dcache_dirty, &page->flags); + } +} + +void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma) +{ + void *vfrom, *vto; + + vto = kmap_atomic(to, KM_USER1); + + if (boot_cpu_data.dcache.n_aliases && page_mapped(from) && + !test_bit(PG_dcache_dirty, &from->flags)) { + vfrom = kmap_coherent(from, vaddr); + copy_page(vto, vfrom); + kunmap_coherent(); + } else { + vfrom = kmap_atomic(from, KM_USER0); + copy_page(vto, vfrom); + kunmap_atomic(vfrom, KM_USER0); + } + + if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) + __flush_wback_region(vto, PAGE_SIZE); + + kunmap_atomic(vto, KM_USER1); + /* Make sure this page is cleared on other CPU's too before using it */ + smp_wmb(); +} +EXPORT_SYMBOL(copy_user_highpage); + +void clear_user_highpage(struct page *page, unsigned long vaddr) +{ + void *kaddr = kmap_atomic(page, KM_USER0); + + clear_page(kaddr); + + if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) + __flush_wback_region(kaddr, PAGE_SIZE); + + kunmap_atomic(kaddr, KM_USER0); +} +EXPORT_SYMBOL(clear_user_highpage); + +void __update_cache(struct vm_area_struct *vma, + unsigned long address, pte_t pte) +{ + struct page *page; + unsigned long pfn = pte_pfn(pte); + + if (!boot_cpu_data.dcache.n_aliases) + return; + + page = pfn_to_page(pfn); + if (pfn_valid(pfn) && page_mapping(page)) { + int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); + if (dirty) { + unsigned long addr = (unsigned long)page_address(page); + + if (pages_do_alias(addr, address & PAGE_MASK)) + __flush_wback_region((void *)addr, PAGE_SIZE); + } + } +} + +void __flush_anon_page(struct page *page, unsigned long vmaddr) +{ + unsigned long addr = (unsigned long) page_address(page); + + if (pages_do_alias(addr, vmaddr)) { + if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && + !test_bit(PG_dcache_dirty, &page->flags)) { + void *kaddr; + + kaddr = kmap_coherent(page, vmaddr); + __flush_wback_region((void *)kaddr, PAGE_SIZE); + kunmap_coherent(); + } else + __flush_wback_region((void *)addr, PAGE_SIZE); + } +} diff --git a/arch/sh/mm/pg-mmu.c b/arch/sh/mm/pg-mmu.c deleted file mode 100644 index f51d0a4eb3ba..000000000000 --- a/arch/sh/mm/pg-mmu.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * arch/sh/mm/pg-mmu.c - * - * Copyright (C) 1999, 2000, 2002 Niibe Yutaka - * Copyright (C) 2002 - 2009 Paul Mundt - * - * Released under the terms of the GNU GPL v2.0. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -void copy_to_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, const void *src, - unsigned long len) -{ - if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && - !test_bit(PG_dcache_dirty, &page->flags)) { - void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); - memcpy(vto, src, len); - kunmap_coherent(); - } else { - memcpy(dst, src, len); - if (boot_cpu_data.dcache.n_aliases) - set_bit(PG_dcache_dirty, &page->flags); - } - - if (vma->vm_flags & VM_EXEC) - flush_cache_page(vma, vaddr, page_to_pfn(page)); -} - -void copy_from_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, const void *src, - unsigned long len) -{ - if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && - !test_bit(PG_dcache_dirty, &page->flags)) { - void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); - memcpy(dst, vfrom, len); - kunmap_coherent(); - } else { - memcpy(dst, src, len); - if (boot_cpu_data.dcache.n_aliases) - set_bit(PG_dcache_dirty, &page->flags); - } -} - -void copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr, struct vm_area_struct *vma) -{ - void *vfrom, *vto; - - vto = kmap_atomic(to, KM_USER1); - - if (boot_cpu_data.dcache.n_aliases && page_mapped(from) && - !test_bit(PG_dcache_dirty, &from->flags)) { - vfrom = kmap_coherent(from, vaddr); - copy_page(vto, vfrom); - kunmap_coherent(); - } else { - vfrom = kmap_atomic(from, KM_USER0); - copy_page(vto, vfrom); - kunmap_atomic(vfrom, KM_USER0); - } - - if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) - __flush_wback_region(vto, PAGE_SIZE); - - kunmap_atomic(vto, KM_USER1); - /* Make sure this page is cleared on other CPU's too before using it */ - smp_wmb(); -} -EXPORT_SYMBOL(copy_user_highpage); - -void clear_user_highpage(struct page *page, unsigned long vaddr) -{ - void *kaddr = kmap_atomic(page, KM_USER0); - - clear_page(kaddr); - - if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) - __flush_wback_region(kaddr, PAGE_SIZE); - - kunmap_atomic(kaddr, KM_USER0); -} -EXPORT_SYMBOL(clear_user_highpage); - -void __update_cache(struct vm_area_struct *vma, - unsigned long address, pte_t pte) -{ - struct page *page; - unsigned long pfn = pte_pfn(pte); - - if (!boot_cpu_data.dcache.n_aliases) - return; - - page = pfn_to_page(pfn); - if (pfn_valid(pfn) && page_mapping(page)) { - int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); - if (dirty) { - unsigned long addr = (unsigned long)page_address(page); - - if (pages_do_alias(addr, address & PAGE_MASK)) - __flush_wback_region((void *)addr, PAGE_SIZE); - } - } -} - -void __flush_anon_page(struct page *page, unsigned long vmaddr) -{ - unsigned long addr = (unsigned long) page_address(page); - - if (pages_do_alias(addr, vmaddr)) { - if (boot_cpu_data.dcache.n_aliases && page_mapped(page) && - !test_bit(PG_dcache_dirty, &page->flags)) { - void *kaddr; - - kaddr = kmap_coherent(page, vmaddr); - __flush_wback_region((void *)kaddr, PAGE_SIZE); - kunmap_coherent(); - } else - __flush_wback_region((void *)addr, PAGE_SIZE); - } -} -- cgit From dde5e3ffb770ef2854bbc32c51a365e932919e19 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 09:49:32 +0900 Subject: sh: rework nommu for generic cache.c use. This does a bit of reorganizing for allowing nommu to use the new and generic cache.c, no functional changes. Signed-off-by: Paul Mundt --- arch/sh/mm/mmap.c | 2 +- arch/sh/mm/tlb-nommu.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index 1b5fdfb4e0c2..d2984fa42d3d 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c @@ -14,10 +14,10 @@ #include #include -#ifdef CONFIG_MMU unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ EXPORT_SYMBOL(shm_align_mask); +#ifdef CONFIG_MMU /* * To avoid cache aliases, we map the shared page with same color. */ diff --git a/arch/sh/mm/tlb-nommu.c b/arch/sh/mm/tlb-nommu.c index c49e9d24c2e6..0710ebb99b9a 100644 --- a/arch/sh/mm/tlb-nommu.c +++ b/arch/sh/mm/tlb-nommu.c @@ -50,11 +50,6 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) { } -void __update_cache(struct vm_area_struct *vma, - unsigned long address, pte_t pte) -{ -} - void __init kmap_coherent_init(void) { } -- cgit From aae4d1428c03b03f9fe6204a83e35822fe9cc591 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 09:57:57 +0900 Subject: sh: consolidate nommu stubs in arch/sh/mm/nommu.c. These were previous littered around tlb-nommu.c and pg-nommu.c, though at this point there are more stubs than are strictly TLB or page op related, so just consolidate them in a single nommu.c. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile_32 | 2 +- arch/sh/mm/Makefile_64 | 2 +- arch/sh/mm/nommu.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ arch/sh/mm/pg-nommu.c | 33 ----------------- arch/sh/mm/tlb-nommu.c | 75 --------------------------------------- 5 files changed, 98 insertions(+), 110 deletions(-) create mode 100644 arch/sh/mm/nommu.c delete mode 100644 arch/sh/mm/pg-nommu.c delete mode 100644 arch/sh/mm/tlb-nommu.c (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32 index affcc9a15cea..ff3b07bd772d 100644 --- a/arch/sh/mm/Makefile_32 +++ b/arch/sh/mm/Makefile_32 @@ -14,7 +14,7 @@ endif obj-y += $(cacheops-y) -mmu-y := tlb-nommu.o pg-nommu.o +mmu-y := nommu.o mmu-$(CONFIG_MMU) := fault_32.o kmap.o tlbflush_32.o ioremap_32.o obj-y += $(mmu-y) diff --git a/arch/sh/mm/Makefile_64 b/arch/sh/mm/Makefile_64 index 66c39106d0a8..4d5ed245ef47 100644 --- a/arch/sh/mm/Makefile_64 +++ b/arch/sh/mm/Makefile_64 @@ -4,7 +4,7 @@ obj-y := init.o consistent.o mmap.o -mmu-y := tlb-nommu.o pg-nommu.o extable_32.o +mmu-y := nommu.o extable_32.o mmu-$(CONFIG_MMU) := fault_64.o ioremap_64.o tlbflush_64.o tlb-sh5.o \ extable_64.o diff --git a/arch/sh/mm/nommu.c b/arch/sh/mm/nommu.c new file mode 100644 index 000000000000..51b54037216f --- /dev/null +++ b/arch/sh/mm/nommu.c @@ -0,0 +1,96 @@ +/* + * arch/sh/mm/nommu.c + * + * Various helper routines and stubs for MMUless SH. + * + * Copyright (C) 2002 - 2009 Paul Mundt + * + * Released under the terms of the GNU GPL v2.0. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Nothing too terribly exciting here .. + */ +void copy_page(void *to, void *from) +{ + memcpy(to, from, PAGE_SIZE); +} + +__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n) +{ + memcpy(to, from, n); + return 0; +} + +__kernel_size_t __clear_user(void *to, __kernel_size_t n) +{ + memset(to, 0, n); + return 0; +} + +void local_flush_tlb_all(void) +{ + BUG(); +} + +void local_flush_tlb_mm(struct mm_struct *mm) +{ + BUG(); +} + +void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + BUG(); +} + +void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + BUG(); +} + +void local_flush_tlb_one(unsigned long asid, unsigned long page) +{ + BUG(); +} + +void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + BUG(); +} + +void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) +{ +} + +void __init kmap_coherent_init(void) +{ +} + +void *kmap_coherent(struct page *page, unsigned long addr) +{ + BUG(); + return NULL; +} + +void kunmap_coherent(void) +{ + BUG(); +} + +void __init page_table_range_init(unsigned long start, unsigned long end, + pgd_t *pgd_base) +{ +} + +void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) +{ +} diff --git a/arch/sh/mm/pg-nommu.c b/arch/sh/mm/pg-nommu.c deleted file mode 100644 index 7e33b486b7e9..000000000000 --- a/arch/sh/mm/pg-nommu.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * arch/sh/mm/pg-nommu.c - * - * copy_page()/__copy_user()/__clear_user() implementations for MMUless SH. - * - * Copyright (C) 2003 Paul Mundt - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include -#include -#include -#include -#include - -void copy_page(void *to, void *from) -{ - memcpy(to, from, PAGE_SIZE); -} - -__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n) -{ - memcpy(to, from, n); - return 0; -} - -__kernel_size_t __clear_user(void *to, __kernel_size_t n) -{ - memset(to, 0, n); - return 0; -} diff --git a/arch/sh/mm/tlb-nommu.c b/arch/sh/mm/tlb-nommu.c deleted file mode 100644 index 0710ebb99b9a..000000000000 --- a/arch/sh/mm/tlb-nommu.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * arch/sh/mm/tlb-nommu.c - * - * TLB Operations for MMUless SH. - * - * Copyright (C) 2002 Paul Mundt - * - * Released under the terms of the GNU GPL v2.0. - */ -#include -#include -#include -#include - -/* - * Nothing too terribly exciting here .. - */ -void local_flush_tlb_all(void) -{ - BUG(); -} - -void local_flush_tlb_mm(struct mm_struct *mm) -{ - BUG(); -} - -void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, - unsigned long end) -{ - BUG(); -} - -void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - BUG(); -} - -void local_flush_tlb_one(unsigned long asid, unsigned long page) -{ - BUG(); -} - -void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) -{ - BUG(); -} - -void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) -{ -} - -void __init kmap_coherent_init(void) -{ -} - -void *kmap_coherent(struct page *page, unsigned long addr) -{ - BUG(); - return NULL; -} - -void kunmap_coherent(void) -{ - BUG(); -} - -void __init page_table_range_init(unsigned long start, unsigned long end, - pgd_t *pgd_base) -{ -} - -void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) -{ -} -- cgit From ecba1060583635ab55092072441ff903b5e9a659 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 11:05:42 +0900 Subject: sh: Centralize the CPU cache initialization routines. This provides a central point for CPU cache initialization routines. This replaces the antiquated p3_cache_init() method, which the vast majority of CPUs never cared about. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 2 +- arch/sh/mm/cache-sh5.c | 2 +- arch/sh/mm/cache.c | 11 +++++++++++ arch/sh/mm/init.c | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 92f87a460a81..df2eb87f1524 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -94,7 +94,7 @@ static void __init emit_cache_params(void) /* * SH-4 has virtually indexed and physically tagged cache. */ -void __init p3_cache_init(void) +void __init sh4_cache_init(void) { compute_alias(&boot_cpu_data.icache); compute_alias(&boot_cpu_data.dcache); diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 28f3c8fb1b99..576cad04b11b 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -23,7 +23,7 @@ /* Wired TLB entry for the D-cache */ static unsigned long long dtlb_cache_slot; -void __init p3_cache_init(void) +void __init cpu_cache_init(void) { /* Reserve a slot for dcache colouring in the DTLB */ dtlb_cache_slot = sh64_get_wired_dtlb_entry(); diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index f51d0a4eb3ba..659981ffae24 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -127,3 +127,14 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) __flush_wback_region((void *)addr, PAGE_SIZE); } } + +void __init cpu_cache_init(void) +{ + if ((boot_cpu_data.family == CPU_FAMILY_SH4) || + (boot_cpu_data.family == CPU_FAMILY_SH4A) || + (boot_cpu_data.family == CPU_FAMILY_SH4AL_DSP)) { + extern void __weak sh4_cache_init(void); + + sh4_cache_init(); + } +} diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index fe532aeaa16d..cf0e9c5146b1 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -230,7 +230,7 @@ void __init mem_init(void) datasize >> 10, initsize >> 10); - p3_cache_init(); + cpu_cache_init(); /* Initialize the vDSO */ vsyscall_init(); -- cgit From 27d59ec1709817a90aa3ab7169f60994a89ad2f5 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 11:11:16 +0900 Subject: sh: Move alias computation to shared cache init. This migrates the alias computation and printing of probed cache parameters from the SH-4 code to the shared cpu_cache_init(). This permits other platforms with aliases to make use of the same probe logic without having to roll their own, and also produces consistent output regardless of platform. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 58 +++++--------------------------------------------- arch/sh/mm/cache.c | 46 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 53 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index df2eb87f1524..4ac844b1432f 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -44,61 +44,15 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys, static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) = (void (*)(unsigned long, unsigned long))0xdeadbeef; -static void compute_alias(struct cache_info *c) -{ - c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1); - c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0; -} - -static void __init emit_cache_params(void) -{ - printk("PVR=%08x CVR=%08x PRR=%08x\n", - ctrl_inl(CCN_PVR), - ctrl_inl(CCN_CVR), - ctrl_inl(CCN_PRR)); - printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n", - boot_cpu_data.icache.ways, - boot_cpu_data.icache.sets, - boot_cpu_data.icache.way_incr); - printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", - boot_cpu_data.icache.entry_mask, - boot_cpu_data.icache.alias_mask, - boot_cpu_data.icache.n_aliases); - printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n", - boot_cpu_data.dcache.ways, - boot_cpu_data.dcache.sets, - boot_cpu_data.dcache.way_incr); - printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", - boot_cpu_data.dcache.entry_mask, - boot_cpu_data.dcache.alias_mask, - boot_cpu_data.dcache.n_aliases); - - /* - * Emit Secondary Cache parameters if the CPU has a probed L2. - */ - if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) { - printk("S-cache : n_ways=%d n_sets=%d way_incr=%d\n", - boot_cpu_data.scache.ways, - boot_cpu_data.scache.sets, - boot_cpu_data.scache.way_incr); - printk("S-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", - boot_cpu_data.scache.entry_mask, - boot_cpu_data.scache.alias_mask, - boot_cpu_data.scache.n_aliases); - } - - if (!__flush_dcache_segment_fn) - panic("unknown number of cache ways\n"); -} - /* * SH-4 has virtually indexed and physically tagged cache. */ void __init sh4_cache_init(void) { - compute_alias(&boot_cpu_data.icache); - compute_alias(&boot_cpu_data.dcache); - compute_alias(&boot_cpu_data.scache); + printk("PVR=%08x CVR=%08x PRR=%08x\n", + ctrl_inl(CCN_PVR), + ctrl_inl(CCN_CVR), + ctrl_inl(CCN_PRR)); switch (boot_cpu_data.dcache.ways) { case 1: @@ -111,11 +65,9 @@ void __init sh4_cache_init(void) __flush_dcache_segment_fn = __flush_dcache_segment_4way; break; default: - __flush_dcache_segment_fn = NULL; + panic("unknown number of cache ways\n"); break; } - - emit_cache_params(); } /* diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index 659981ffae24..a31e5c46e7a6 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -128,8 +128,52 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) } } +static void compute_alias(struct cache_info *c) +{ + c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1); + c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0; +} + +static void __init emit_cache_params(void) +{ + printk(KERN_NOTICE "I-cache : n_ways=%d n_sets=%d way_incr=%d\n", + boot_cpu_data.icache.ways, + boot_cpu_data.icache.sets, + boot_cpu_data.icache.way_incr); + printk(KERN_NOTICE "I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", + boot_cpu_data.icache.entry_mask, + boot_cpu_data.icache.alias_mask, + boot_cpu_data.icache.n_aliases); + printk(KERN_NOTICE "D-cache : n_ways=%d n_sets=%d way_incr=%d\n", + boot_cpu_data.dcache.ways, + boot_cpu_data.dcache.sets, + boot_cpu_data.dcache.way_incr); + printk(KERN_NOTICE "D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", + boot_cpu_data.dcache.entry_mask, + boot_cpu_data.dcache.alias_mask, + boot_cpu_data.dcache.n_aliases); + + /* + * Emit Secondary Cache parameters if the CPU has a probed L2. + */ + if (boot_cpu_data.flags & CPU_HAS_L2_CACHE) { + printk(KERN_NOTICE "S-cache : n_ways=%d n_sets=%d way_incr=%d\n", + boot_cpu_data.scache.ways, + boot_cpu_data.scache.sets, + boot_cpu_data.scache.way_incr); + printk(KERN_NOTICE "S-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n", + boot_cpu_data.scache.entry_mask, + boot_cpu_data.scache.alias_mask, + boot_cpu_data.scache.n_aliases); + } +} + void __init cpu_cache_init(void) { + compute_alias(&boot_cpu_data.icache); + compute_alias(&boot_cpu_data.dcache); + compute_alias(&boot_cpu_data.scache); + if ((boot_cpu_data.family == CPU_FAMILY_SH4) || (boot_cpu_data.family == CPU_FAMILY_SH4A) || (boot_cpu_data.family == CPU_FAMILY_SH4AL_DSP)) { @@ -137,4 +181,6 @@ void __init cpu_cache_init(void) sh4_cache_init(); } + + emit_cache_params(); } -- cgit From 0b445dcaf3adda5bec5cc494925bc689fcc59a0e Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 11:22:50 +0900 Subject: sh: Don't export flush_dcache_all(). flush_dcache_all() is used internally by the SH-4 cache code, it is not part of the exported cache API, so make it static and don't export it. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 4ac844b1432f..4466787a52aa 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -182,7 +182,7 @@ static void __uses_jump_to_uncached flush_icache_all(void) local_irq_restore(flags); } -void flush_dcache_all(void) +static inline void flush_dcache_all(void) { (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size); wmb(); -- cgit From 916e97834e023f89b31f796b53cc9c7956e7fe17 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 11:38:05 +0900 Subject: sh: Kill off unused flush_icache_user_range(). We use flush_cache_page() outright in copy_to_user_page(), and nothing else needs it, so just kill it off. SH-5 still defines its own version, but that too will go away in the same fashion once it converts over. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 14 -------------- arch/sh/mm/cache-sh5.c | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 4466787a52aa..b5860535e61f 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -401,20 +401,6 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, } } -/* - * flush_icache_user_range - * @vma: VMA of the process - * @page: page - * @addr: U0 address - * @len: length of the range (< page size) - */ -void flush_icache_user_range(struct vm_area_struct *vma, - struct page *page, unsigned long addr, int len) -{ - flush_cache_page(vma, addr, page_to_pfn(page)); - mb(); -} - /** * __flush_cache_4096 * diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 576cad04b11b..a50d23caf015 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -655,7 +655,7 @@ void flush_icache_range(unsigned long start, unsigned long end) * range following a poke into the program text through the ptrace() call * from another process (e.g. for BRK instruction insertion). */ -void flush_icache_user_range(struct vm_area_struct *vma, +static void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, unsigned long addr, int len) { -- cgit From 37443ef3f0406e855e169c87ae3f4ffb4b6ff635 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 12:29:49 +0900 Subject: sh: Migrate SH-4 cacheflush ops to function pointers. This paves the way for allowing individual CPUs to overload the individual flushing routines that they care about without having to depend on weak aliases. SH-4 is converted over initially, as it wires up pretty much everything. The majority of the other CPUs will simply use the default no-op implementation with their own region flushers wired up. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 87 ++++++++++++++++++++++++++------------------------ arch/sh/mm/cache-sh5.c | 4 +++ arch/sh/mm/cache.c | 70 ++++++++++++++++++++++++++++++++++++++++ arch/sh/mm/flush-sh4.c | 13 ++++++-- arch/sh/mm/init.c | 5 +-- 5 files changed, 133 insertions(+), 46 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index b5860535e61f..05cb04bc3940 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -26,13 +26,6 @@ #define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ #define MAX_ICACHE_PAGES 32 -static void __flush_dcache_segment_1way(unsigned long start, - unsigned long extent); -static void __flush_dcache_segment_2way(unsigned long start, - unsigned long extent); -static void __flush_dcache_segment_4way(unsigned long start, - unsigned long extent); - static void __flush_cache_4096(unsigned long addr, unsigned long phys, unsigned long exec_offset); @@ -44,39 +37,13 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys, static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) = (void (*)(unsigned long, unsigned long))0xdeadbeef; -/* - * SH-4 has virtually indexed and physically tagged cache. - */ -void __init sh4_cache_init(void) -{ - printk("PVR=%08x CVR=%08x PRR=%08x\n", - ctrl_inl(CCN_PVR), - ctrl_inl(CCN_CVR), - ctrl_inl(CCN_PRR)); - - switch (boot_cpu_data.dcache.ways) { - case 1: - __flush_dcache_segment_fn = __flush_dcache_segment_1way; - break; - case 2: - __flush_dcache_segment_fn = __flush_dcache_segment_2way; - break; - case 4: - __flush_dcache_segment_fn = __flush_dcache_segment_4way; - break; - default: - panic("unknown number of cache ways\n"); - break; - } -} - /* * Write back the range of D-cache, and purge the I-cache. * * Called from kernel/module.c:sys_init_module and routine for a.out format, * signal handler code and kprobes code */ -void flush_icache_range(unsigned long start, unsigned long end) +static void sh4_flush_icache_range(unsigned long start, unsigned long end) { int icacheaddr; unsigned long flags, v; @@ -137,7 +104,7 @@ static inline void flush_cache_4096(unsigned long start, * Write back & invalidate the D-cache of the page. * (To avoid "alias" issues) */ -void flush_dcache_page(struct page *page) +static void sh4_flush_dcache_page(struct page *page) { struct address_space *mapping = page_mapping(page); @@ -188,7 +155,7 @@ static inline void flush_dcache_all(void) wmb(); } -void flush_cache_all(void) +static void sh4_flush_cache_all(void) { flush_dcache_all(); flush_icache_all(); @@ -280,7 +247,7 @@ loop_exit: * * Caller takes mm->mmap_sem. */ -void flush_cache_mm(struct mm_struct *mm) +static void sh4_flush_cache_mm(struct mm_struct *mm) { if (cpu_context(smp_processor_id(), mm) == NO_CONTEXT) return; @@ -320,8 +287,8 @@ void flush_cache_mm(struct mm_struct *mm) * ADDR: Virtual Address (U0 address) * PFN: Physical page number */ -void flush_cache_page(struct vm_area_struct *vma, unsigned long address, - unsigned long pfn) +static void sh4_flush_cache_page(struct vm_area_struct *vma, + unsigned long address, unsigned long pfn) { unsigned long phys = pfn << PAGE_SHIFT; unsigned int alias_mask; @@ -368,8 +335,8 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address, * Flushing the cache lines for U0 only isn't enough. * We need to flush for P1 too, which may contain aliases. */ -void flush_cache_range(struct vm_area_struct *vma, unsigned long start, - unsigned long end) +static void sh4_flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) { if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT) return; @@ -668,3 +635,41 @@ static void __flush_dcache_segment_4way(unsigned long start, a3 += linesz; } while (a0 < a0e); } + +extern void __weak sh4__flush_region_init(void); + +/* + * SH-4 has virtually indexed and physically tagged cache. + */ +void __init sh4_cache_init(void) +{ + printk("PVR=%08x CVR=%08x PRR=%08x\n", + ctrl_inl(CCN_PVR), + ctrl_inl(CCN_CVR), + ctrl_inl(CCN_PRR)); + + switch (boot_cpu_data.dcache.ways) { + case 1: + __flush_dcache_segment_fn = __flush_dcache_segment_1way; + break; + case 2: + __flush_dcache_segment_fn = __flush_dcache_segment_2way; + break; + case 4: + __flush_dcache_segment_fn = __flush_dcache_segment_4way; + break; + default: + panic("unknown number of cache ways\n"); + break; + } + + flush_icache_range = sh4_flush_icache_range; + flush_dcache_page = sh4_flush_dcache_page; + flush_cache_all = sh4_flush_cache_all; + flush_cache_mm = sh4_flush_cache_mm; + flush_cache_dup_mm = sh4_flush_cache_mm; + flush_cache_page = sh4_flush_cache_page; + flush_cache_range = sh4_flush_cache_range; + + sh4__flush_region_init(); +} diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index a50d23caf015..a8f5142dc2cf 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -20,6 +20,8 @@ #include #include +extern void __weak sh4__flush_region_init(void); + /* Wired TLB entry for the D-cache */ static unsigned long long dtlb_cache_slot; @@ -27,6 +29,8 @@ void __init cpu_cache_init(void) { /* Reserve a slot for dcache colouring in the DTLB */ dtlb_cache_slot = sh64_get_wired_dtlb_entry(); + + sh4__flush_region_init(); } void __init kmap_coherent_init(void) diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index a31e5c46e7a6..da5bc6ac1b28 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -15,6 +15,62 @@ #include #include +void (*flush_cache_all)(void); +void (*flush_cache_mm)(struct mm_struct *mm); +void (*flush_cache_dup_mm)(struct mm_struct *mm); +void (*flush_cache_page)(struct vm_area_struct *vma, + unsigned long addr, unsigned long pfn); +void (*flush_cache_range)(struct vm_area_struct *vma, + unsigned long start, unsigned long end); +void (*flush_dcache_page)(struct page *page); +void (*flush_icache_range)(unsigned long start, unsigned long end); +void (*flush_icache_page)(struct vm_area_struct *vma, + struct page *page); +void (*flush_cache_sigtramp)(unsigned long address); +void (*__flush_wback_region)(void *start, int size); +void (*__flush_purge_region)(void *start, int size); +void (*__flush_invalidate_region)(void *start, int size); + +static inline void noop_flush_cache_all(void) +{ +} + +static inline void noop_flush_cache_mm(struct mm_struct *mm) +{ +} + +static inline void noop_flush_cache_page(struct vm_area_struct *vma, + unsigned long addr, unsigned long pfn) +{ +} + +static inline void noop_flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ +} + +static inline void noop_flush_dcache_page(struct page *page) +{ +} + +static inline void noop_flush_icache_range(unsigned long start, + unsigned long end) +{ +} + +static inline void noop_flush_icache_page(struct vm_area_struct *vma, + struct page *page) +{ +} + +static inline void noop_flush_cache_sigtramp(unsigned long address) +{ +} + +static inline void noop__flush_region(void *start, int size) +{ +} + void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) @@ -174,6 +230,20 @@ void __init cpu_cache_init(void) compute_alias(&boot_cpu_data.dcache); compute_alias(&boot_cpu_data.scache); + flush_cache_all = noop_flush_cache_all; + flush_cache_mm = noop_flush_cache_mm; + flush_cache_dup_mm = noop_flush_cache_mm; + flush_cache_page = noop_flush_cache_page; + flush_cache_range = noop_flush_cache_range; + flush_dcache_page = noop_flush_dcache_page; + flush_icache_range = noop_flush_icache_range; + flush_icache_page = noop_flush_icache_page; + flush_cache_sigtramp = noop_flush_cache_sigtramp; + + __flush_wback_region = noop__flush_region; + __flush_purge_region = noop__flush_region; + __flush_invalidate_region = noop__flush_region; + if ((boot_cpu_data.family == CPU_FAMILY_SH4) || (boot_cpu_data.family == CPU_FAMILY_SH4A) || (boot_cpu_data.family == CPU_FAMILY_SH4AL_DSP)) { diff --git a/arch/sh/mm/flush-sh4.c b/arch/sh/mm/flush-sh4.c index 1b6b6a12a99b..99c50dc7551e 100644 --- a/arch/sh/mm/flush-sh4.c +++ b/arch/sh/mm/flush-sh4.c @@ -8,7 +8,7 @@ * START: Virtual Address (U0, P1, or P3) * SIZE: Size of the region. */ -void __weak __flush_wback_region(void *start, int size) +static void sh4__flush_wback_region(void *start, int size) { reg_size_t aligned_start, v, cnt, end; @@ -51,7 +51,7 @@ void __weak __flush_wback_region(void *start, int size) * START: Virtual Address (U0, P1, or P3) * SIZE: Size of the region. */ -void __weak __flush_purge_region(void *start, int size) +static void sh4__flush_purge_region(void *start, int size) { reg_size_t aligned_start, v, cnt, end; @@ -90,7 +90,7 @@ void __weak __flush_purge_region(void *start, int size) /* * No write back please */ -void __weak __flush_invalidate_region(void *start, int size) +static void sh4__flush_invalidate_region(void *start, int size) { reg_size_t aligned_start, v, cnt, end; @@ -126,3 +126,10 @@ void __weak __flush_invalidate_region(void *start, int size) cnt--; } } + +void __init sh4__flush_region_init(void) +{ + __flush_wback_region = sh4__flush_wback_region; + __flush_invalidate_region = sh4__flush_invalidate_region; + __flush_purge_region = sh4__flush_purge_region; +} diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index cf0e9c5146b1..0a9b4d855bc9 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -210,6 +210,9 @@ void __init mem_init(void) high_memory = node_high_memory; } + /* Set this up early, so we can take care of the zero page */ + cpu_cache_init(); + /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); __flush_wback_region(empty_zero_page, PAGE_SIZE); @@ -230,8 +233,6 @@ void __init mem_init(void) datasize >> 10, initsize >> 10); - cpu_cache_init(); - /* Initialize the vDSO */ vsyscall_init(); } -- cgit From 109b44a82a7a8ae32d7fb257480f92f2d96f0daf Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 12:35:15 +0900 Subject: sh: Convert SH-2 to new cacheflush interface. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh2.c | 13 ++++++++++--- arch/sh/mm/cache.c | 6 ++++++ 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh2.c b/arch/sh/mm/cache-sh2.c index c4e80d2b764b..699a71f46327 100644 --- a/arch/sh/mm/cache-sh2.c +++ b/arch/sh/mm/cache-sh2.c @@ -16,7 +16,7 @@ #include #include -void __flush_wback_region(void *start, int size) +static void sh2__flush_wback_region(void *start, int size) { unsigned long v; unsigned long begin, end; @@ -37,7 +37,7 @@ void __flush_wback_region(void *start, int size) } } -void __flush_purge_region(void *start, int size) +static void sh2__flush_purge_region(void *start, int size) { unsigned long v; unsigned long begin, end; @@ -51,7 +51,7 @@ void __flush_purge_region(void *start, int size) CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); } -void __flush_invalidate_region(void *start, int size) +static void sh2__flush_invalidate_region(void *start, int size) { #ifdef CONFIG_CACHE_WRITEBACK /* @@ -82,3 +82,10 @@ void __flush_invalidate_region(void *start, int size) CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008); #endif } + +void __init sh2_cache_init(void) +{ + __flush_wback_region = sh2__flush_wback_region; + __flush_purge_region = sh2__flush_purge_region; + __flush_invalidate_region = sh2__flush_invalidate_region; +} diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index da5bc6ac1b28..5ac299d6604e 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -244,6 +244,12 @@ void __init cpu_cache_init(void) __flush_purge_region = noop__flush_region; __flush_invalidate_region = noop__flush_region; + if (boot_cpu_data.family == CPU_FAMILY_SH2) { + extern void __weak sh2_cache_init(void); + + sh2_cache_init(); + } + if ((boot_cpu_data.family == CPU_FAMILY_SH4) || (boot_cpu_data.family == CPU_FAMILY_SH4A) || (boot_cpu_data.family == CPU_FAMILY_SH4AL_DSP)) { -- cgit From a58e1a2ab4f6334c50dfbda83d3a5c6e0b2b4bee Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 12:38:29 +0900 Subject: sh: Convert SH-2A to new cacheflush interface. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh2a.c | 17 +++++++++++++---- arch/sh/mm/cache.c | 6 ++++++ 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c index 24d86a794065..96a41872dfd3 100644 --- a/arch/sh/mm/cache-sh2a.c +++ b/arch/sh/mm/cache-sh2a.c @@ -15,7 +15,7 @@ #include #include -void __flush_wback_region(void *start, int size) +static void sh2a__flush_wback_region(void *start, int size) { unsigned long v; unsigned long begin, end; @@ -44,7 +44,7 @@ void __flush_wback_region(void *start, int size) local_irq_restore(flags); } -void __flush_purge_region(void *start, int size) +static void sh2a__flush_purge_region(void *start, int size) { unsigned long v; unsigned long begin, end; @@ -65,7 +65,7 @@ void __flush_purge_region(void *start, int size) local_irq_restore(flags); } -void __flush_invalidate_region(void *start, int size) +static void sh2a__flush_invalidate_region(void *start, int size) { unsigned long v; unsigned long begin, end; @@ -97,7 +97,7 @@ void __flush_invalidate_region(void *start, int size) } /* WBack O-Cache and flush I-Cache */ -void flush_icache_range(unsigned long start, unsigned long end) +static void sh2a_flush_icache_range(unsigned long start, unsigned long end) { unsigned long v; unsigned long flags; @@ -127,3 +127,12 @@ void flush_icache_range(unsigned long start, unsigned long end) back_to_cached(); local_irq_restore(flags); } + +void __init sh2a_cache_init(void) +{ + flush_icache_range = sh2a_flush_icache_range; + + __flush_wback_region = sh2a__flush_wback_region; + __flush_purge_region = sh2a__flush_purge_region; + __flush_invalidate_region = sh2a__flush_invalidate_region; +} diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index 5ac299d6604e..b56cce408912 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -250,6 +250,12 @@ void __init cpu_cache_init(void) sh2_cache_init(); } + if (boot_cpu_data.family == CPU_FAMILY_SH2A) { + extern void __weak sh2a_cache_init(void); + + sh2a_cache_init(); + } + if ((boot_cpu_data.family == CPU_FAMILY_SH4) || (boot_cpu_data.family == CPU_FAMILY_SH4A) || (boot_cpu_data.family == CPU_FAMILY_SH4AL_DSP)) { -- cgit From 79f1c9da5e5fc5f4705836d8c1cee2213fc80640 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 12:42:55 +0900 Subject: sh: Convert SH-3 to new cacheflush interface. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh3.c | 25 +++++++++++++++---------- arch/sh/mm/cache.c | 6 ++++++ 2 files changed, 21 insertions(+), 10 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh3.c b/arch/sh/mm/cache-sh3.c index 6d1dbec08ad4..faef80c98134 100644 --- a/arch/sh/mm/cache-sh3.c +++ b/arch/sh/mm/cache-sh3.c @@ -32,7 +32,7 @@ * SIZE: Size of the region. */ -void __flush_wback_region(void *start, int size) +static void sh3__flush_wback_region(void *start, int size) { unsigned long v, j; unsigned long begin, end; @@ -71,7 +71,7 @@ void __flush_wback_region(void *start, int size) * START: Virtual Address (U0, P1, or P3) * SIZE: Size of the region. */ -void __flush_purge_region(void *start, int size) +static void sh3__flush_purge_region(void *start, int size) { unsigned long v; unsigned long begin, end; @@ -90,11 +90,16 @@ void __flush_purge_region(void *start, int size) } } -/* - * No write back please - * - * Except I don't think there's any way to avoid the writeback. So we - * just alias it to __flush_purge_region(). dwmw2. - */ -void __flush_invalidate_region(void *start, int size) - __attribute__((alias("__flush_purge_region"))); +void __init sh3_cache_init(void) +{ + __flush_wback_region = sh3__flush_wback_region; + __flush_purge_region = sh3__flush_purge_region; + + /* + * No write back please + * + * Except I don't think there's any way to avoid the writeback. + * So we just alias it to sh3__flush_purge_region(). dwmw2. + */ + __flush_invalidate_region = sh3__flush_purge_region; +} diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index b56cce408912..c9480b48c746 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -256,6 +256,12 @@ void __init cpu_cache_init(void) sh2a_cache_init(); } + if (boot_cpu_data.family == CPU_FAMILY_SH3) { + extern void __weak sh3_cache_init(void); + + sh3_cache_init(); + } + if ((boot_cpu_data.family == CPU_FAMILY_SH4) || (boot_cpu_data.family == CPU_FAMILY_SH4A) || (boot_cpu_data.family == CPU_FAMILY_SH4AL_DSP)) { -- cgit From 0d051d90bb08b516b9d6c30d25f83d3c6b5b1c1d Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 15 Aug 2009 12:53:39 +0900 Subject: sh: Convert SH7705 extended mode to new cacheflush interface. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh7705.c | 33 +++++++++++++++++++++++---------- arch/sh/mm/cache.c | 7 +++++++ 2 files changed, 30 insertions(+), 10 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index fa37bff306b9..f1d5c803c04b 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -64,7 +64,7 @@ static inline void cache_wback_all(void) * * Called from kernel/module.c:sys_init_module and routine for a.out format. */ -void flush_icache_range(unsigned long start, unsigned long end) +static void sh7705_flush_icache_range(unsigned long start, unsigned long end) { __flush_wback_region((void *)start, end - start); } @@ -72,7 +72,7 @@ void flush_icache_range(unsigned long start, unsigned long end) /* * Writeback&Invalidate the D-cache of the page */ -static void __uses_jump_to_uncached __flush_dcache_page(unsigned long phys) +static void __flush_dcache_page(unsigned long phys) { unsigned long ways, waysize, addrstart; unsigned long flags; @@ -127,7 +127,7 @@ static void __uses_jump_to_uncached __flush_dcache_page(unsigned long phys) * Write back & invalidate the D-cache of the page. * (To avoid "alias" issues) */ -void flush_dcache_page(struct page *page) +static void sh7705_flush_dcache_page(struct page *page) { struct address_space *mapping = page_mapping(page); @@ -137,7 +137,7 @@ void flush_dcache_page(struct page *page) __flush_dcache_page(PHYSADDR(page_address(page))); } -void __uses_jump_to_uncached flush_cache_all(void) +static void sh7705_flush_cache_all(void) { unsigned long flags; @@ -149,7 +149,7 @@ void __uses_jump_to_uncached flush_cache_all(void) local_irq_restore(flags); } -void flush_cache_mm(struct mm_struct *mm) +static void sh7705_flush_cache_mm(struct mm_struct *mm) { /* Is there any good way? */ /* XXX: possibly call flush_cache_range for each vm area */ @@ -165,8 +165,8 @@ void flush_cache_mm(struct mm_struct *mm) * Flushing the cache lines for U0 only isn't enough. * We need to flush for P1 too, which may contain aliases. */ -void flush_cache_range(struct vm_area_struct *vma, unsigned long start, - unsigned long end) +static void sh7705_flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) { /* @@ -184,8 +184,8 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, * * ADDRESS: Virtual Address (U0 address) */ -void flush_cache_page(struct vm_area_struct *vma, unsigned long address, - unsigned long pfn) +static void sh7705_flush_cache_page(struct vm_area_struct *vma, + unsigned long address, unsigned long pfn) { __flush_dcache_page(pfn << PAGE_SHIFT); } @@ -198,7 +198,20 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address, * Not entirely sure why this is necessary on SH3 with 32K cache but * without it we get occasional "Memory fault" when loading a program. */ -void flush_icache_page(struct vm_area_struct *vma, struct page *page) +static void sh7705_flush_icache_page(struct vm_area_struct *vma, + struct page *page) { __flush_purge_region(page_address(page), PAGE_SIZE); } + +void __init sh7705_cache_init(void) +{ + flush_icache_range = sh7705_flush_icache_range; + flush_dcache_page = sh7705_flush_dcache_page; + flush_cache_all = sh7705_flush_cache_all; + flush_cache_mm = sh7705_flush_cache_mm; + flush_cache_dup_mm = sh7705_flush_cache_mm; + flush_cache_range = sh7705_flush_cache_range; + flush_cache_page = sh7705_flush_cache_page; + flush_icache_page = sh7705_flush_icache_page; +} diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index c9480b48c746..8618ccdc1ca5 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -260,6 +260,13 @@ void __init cpu_cache_init(void) extern void __weak sh3_cache_init(void); sh3_cache_init(); + + if ((boot_cpu_data.type == CPU_SH7705) && + (boot_cpu_data.dcache.sets == 512)) { + extern void __weak sh7705_cache_init(void); + + sh7705_cache_init(); + } } if ((boot_cpu_data.family == CPU_FAMILY_SH4) || -- cgit From 65305ae816ca17a38340aef0ccc92d0c127acccf Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sun, 16 Aug 2009 00:53:56 +0900 Subject: sh: Convert cache disabled SH-5 over to new cache interface. The caches enabled case needs more work, but is presently broken regardless, so this can be done incrementally. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile_64 | 2 +- arch/sh/mm/tlbflush_64.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile_64 b/arch/sh/mm/Makefile_64 index 4d5ed245ef47..dd104c4fffa2 100644 --- a/arch/sh/mm/Makefile_64 +++ b/arch/sh/mm/Makefile_64 @@ -2,7 +2,7 @@ # Makefile for the Linux SuperH-specific parts of the memory manager. # -obj-y := init.o consistent.o mmap.o +obj-y := cache.o consistent.o init.o kmap.o mmap.o mmu-y := nommu.o extable_32.o mmu-$(CONFIG_MMU) := fault_64.o ioremap_64.o tlbflush_64.o tlb-sh5.o \ diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c index fa5a95a062d0..2dcc48528f7a 100644 --- a/arch/sh/mm/tlbflush_64.c +++ b/arch/sh/mm/tlbflush_64.c @@ -470,8 +470,3 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) { } - -void __update_cache(struct vm_area_struct *vma, - unsigned long address, pte_t pte) -{ -} -- cgit From 94ecd224c940830e2f2724c3860eb7fb74c15d31 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sun, 16 Aug 2009 01:50:17 +0900 Subject: sh: Fix up the SH-5 build with caches enabled. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh5.c | 249 +++++-------------------------------------------- arch/sh/mm/flush-sh4.c | 81 ++++++---------- 2 files changed, 48 insertions(+), 282 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index a8f5142dc2cf..819e0f9e8dba 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -25,29 +25,6 @@ extern void __weak sh4__flush_region_init(void); /* Wired TLB entry for the D-cache */ static unsigned long long dtlb_cache_slot; -void __init cpu_cache_init(void) -{ - /* Reserve a slot for dcache colouring in the DTLB */ - dtlb_cache_slot = sh64_get_wired_dtlb_entry(); - - sh4__flush_region_init(); -} - -void __init kmap_coherent_init(void) -{ - /* XXX ... */ -} - -void *kmap_coherent(struct page *page, unsigned long addr) -{ - /* XXX ... */ - return NULL; -} - -void kunmap_coherent(void) -{ -} - #ifdef CONFIG_DCACHE_DISABLED #define sh64_dcache_purge_all() do { } while (0) #define sh64_dcache_purge_coloured_phy_page(paddr, eaddr) do { } while (0) @@ -233,52 +210,6 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, } } -/* - * Invalidate a small range of user context I-cache, not necessarily page - * (or even cache-line) aligned. - * - * Since this is used inside ptrace, the ASID in the mm context typically - * won't match current_asid. We'll have to switch ASID to do this. For - * safety, and given that the range will be small, do all this under cli. - * - * Note, there is a hazard that the ASID in mm->context is no longer - * actually associated with mm, i.e. if the mm->context has started a new - * cycle since mm was last active. However, this is just a performance - * issue: all that happens is that we invalidate lines belonging to - * another mm, so the owning process has to refill them when that mm goes - * live again. mm itself can't have any cache entries because there will - * have been a flush_cache_all when the new mm->context cycle started. - */ -static void sh64_icache_inv_user_small_range(struct mm_struct *mm, - unsigned long start, int len) -{ - unsigned long long eaddr = start; - unsigned long long eaddr_end = start + len; - unsigned long current_asid, mm_asid; - unsigned long flags; - unsigned long long epage_start; - - /* - * Align to start of cache line. Otherwise, suppose len==8 and - * start was at 32N+28 : the last 4 bytes wouldn't get invalidated. - */ - eaddr = L1_CACHE_ALIGN(start); - eaddr_end = start + len; - - mm_asid = cpu_asid(smp_processor_id(), mm); - local_irq_save(flags); - current_asid = switch_and_save_asid(mm_asid); - - epage_start = eaddr & PAGE_MASK; - - while (eaddr < eaddr_end) { - __asm__ __volatile__("icbi %0, 0" : : "r" (eaddr)); - eaddr += L1_CACHE_BYTES; - } - switch_and_save_asid(current_asid); - local_irq_restore(flags); -} - static void sh64_icache_inv_current_user_range(unsigned long start, unsigned long end) { /* The icbi instruction never raises ITLBMISS. i.e. if there's not a @@ -564,7 +495,7 @@ static void sh64_dcache_purge_user_range(struct mm_struct *mm, * Invalidate the entire contents of both caches, after writing back to * memory any dirty data from the D-cache. */ -void flush_cache_all(void) +static void sh5_flush_cache_all(void) { sh64_dcache_purge_all(); sh64_icache_inv_all(); @@ -591,7 +522,7 @@ void flush_cache_all(void) * I-cache. This is similar to the lack of action needed in * flush_tlb_mm - see fault.c. */ -void flush_cache_mm(struct mm_struct *mm) +static void sh5_flush_cache_mm(struct mm_struct *mm) { sh64_dcache_purge_all(); } @@ -603,8 +534,8 @@ void flush_cache_mm(struct mm_struct *mm) * * Note, 'end' is 1 byte beyond the end of the range to flush. */ -void flush_cache_range(struct vm_area_struct *vma, unsigned long start, - unsigned long end) +static void sh5_flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) { struct mm_struct *mm = vma->vm_mm; @@ -621,8 +552,8 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, * * Note, this is called with pte lock held. */ -void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr, - unsigned long pfn) +static void sh5_flush_cache_page(struct vm_area_struct *vma, + unsigned long eaddr, unsigned long pfn) { sh64_dcache_purge_phy_page(pfn << PAGE_SHIFT); @@ -630,7 +561,7 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr, sh64_icache_inv_user_page(vma, eaddr); } -void flush_dcache_page(struct page *page) +static void sh5_flush_dcache_page(struct page *page) { sh64_dcache_purge_phy_page(page_to_phys(page)); wmb(); @@ -644,39 +575,20 @@ void flush_dcache_page(struct page *page) * mapping, therefore it's guaranteed that there no cache entries for * the range in cache sets of the wrong colour. */ -void flush_icache_range(unsigned long start, unsigned long end) +static void sh5_flush_icache_range(unsigned long start, unsigned long end) { __flush_purge_region((void *)start, end); wmb(); sh64_icache_inv_kernel_range(start, end); } -/* - * Flush the range of user (defined by vma->vm_mm) address space starting - * at 'addr' for 'len' bytes from the cache. The range does not straddle - * a page boundary, the unique physical page containing the range is - * 'page'. This seems to be used mainly for invalidating an address - * range following a poke into the program text through the ptrace() call - * from another process (e.g. for BRK instruction insertion). - */ -static void flush_icache_user_range(struct vm_area_struct *vma, - struct page *page, unsigned long addr, int len) -{ - - sh64_dcache_purge_coloured_phy_page(page_to_phys(page), addr); - mb(); - - if (vma->vm_flags & VM_EXEC) - sh64_icache_inv_user_small_range(vma->vm_mm, addr, len); -} - /* * For the address range [start,end), write back the data from the * D-cache and invalidate the corresponding region of the I-cache for the * current process. Used to flush signal trampolines on the stack to * make them executable. */ -void flush_cache_sigtramp(unsigned long vaddr) +static void sh5_flush_cache_sigtramp(unsigned long vaddr) { unsigned long end = vaddr + L1_CACHE_BYTES; @@ -685,138 +597,19 @@ void flush_cache_sigtramp(unsigned long vaddr) sh64_icache_inv_current_user_range(vaddr, end); } -#ifdef CONFIG_MMU -/* - * These *MUST* lie in an area of virtual address space that's otherwise - * unused. - */ -#define UNIQUE_EADDR_START 0xe0000000UL -#define UNIQUE_EADDR_END 0xe8000000UL - -/* - * Given a physical address paddr, and a user virtual address user_eaddr - * which will eventually be mapped to it, create a one-off kernel-private - * eaddr mapped to the same paddr. This is used for creating special - * destination pages for copy_user_page and clear_user_page. - */ -static unsigned long sh64_make_unique_eaddr(unsigned long user_eaddr, - unsigned long paddr) -{ - static unsigned long current_pointer = UNIQUE_EADDR_START; - unsigned long coloured_pointer; - - if (current_pointer == UNIQUE_EADDR_END) { - sh64_dcache_purge_all(); - current_pointer = UNIQUE_EADDR_START; - } - - coloured_pointer = (current_pointer & ~CACHE_OC_SYN_MASK) | - (user_eaddr & CACHE_OC_SYN_MASK); - sh64_setup_dtlb_cache_slot(coloured_pointer, get_asid(), paddr); - - current_pointer += (PAGE_SIZE << CACHE_OC_N_SYNBITS); - - return coloured_pointer; -} - -static void sh64_copy_user_page_coloured(void *to, void *from, - unsigned long address) -{ - void *coloured_to; - - /* - * Discard any existing cache entries of the wrong colour. These are - * present quite often, if the kernel has recently used the page - * internally, then given it up, then it's been allocated to the user. - */ - sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long)to); - - coloured_to = (void *)sh64_make_unique_eaddr(address, __pa(to)); - copy_page(from, coloured_to); - - sh64_teardown_dtlb_cache_slot(); -} - -static void sh64_clear_user_page_coloured(void *to, unsigned long address) -{ - void *coloured_to; - - /* - * Discard any existing kernel-originated lines of the wrong - * colour (as above) - */ - sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long)to); - - coloured_to = (void *)sh64_make_unique_eaddr(address, __pa(to)); - clear_page(coloured_to); - - sh64_teardown_dtlb_cache_slot(); -} - -/* - * 'from' and 'to' are kernel virtual addresses (within the superpage - * mapping of the physical RAM). 'address' is the user virtual address - * where the copy 'to' will be mapped after. This allows a custom - * mapping to be used to ensure that the new copy is placed in the - * right cache sets for the user to see it without having to bounce it - * out via memory. Note however : the call to flush_page_to_ram in - * (generic)/mm/memory.c:(break_cow) undoes all this good work in that one - * very important case! - * - * TBD : can we guarantee that on every call, any cache entries for - * 'from' are in the same colour sets as 'address' also? i.e. is this - * always used just to deal with COW? (I suspect not). - * - * There are two possibilities here for when the page 'from' was last accessed: - * - by the kernel : this is OK, no purge required. - * - by the/a user (e.g. for break_COW) : need to purge. - * - * If the potential user mapping at 'address' is the same colour as - * 'from' there is no need to purge any cache lines from the 'from' - * page mapped into cache sets of colour 'address'. (The copy will be - * accessing the page through 'from'). - */ -void copy_user_page(void *to, void *from, unsigned long address, - struct page *page) +void __init sh5_cache_init(void) { - if (((address ^ (unsigned long) from) & CACHE_OC_SYN_MASK) != 0) - sh64_dcache_purge_coloured_phy_page(__pa(from), address); + flush_cache_all = sh5_flush_cache_all; + flush_cache_mm = sh5_flush_cache_mm; + flush_cache_dup_mm = sh5_flush_cache_mm; + flush_cache_page = sh5_flush_cache_page; + flush_cache_range = sh5_flush_cache_range; + flush_dcache_page = sh5_flush_dcache_page; + flush_icache_range = sh5_flush_icache_range; + flush_cache_sigtramp = sh5_flush_cache_sigtramp; - if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) - copy_page(to, from); - else - sh64_copy_user_page_coloured(to, from, address); -} - -/* - * 'to' is a kernel virtual address (within the superpage mapping of the - * physical RAM). 'address' is the user virtual address where the 'to' - * page will be mapped after. This allows a custom mapping to be used to - * ensure that the new copy is placed in the right cache sets for the - * user to see it without having to bounce it out via memory. - */ -void clear_user_page(void *to, unsigned long address, struct page *page) -{ - if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) - clear_page(to); - else - sh64_clear_user_page_coloured(to, address); -} - -void copy_to_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, const void *src, - unsigned long len) -{ - flush_cache_page(vma, vaddr, page_to_pfn(page)); - memcpy(dst, src, len); - flush_icache_user_range(vma, page, vaddr, len); -} + /* Reserve a slot for dcache colouring in the DTLB */ + dtlb_cache_slot = sh64_get_wired_dtlb_entry(); -void copy_from_user_page(struct vm_area_struct *vma, struct page *page, - unsigned long vaddr, void *dst, const void *src, - unsigned long len) -{ - flush_cache_page(vma, vaddr, page_to_pfn(page)); - memcpy(dst, src, len); + sh4__flush_region_init(); } -#endif diff --git a/arch/sh/mm/flush-sh4.c b/arch/sh/mm/flush-sh4.c index 99c50dc7551e..cef402678f42 100644 --- a/arch/sh/mm/flush-sh4.c +++ b/arch/sh/mm/flush-sh4.c @@ -19,28 +19,19 @@ static void sh4__flush_wback_region(void *start, int size) cnt = (end - v) / L1_CACHE_BYTES; while (cnt >= 8) { - asm volatile("ocbwb @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbwb @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbwb @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbwb @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbwb @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbwb @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbwb @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbwb @%0" : : "r" (v)); - v += L1_CACHE_BYTES; + __ocbwb(v); v += L1_CACHE_BYTES; + __ocbwb(v); v += L1_CACHE_BYTES; + __ocbwb(v); v += L1_CACHE_BYTES; + __ocbwb(v); v += L1_CACHE_BYTES; + __ocbwb(v); v += L1_CACHE_BYTES; + __ocbwb(v); v += L1_CACHE_BYTES; + __ocbwb(v); v += L1_CACHE_BYTES; + __ocbwb(v); v += L1_CACHE_BYTES; cnt -= 8; } while (cnt) { - asm volatile("ocbwb @%0" : : "r" (v)); - v += L1_CACHE_BYTES; + __ocbwb(v); v += L1_CACHE_BYTES; cnt--; } } @@ -62,27 +53,18 @@ static void sh4__flush_purge_region(void *start, int size) cnt = (end - v) / L1_CACHE_BYTES; while (cnt >= 8) { - asm volatile("ocbp @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbp @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbp @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbp @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbp @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbp @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbp @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbp @%0" : : "r" (v)); - v += L1_CACHE_BYTES; + __ocbp(v); v += L1_CACHE_BYTES; + __ocbp(v); v += L1_CACHE_BYTES; + __ocbp(v); v += L1_CACHE_BYTES; + __ocbp(v); v += L1_CACHE_BYTES; + __ocbp(v); v += L1_CACHE_BYTES; + __ocbp(v); v += L1_CACHE_BYTES; + __ocbp(v); v += L1_CACHE_BYTES; + __ocbp(v); v += L1_CACHE_BYTES; cnt -= 8; } while (cnt) { - asm volatile("ocbp @%0" : : "r" (v)); - v += L1_CACHE_BYTES; + __ocbp(v); v += L1_CACHE_BYTES; cnt--; } } @@ -101,28 +83,19 @@ static void sh4__flush_invalidate_region(void *start, int size) cnt = (end - v) / L1_CACHE_BYTES; while (cnt >= 8) { - asm volatile("ocbi @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbi @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbi @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbi @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbi @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbi @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbi @%0" : : "r" (v)); - v += L1_CACHE_BYTES; - asm volatile("ocbi @%0" : : "r" (v)); - v += L1_CACHE_BYTES; + __ocbi(v); v += L1_CACHE_BYTES; + __ocbi(v); v += L1_CACHE_BYTES; + __ocbi(v); v += L1_CACHE_BYTES; + __ocbi(v); v += L1_CACHE_BYTES; + __ocbi(v); v += L1_CACHE_BYTES; + __ocbi(v); v += L1_CACHE_BYTES; + __ocbi(v); v += L1_CACHE_BYTES; + __ocbi(v); v += L1_CACHE_BYTES; cnt -= 8; } while (cnt) { - asm volatile("ocbi @%0" : : "r" (v)); - v += L1_CACHE_BYTES; + __ocbi(v); v += L1_CACHE_BYTES; cnt--; } } -- cgit From 8c41cdcaffb09dca8e6ad7d4d8f885e0b86b9002 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sun, 16 Aug 2009 02:15:50 +0900 Subject: sh64: Kill off dead i/d-cache disabled bits. These will be handled through the shared cache interface instead, and they are presently undefined anyways. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh5.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 819e0f9e8dba..d4a445c865d7 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -25,14 +25,6 @@ extern void __weak sh4__flush_region_init(void); /* Wired TLB entry for the D-cache */ static unsigned long long dtlb_cache_slot; -#ifdef CONFIG_DCACHE_DISABLED -#define sh64_dcache_purge_all() do { } while (0) -#define sh64_dcache_purge_coloured_phy_page(paddr, eaddr) do { } while (0) -#define sh64_dcache_purge_user_range(mm, start, end) do { } while (0) -#define sh64_dcache_purge_phy_page(paddr) do { } while (0) -#define sh64_dcache_purge_virt_page(mm, eaddr) do { } while (0) -#endif - /* * The following group of functions deal with mapping and unmapping a * temporary page into a DTLB slot that has been set aside for exclusive @@ -52,7 +44,6 @@ static inline void sh64_teardown_dtlb_cache_slot(void) local_irq_enable(); } -#ifndef CONFIG_ICACHE_DISABLED static inline void sh64_icache_inv_all(void) { unsigned long long addr, flag, data; @@ -237,9 +228,7 @@ static void sh64_icache_inv_current_user_range(unsigned long start, unsigned lon addr += L1_CACHE_BYTES; } } -#endif /* !CONFIG_ICACHE_DISABLED */ -#ifndef CONFIG_DCACHE_DISABLED /* Buffer used as the target of alloco instructions to purge data from cache sets by natural eviction. -- RPC */ #define DUMMY_ALLOCO_AREA_SIZE ((L1_CACHE_BYTES << 10) + (1024 * 4)) @@ -489,7 +478,6 @@ static void sh64_dcache_purge_user_range(struct mm_struct *mm, sh64_dcache_purge_user_pages(mm, start, end); } } -#endif /* !CONFIG_DCACHE_DISABLED */ /* * Invalidate the entire contents of both caches, after writing back to -- cgit From 2b4315185a06414c4ab40fb0db50dce1b534a1d9 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sun, 16 Aug 2009 02:16:44 +0900 Subject: sh: Wire up sh5_cache_init(). Now that the SH-5 code is more or less behaving with the new cacheflush interface, wire up the initialization code. Signed-off-by: Paul Mundt --- arch/sh/mm/cache.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index 8618ccdc1ca5..d60239460436 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -277,5 +277,11 @@ void __init cpu_cache_init(void) sh4_cache_init(); } + if (boot_cpu_data.family == CPU_FAMILY_SH5) { + extern void __weak sh5_cache_init(void); + + sh5_cache_init(); + } + emit_cache_params(); } -- cgit From 1b3edd9745ef3a9ee831fe5a611757686579c9e1 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sun, 16 Aug 2009 03:49:21 +0900 Subject: sh: Merge the _32/_64 variants of arch/sh/mm/Makefile. Now that there is sufficient shared infrastructure, merge the Makefiles. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile | 70 +++++++++++++++++++++++++++++++++++++++++++++++--- arch/sh/mm/Makefile_32 | 39 ---------------------------- arch/sh/mm/Makefile_64 | 46 --------------------------------- 3 files changed, 66 insertions(+), 89 deletions(-) delete mode 100644 arch/sh/mm/Makefile_32 delete mode 100644 arch/sh/mm/Makefile_64 (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 9f4bc3d90b1e..4ca71e9e09eb 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -1,5 +1,67 @@ -ifeq ($(CONFIG_SUPERH32),y) -include ${srctree}/arch/sh/mm/Makefile_32 -else -include ${srctree}/arch/sh/mm/Makefile_64 +# +# Makefile for the Linux SuperH-specific parts of the memory manager. +# + +obj-y := cache.o init.o consistent.o mmap.o + +ifndef CONFIG_CACHE_OFF +cacheops-$(CONFIG_CPU_SH2) := cache-sh2.o +cacheops-$(CONFIG_CPU_SH2A) := cache-sh2a.o +cacheops-$(CONFIG_CPU_SH3) := cache-sh3.o +cacheops-$(CONFIG_CPU_SH4) := cache-sh4.o flush-sh4.o +cacheops-$(CONFIG_CPU_SH5) := cache-sh5.o flush-sh4.o +cacheops-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o endif + +obj-y += $(cacheops-y) + +mmu-y := nommu.o extable_32.o +mmu-$(CONFIG_MMU) := extable_$(BITS).o fault_$(BITS).o \ + ioremap_$(BITS).o kmap.o tlbflush_$(BITS).o + +obj-y += $(mmu-y) +obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o + +ifdef CONFIG_DEBUG_FS +obj-$(CONFIG_CPU_SH4) += cache-debugfs.o +endif + +ifdef CONFIG_MMU +tlb-$(CONFIG_CPU_SH3) := tlb-sh3.o +tlb-$(CONFIG_CPU_SH4) := tlb-sh4.o +tlb-$(CONFIG_CPU_SH5) := tlb-sh5.o +tlb-$(CONFIG_CPU_HAS_PTEAEX) := tlb-pteaex.o +obj-y += $(tlb-y) +endif + +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o +obj-$(CONFIG_PMB) += pmb.o +obj-$(CONFIG_PMB_FIXED) += pmb-fixed.o +obj-$(CONFIG_NUMA) += numa.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. +# This is required because the code is called from a context in entry.S where +# very few registers have been saved in the exception handler (for speed +# reasons). +# The caller save registers that have been saved and which can be used are +# r2,r3,r4,r5 : argument passing +# r15, r18 : SP and LINK +# tr0-4 : allow all caller-save TR's. The compiler seems to be able to make +# use of them, so it's probably beneficial to performance to save them +# and have them available for it. +# +# The resources not listed below are callee save, i.e. the compiler is free to +# use any of them and will spill them to the stack itself. + +CFLAGS_fault_64.o += -ffixed-r7 \ + -ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \ + -ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \ + -ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \ + -ffixed-r24 -ffixed-r25 -ffixed-r26 -ffixed-r27 \ + -ffixed-r36 -ffixed-r37 -ffixed-r38 -ffixed-r39 -ffixed-r40 \ + -ffixed-r41 -ffixed-r42 -ffixed-r43 \ + -ffixed-r60 -ffixed-r61 -ffixed-r62 \ + -fomit-frame-pointer + +EXTRA_CFLAGS += -Werror diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32 deleted file mode 100644 index ff3b07bd772d..000000000000 --- a/arch/sh/mm/Makefile_32 +++ /dev/null @@ -1,39 +0,0 @@ -# -# Makefile for the Linux SuperH-specific parts of the memory manager. -# - -obj-y := cache.o init.o extable_32.o consistent.o mmap.o - -ifndef CONFIG_CACHE_OFF -cacheops-$(CONFIG_CPU_SH2) := cache-sh2.o -cacheops-$(CONFIG_CPU_SH2A) := cache-sh2a.o -cacheops-$(CONFIG_CPU_SH3) := cache-sh3.o -cacheops-$(CONFIG_CPU_SH4) := cache-sh4.o flush-sh4.o -cacheops-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o -endif - -obj-y += $(cacheops-y) - -mmu-y := nommu.o -mmu-$(CONFIG_MMU) := fault_32.o kmap.o tlbflush_32.o ioremap_32.o - -obj-y += $(mmu-y) -obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o - -ifdef CONFIG_DEBUG_FS -obj-$(CONFIG_CPU_SH4) += cache-debugfs.o -endif - -ifdef CONFIG_MMU -tlb-$(CONFIG_CPU_SH3) := tlb-sh3.o -tlb-$(CONFIG_CPU_SH4) := tlb-sh4.o -tlb-$(CONFIG_CPU_HAS_PTEAEX) := tlb-pteaex.o -obj-y += $(tlb-y) -endif - -obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_PMB) += pmb.o -obj-$(CONFIG_PMB_FIXED) += pmb-fixed.o -obj-$(CONFIG_NUMA) += numa.o - -EXTRA_CFLAGS += -Werror diff --git a/arch/sh/mm/Makefile_64 b/arch/sh/mm/Makefile_64 deleted file mode 100644 index dd104c4fffa2..000000000000 --- a/arch/sh/mm/Makefile_64 +++ /dev/null @@ -1,46 +0,0 @@ -# -# Makefile for the Linux SuperH-specific parts of the memory manager. -# - -obj-y := cache.o consistent.o init.o kmap.o mmap.o - -mmu-y := nommu.o extable_32.o -mmu-$(CONFIG_MMU) := fault_64.o ioremap_64.o tlbflush_64.o tlb-sh5.o \ - extable_64.o - -ifndef CONFIG_CACHE_OFF -obj-y += cache-sh5.o flush-sh4.o -endif - -obj-y += $(mmu-y) -obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o - -obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_NUMA) += numa.o - -EXTRA_CFLAGS += -Werror - -# 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. -# This is required because the code is called from a context in entry.S where -# very few registers have been saved in the exception handler (for speed -# reasons). -# The caller save registers that have been saved and which can be used are -# r2,r3,r4,r5 : argument passing -# r15, r18 : SP and LINK -# tr0-4 : allow all caller-save TR's. The compiler seems to be able to make -# use of them, so it's probably beneficial to performance to save them -# and have them available for it. -# -# The resources not listed below are callee save, i.e. the compiler is free to -# use any of them and will spill them to the stack itself. - -CFLAGS_fault_64.o += -ffixed-r7 \ - -ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \ - -ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \ - -ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \ - -ffixed-r24 -ffixed-r25 -ffixed-r26 -ffixed-r27 \ - -ffixed-r36 -ffixed-r37 -ffixed-r38 -ffixed-r39 -ffixed-r40 \ - -ffixed-r41 -ffixed-r42 -ffixed-r43 \ - -ffixed-r60 -ffixed-r61 -ffixed-r62 \ - -fomit-frame-pointer -- cgit From e055d41ff5e9761c5572a6f4ce94bcd82bfbb28f Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 19 Aug 2009 17:57:01 +0900 Subject: sh: Build fix for disabled caches. This fixes up the build when caches are disabled, by linking in all of the cache routines directly. This paves the way for splitting out separate I and D cache disabling, similar to what sh64 had, and which we want for SH-X3 anyways. Signed-off-by: Paul Mundt --- arch/sh/mm/Makefile | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 4ca71e9e09eb..3759bf853293 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile @@ -4,14 +4,12 @@ obj-y := cache.o init.o consistent.o mmap.o -ifndef CONFIG_CACHE_OFF cacheops-$(CONFIG_CPU_SH2) := cache-sh2.o cacheops-$(CONFIG_CPU_SH2A) := cache-sh2a.o cacheops-$(CONFIG_CPU_SH3) := cache-sh3.o cacheops-$(CONFIG_CPU_SH4) := cache-sh4.o flush-sh4.o cacheops-$(CONFIG_CPU_SH5) := cache-sh5.o flush-sh4.o cacheops-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o -endif obj-y += $(cacheops-y) -- cgit From 6503fe4a6508673c15a509ec4ac3ca5979ae9593 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Thu, 20 Aug 2009 13:27:44 +0900 Subject: sh: Better description of SH-4 PTEA register update. Signed-off-by: Michael Trimarchi Signed-off-by: Paul Mundt --- arch/sh/mm/tlb-sh4.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index f0c7b7397fa6..fd0d11f1a81c 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c @@ -61,9 +61,12 @@ void update_mmu_cache(struct vm_area_struct * vma, */ ctrl_outl(pte.pte_high, MMU_PTEA); #else - if (cpu_data->flags & CPU_HAS_PTEA) - /* TODO: make this look less hacky */ - ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA); + if (cpu_data->flags & CPU_HAS_PTEA) { + /* The last 3 bits and the first one of pteval contains + * the PTEA timing control and space attribute bits + */ + ctrl_outl(copy_ptea_attributes(pteval), MMU_PTEA); + } #endif /* Set PTEL register */ -- cgit From c139a595878b0e8156476668e3d5c27b6aca7624 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 20 Aug 2009 15:24:41 +0900 Subject: sh: Fix up cache-sh4 build on SMP. mapping is unused on the SMP build, trigger a build error. Move it under the ifdef. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 05cb04bc3940..6c2db1401080 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -106,9 +106,9 @@ static inline void flush_cache_4096(unsigned long start, */ static void sh4_flush_dcache_page(struct page *page) { +#ifndef CONFIG_SMP struct address_space *mapping = page_mapping(page); -#ifndef CONFIG_SMP if (mapping && !mapping_mapped(mapping)) set_bit(PG_dcache_dirty, &page->flags); else -- cgit From f26b2a562b46ab186c8383993ab1332673ac4a47 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 21 Aug 2009 17:23:14 +0900 Subject: sh: Make cache flushers SMP-aware. This does a bit of rework for making the cache flushers SMP-aware. The function pointer-based flushers are renamed to local variants with the exported interface being commonly implemented and wrapping as necessary. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh2a.c | 10 ++-- arch/sh/mm/cache-sh4.c | 54 ++++++++++++------ arch/sh/mm/cache-sh5.c | 64 ++++++++++++++-------- arch/sh/mm/cache-sh7705.c | 67 ++++++++--------------- arch/sh/mm/cache.c | 137 ++++++++++++++++++++++++++-------------------- 5 files changed, 184 insertions(+), 148 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c index 96a41872dfd3..975899d83564 100644 --- a/arch/sh/mm/cache-sh2a.c +++ b/arch/sh/mm/cache-sh2a.c @@ -97,13 +97,15 @@ static void sh2a__flush_invalidate_region(void *start, int size) } /* WBack O-Cache and flush I-Cache */ -static void sh2a_flush_icache_range(unsigned long start, unsigned long end) +static void sh2a_flush_icache_range(void *args) { + struct flusher_data *data = args; + unsigned long start, end; unsigned long v; unsigned long flags; - start = start & ~(L1_CACHE_BYTES-1); - end = (end + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); + start = data->addr1 & ~(L1_CACHE_BYTES-1); + end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); local_irq_save(flags); jump_to_uncached(); @@ -130,7 +132,7 @@ static void sh2a_flush_icache_range(unsigned long start, unsigned long end) void __init sh2a_cache_init(void) { - flush_icache_range = sh2a_flush_icache_range; + local_flush_icache_range = sh2a_flush_icache_range; __flush_wback_region = sh2a__flush_wback_region; __flush_purge_region = sh2a__flush_purge_region; diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 6c2db1401080..9201b37c7cca 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -43,15 +43,20 @@ static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) = * Called from kernel/module.c:sys_init_module and routine for a.out format, * signal handler code and kprobes code */ -static void sh4_flush_icache_range(unsigned long start, unsigned long end) +static void sh4_flush_icache_range(void *args) { + struct flusher_data *data = args; int icacheaddr; + unsigned long start, end; unsigned long flags, v; int i; + start = data->addr1; + end = data->addr2; + /* If there are too many pages then just blow the caches */ if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { - flush_cache_all(); + local_flush_cache_all(args); } else { /* selectively flush d-cache then invalidate the i-cache */ /* this is inefficient, so only use for small ranges */ @@ -104,7 +109,7 @@ static inline void flush_cache_4096(unsigned long start, * Write back & invalidate the D-cache of the page. * (To avoid "alias" issues) */ -static void sh4_flush_dcache_page(struct page *page) +static void sh4_flush_dcache_page(void *page) { #ifndef CONFIG_SMP struct address_space *mapping = page_mapping(page); @@ -155,7 +160,7 @@ static inline void flush_dcache_all(void) wmb(); } -static void sh4_flush_cache_all(void) +static void sh4_flush_cache_all(void *unused) { flush_dcache_all(); flush_icache_all(); @@ -247,8 +252,10 @@ loop_exit: * * Caller takes mm->mmap_sem. */ -static void sh4_flush_cache_mm(struct mm_struct *mm) +static void sh4_flush_cache_mm(void *arg) { + struct mm_struct *mm = arg; + if (cpu_context(smp_processor_id(), mm) == NO_CONTEXT) return; @@ -287,12 +294,18 @@ static void sh4_flush_cache_mm(struct mm_struct *mm) * ADDR: Virtual Address (U0 address) * PFN: Physical page number */ -static void sh4_flush_cache_page(struct vm_area_struct *vma, - unsigned long address, unsigned long pfn) +static void sh4_flush_cache_page(void *args) { - unsigned long phys = pfn << PAGE_SHIFT; + struct flusher_data *data = args; + struct vm_area_struct *vma; + unsigned long address, pfn, phys; unsigned int alias_mask; + vma = data->vma; + address = data->addr1; + pfn = data->addr2; + phys = pfn << PAGE_SHIFT; + if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT) return; @@ -335,9 +348,16 @@ static void sh4_flush_cache_page(struct vm_area_struct *vma, * Flushing the cache lines for U0 only isn't enough. * We need to flush for P1 too, which may contain aliases. */ -static void sh4_flush_cache_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) +static void sh4_flush_cache_range(void *args) { + struct flusher_data *data = args; + struct vm_area_struct *vma; + unsigned long start, end; + + vma = data->vma; + start = data->addr1; + end = data->addr2; + if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT) return; @@ -663,13 +683,13 @@ void __init sh4_cache_init(void) break; } - flush_icache_range = sh4_flush_icache_range; - flush_dcache_page = sh4_flush_dcache_page; - flush_cache_all = sh4_flush_cache_all; - flush_cache_mm = sh4_flush_cache_mm; - flush_cache_dup_mm = sh4_flush_cache_mm; - flush_cache_page = sh4_flush_cache_page; - flush_cache_range = sh4_flush_cache_range; + local_flush_icache_range = sh4_flush_icache_range; + local_flush_dcache_page = sh4_flush_dcache_page; + local_flush_cache_all = sh4_flush_cache_all; + local_flush_cache_mm = sh4_flush_cache_mm; + local_flush_cache_dup_mm = sh4_flush_cache_mm; + local_flush_cache_page = sh4_flush_cache_page; + local_flush_cache_range = sh4_flush_cache_range; sh4__flush_region_init(); } diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index d4a445c865d7..467ff8e260f7 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -483,7 +483,7 @@ static void sh64_dcache_purge_user_range(struct mm_struct *mm, * Invalidate the entire contents of both caches, after writing back to * memory any dirty data from the D-cache. */ -static void sh5_flush_cache_all(void) +static void sh5_flush_cache_all(void *unused) { sh64_dcache_purge_all(); sh64_icache_inv_all(); @@ -510,7 +510,7 @@ static void sh5_flush_cache_all(void) * I-cache. This is similar to the lack of action needed in * flush_tlb_mm - see fault.c. */ -static void sh5_flush_cache_mm(struct mm_struct *mm) +static void sh5_flush_cache_mm(void *unused) { sh64_dcache_purge_all(); } @@ -522,13 +522,18 @@ static void sh5_flush_cache_mm(struct mm_struct *mm) * * Note, 'end' is 1 byte beyond the end of the range to flush. */ -static void sh5_flush_cache_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) +static void sh5_flush_cache_range(void *args) { - struct mm_struct *mm = vma->vm_mm; + struct flusher_data *data = args; + struct vm_area_struct *vma; + unsigned long start, end; - sh64_dcache_purge_user_range(mm, start, end); - sh64_icache_inv_user_page_range(mm, start, end); + vma = data->vma; + start = data->addr1; + end = data->addr2; + + sh64_dcache_purge_user_range(vma->vm_mm, start, end); + sh64_icache_inv_user_page_range(vma->vm_mm, start, end); } /* @@ -540,16 +545,23 @@ static void sh5_flush_cache_range(struct vm_area_struct *vma, * * Note, this is called with pte lock held. */ -static void sh5_flush_cache_page(struct vm_area_struct *vma, - unsigned long eaddr, unsigned long pfn) +static void sh5_flush_cache_page(void *args) { + struct flusher_data *data = args; + struct vm_area_struct *vma; + unsigned long eaddr, pfn; + + vma = data->vma; + eaddr = data->addr1; + pfn = data->addr2; + sh64_dcache_purge_phy_page(pfn << PAGE_SHIFT); if (vma->vm_flags & VM_EXEC) sh64_icache_inv_user_page(vma, eaddr); } -static void sh5_flush_dcache_page(struct page *page) +static void sh5_flush_dcache_page(void *page) { sh64_dcache_purge_phy_page(page_to_phys(page)); wmb(); @@ -563,8 +575,14 @@ static void sh5_flush_dcache_page(struct page *page) * mapping, therefore it's guaranteed that there no cache entries for * the range in cache sets of the wrong colour. */ -static void sh5_flush_icache_range(unsigned long start, unsigned long end) +static void sh5_flush_icache_range(void *args) { + struct flusher_data *data = args; + unsigned long start, end; + + start = data->addr1; + end = data->addr2; + __flush_purge_region((void *)start, end); wmb(); sh64_icache_inv_kernel_range(start, end); @@ -576,25 +594,25 @@ static void sh5_flush_icache_range(unsigned long start, unsigned long end) * current process. Used to flush signal trampolines on the stack to * make them executable. */ -static void sh5_flush_cache_sigtramp(unsigned long vaddr) +static void sh5_flush_cache_sigtramp(void *vaddr) { - unsigned long end = vaddr + L1_CACHE_BYTES; + unsigned long end = (unsigned long)vaddr + L1_CACHE_BYTES; - __flush_wback_region((void *)vaddr, L1_CACHE_BYTES); + __flush_wback_region(vaddr, L1_CACHE_BYTES); wmb(); - sh64_icache_inv_current_user_range(vaddr, end); + sh64_icache_inv_current_user_range((unsigned long)vaddr, end); } void __init sh5_cache_init(void) { - flush_cache_all = sh5_flush_cache_all; - flush_cache_mm = sh5_flush_cache_mm; - flush_cache_dup_mm = sh5_flush_cache_mm; - flush_cache_page = sh5_flush_cache_page; - flush_cache_range = sh5_flush_cache_range; - flush_dcache_page = sh5_flush_dcache_page; - flush_icache_range = sh5_flush_icache_range; - flush_cache_sigtramp = sh5_flush_cache_sigtramp; + local_flush_cache_all = sh5_flush_cache_all; + local_flush_cache_mm = sh5_flush_cache_mm; + local_flush_cache_dup_mm = sh5_flush_cache_mm; + local_flush_cache_page = sh5_flush_cache_page; + local_flush_cache_range = sh5_flush_cache_range; + local_flush_dcache_page = sh5_flush_dcache_page; + local_flush_icache_range = sh5_flush_icache_range; + local_flush_cache_sigtramp = sh5_flush_cache_sigtramp; /* Reserve a slot for dcache colouring in the DTLB */ dtlb_cache_slot = sh64_get_wired_dtlb_entry(); diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index f1d5c803c04b..6293f57fa888 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -64,8 +64,14 @@ static inline void cache_wback_all(void) * * Called from kernel/module.c:sys_init_module and routine for a.out format. */ -static void sh7705_flush_icache_range(unsigned long start, unsigned long end) +static void sh7705_flush_icache_range(void *args) { + struct flusher_data *data = args; + unsigned long start, end; + + start = data->addr1; + end = data->addr2; + __flush_wback_region((void *)start, end - start); } @@ -127,7 +133,7 @@ static void __flush_dcache_page(unsigned long phys) * Write back & invalidate the D-cache of the page. * (To avoid "alias" issues) */ -static void sh7705_flush_dcache_page(struct page *page) +static void sh7705_flush_dcache_page(void *page) { struct address_space *mapping = page_mapping(page); @@ -137,7 +143,7 @@ static void sh7705_flush_dcache_page(struct page *page) __flush_dcache_page(PHYSADDR(page_address(page))); } -static void sh7705_flush_cache_all(void) +static void sh7705_flush_cache_all(void *args) { unsigned long flags; @@ -149,44 +155,16 @@ static void sh7705_flush_cache_all(void) local_irq_restore(flags); } -static void sh7705_flush_cache_mm(struct mm_struct *mm) -{ - /* Is there any good way? */ - /* XXX: possibly call flush_cache_range for each vm area */ - flush_cache_all(); -} - -/* - * Write back and invalidate D-caches. - * - * START, END: Virtual Address (U0 address) - * - * NOTE: We need to flush the _physical_ page entry. - * Flushing the cache lines for U0 only isn't enough. - * We need to flush for P1 too, which may contain aliases. - */ -static void sh7705_flush_cache_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - - /* - * We could call flush_cache_page for the pages of these range, - * but it's not efficient (scan the caches all the time...). - * - * We can't use A-bit magic, as there's the case we don't have - * valid entry on TLB. - */ - flush_cache_all(); -} - /* * Write back and invalidate I/D-caches for the page. * * ADDRESS: Virtual Address (U0 address) */ -static void sh7705_flush_cache_page(struct vm_area_struct *vma, - unsigned long address, unsigned long pfn) +static void sh7705_flush_cache_page(void *args) { + struct flusher_data *data = args; + unsigned long pfn = data->addr2; + __flush_dcache_page(pfn << PAGE_SHIFT); } @@ -198,20 +176,19 @@ static void sh7705_flush_cache_page(struct vm_area_struct *vma, * Not entirely sure why this is necessary on SH3 with 32K cache but * without it we get occasional "Memory fault" when loading a program. */ -static void sh7705_flush_icache_page(struct vm_area_struct *vma, - struct page *page) +static void sh7705_flush_icache_page(void *page) { __flush_purge_region(page_address(page), PAGE_SIZE); } void __init sh7705_cache_init(void) { - flush_icache_range = sh7705_flush_icache_range; - flush_dcache_page = sh7705_flush_dcache_page; - flush_cache_all = sh7705_flush_cache_all; - flush_cache_mm = sh7705_flush_cache_mm; - flush_cache_dup_mm = sh7705_flush_cache_mm; - flush_cache_range = sh7705_flush_cache_range; - flush_cache_page = sh7705_flush_cache_page; - flush_icache_page = sh7705_flush_icache_page; + local_flush_icache_range = sh7705_flush_icache_range; + local_flush_dcache_page = sh7705_flush_dcache_page; + local_flush_cache_all = sh7705_flush_cache_all; + local_flush_cache_mm = sh7705_flush_cache_all; + local_flush_cache_dup_mm = sh7705_flush_cache_all; + local_flush_cache_range = sh7705_flush_cache_all; + local_flush_cache_page = sh7705_flush_cache_page; + local_flush_icache_page = sh7705_flush_icache_page; } diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index d60239460436..411fe6058429 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -1,5 +1,5 @@ /* - * arch/sh/mm/pg-mmu.c + * arch/sh/mm/cache.c * * Copyright (C) 1999, 2000, 2002 Niibe Yutaka * Copyright (C) 2002 - 2009 Paul Mundt @@ -10,63 +10,26 @@ #include #include #include +#include #include #include #include #include -void (*flush_cache_all)(void); -void (*flush_cache_mm)(struct mm_struct *mm); -void (*flush_cache_dup_mm)(struct mm_struct *mm); -void (*flush_cache_page)(struct vm_area_struct *vma, - unsigned long addr, unsigned long pfn); -void (*flush_cache_range)(struct vm_area_struct *vma, - unsigned long start, unsigned long end); -void (*flush_dcache_page)(struct page *page); -void (*flush_icache_range)(unsigned long start, unsigned long end); -void (*flush_icache_page)(struct vm_area_struct *vma, - struct page *page); -void (*flush_cache_sigtramp)(unsigned long address); +void (*local_flush_cache_all)(void *args) = cache_noop; +void (*local_flush_cache_mm)(void *args) = cache_noop; +void (*local_flush_cache_dup_mm)(void *args) = cache_noop; +void (*local_flush_cache_page)(void *args) = cache_noop; +void (*local_flush_cache_range)(void *args) = cache_noop; +void (*local_flush_dcache_page)(void *args) = cache_noop; +void (*local_flush_icache_range)(void *args) = cache_noop; +void (*local_flush_icache_page)(void *args) = cache_noop; +void (*local_flush_cache_sigtramp)(void *args) = cache_noop; + void (*__flush_wback_region)(void *start, int size); void (*__flush_purge_region)(void *start, int size); void (*__flush_invalidate_region)(void *start, int size); -static inline void noop_flush_cache_all(void) -{ -} - -static inline void noop_flush_cache_mm(struct mm_struct *mm) -{ -} - -static inline void noop_flush_cache_page(struct vm_area_struct *vma, - unsigned long addr, unsigned long pfn) -{ -} - -static inline void noop_flush_cache_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ -} - -static inline void noop_flush_dcache_page(struct page *page) -{ -} - -static inline void noop_flush_icache_range(unsigned long start, - unsigned long end) -{ -} - -static inline void noop_flush_icache_page(struct vm_area_struct *vma, - struct page *page) -{ -} - -static inline void noop_flush_cache_sigtramp(unsigned long address) -{ -} - static inline void noop__flush_region(void *start, int size) { } @@ -184,6 +147,72 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) } } +void flush_cache_all(void) +{ + on_each_cpu(local_flush_cache_all, NULL, 1); +} + +void flush_cache_mm(struct mm_struct *mm) +{ + on_each_cpu(local_flush_cache_mm, mm, 1); +} + +void flush_cache_dup_mm(struct mm_struct *mm) +{ + on_each_cpu(local_flush_cache_dup_mm, mm, 1); +} + +void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, + unsigned long pfn) +{ + struct flusher_data data; + + data.vma = vma; + data.addr1 = addr; + data.addr2 = pfn; + + on_each_cpu(local_flush_cache_page, (void *)&data, 1); +} + +void flush_cache_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + struct flusher_data data; + + data.vma = vma; + data.addr1 = start; + data.addr2 = end; + + on_each_cpu(local_flush_cache_range, (void *)&data, 1); +} + +void flush_dcache_page(struct page *page) +{ + on_each_cpu(local_flush_dcache_page, page, 1); +} + +void flush_icache_range(unsigned long start, unsigned long end) +{ + struct flusher_data data; + + data.vma = NULL; + data.addr1 = start; + data.addr2 = end; + + on_each_cpu(local_flush_icache_range, (void *)&data, 1); +} + +void flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + /* Nothing uses the VMA, so just pass the struct page along */ + on_each_cpu(local_flush_icache_page, page, 1); +} + +void flush_cache_sigtramp(unsigned long address) +{ + on_each_cpu(local_flush_cache_sigtramp, (void *)address, 1); +} + static void compute_alias(struct cache_info *c) { c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1); @@ -230,16 +259,6 @@ void __init cpu_cache_init(void) compute_alias(&boot_cpu_data.dcache); compute_alias(&boot_cpu_data.scache); - flush_cache_all = noop_flush_cache_all; - flush_cache_mm = noop_flush_cache_mm; - flush_cache_dup_mm = noop_flush_cache_mm; - flush_cache_page = noop_flush_cache_page; - flush_cache_range = noop_flush_cache_range; - flush_dcache_page = noop_flush_dcache_page; - flush_icache_range = noop_flush_icache_range; - flush_icache_page = noop_flush_icache_page; - flush_cache_sigtramp = noop_flush_cache_sigtramp; - __flush_wback_region = noop__flush_region; __flush_purge_region = noop__flush_region; __flush_invalidate_region = noop__flush_region; -- cgit From c01f0f1a4a96eb3acc5850e18cc43f24366966d0 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 21 Aug 2009 16:30:28 +0900 Subject: sh: Add initial support for SH7757 CPU subtype Signed-off-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- arch/sh/mm/Kconfig | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 2795618e4f07..64dc1ad59801 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -82,7 +82,7 @@ config 32BIT config PMB_ENABLE bool "Support 32-bit physical addressing through PMB" - depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785) + depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785) select 32BIT default y help @@ -97,7 +97,7 @@ choice config PMB bool "PMB" - depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785) + depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785) select 32BIT help If you say Y here, physical addressing will be extended to @@ -106,7 +106,8 @@ config PMB config PMB_FIXED bool "fixed PMB" - depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7780 || \ + depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || \ + CPU_SUBTYPE_SH7780 || \ CPU_SUBTYPE_SH7785) select 32BIT help -- cgit From 64a6d72213dd810dd55bd0a503c36150af41c3c3 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 21 Aug 2009 18:21:07 +0900 Subject: sh: Kill off now redundant local irq disabling. on_each_cpu() takes care of IRQ and preempt handling, the localized handling in each of the called functions can be killed off. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh2a.c | 6 +---- arch/sh/mm/cache-sh4.c | 61 ++++++++++++++++++++--------------------------- arch/sh/mm/cache-sh5.c | 29 +++++----------------- arch/sh/mm/cache-sh7705.c | 8 ------- 4 files changed, 33 insertions(+), 71 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c index 975899d83564..d783361e3f0a 100644 --- a/arch/sh/mm/cache-sh2a.c +++ b/arch/sh/mm/cache-sh2a.c @@ -102,12 +102,10 @@ static void sh2a_flush_icache_range(void *args) struct flusher_data *data = args; unsigned long start, end; unsigned long v; - unsigned long flags; start = data->addr1 & ~(L1_CACHE_BYTES-1); end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); - local_irq_save(flags); jump_to_uncached(); for (v = start; v < end; v+=L1_CACHE_BYTES) { @@ -122,12 +120,10 @@ static void sh2a_flush_icache_range(void *args) } } /* I-Cache invalidate */ - ctrl_outl(addr, - CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); + ctrl_outl(addr, CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); } back_to_cached(); - local_irq_restore(flags); } void __init sh2a_cache_init(void) diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 9201b37c7cca..e3b77f0fa470 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -48,48 +48,44 @@ static void sh4_flush_icache_range(void *args) struct flusher_data *data = args; int icacheaddr; unsigned long start, end; - unsigned long flags, v; + unsigned long v; int i; start = data->addr1; end = data->addr2; - /* If there are too many pages then just blow the caches */ - if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { - local_flush_cache_all(args); - } else { - /* selectively flush d-cache then invalidate the i-cache */ - /* this is inefficient, so only use for small ranges */ - start &= ~(L1_CACHE_BYTES-1); - end += L1_CACHE_BYTES-1; - end &= ~(L1_CACHE_BYTES-1); - - local_irq_save(flags); - jump_to_uncached(); - - for (v = start; v < end; v+=L1_CACHE_BYTES) { - asm volatile("ocbwb %0" - : /* no output */ - : "m" (__m(v))); - - icacheaddr = CACHE_IC_ADDRESS_ARRAY | ( - v & cpu_data->icache.entry_mask); - - for (i = 0; i < cpu_data->icache.ways; - i++, icacheaddr += cpu_data->icache.way_incr) - /* Clear i-cache line valid-bit */ - ctrl_outl(0, icacheaddr); - } + /* If there are too many pages then just blow the caches */ + if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { + local_flush_cache_all(args); + } else { + /* selectively flush d-cache then invalidate the i-cache */ + /* this is inefficient, so only use for small ranges */ + start &= ~(L1_CACHE_BYTES-1); + end += L1_CACHE_BYTES-1; + end &= ~(L1_CACHE_BYTES-1); + + jump_to_uncached(); + + for (v = start; v < end; v+=L1_CACHE_BYTES) { + __ocbwb(v); + + icacheaddr = CACHE_IC_ADDRESS_ARRAY | + (v & cpu_data->icache.entry_mask); + + for (i = 0; i < cpu_data->icache.ways; + i++, icacheaddr += cpu_data->icache.way_incr) + /* Clear i-cache line valid-bit */ + ctrl_outl(0, icacheaddr); + } back_to_cached(); - local_irq_restore(flags); } } static inline void flush_cache_4096(unsigned long start, unsigned long phys) { - unsigned long flags, exec_offset = 0; + unsigned long exec_offset = 0; /* * All types of SH-4 require PC to be in P2 to operate on the I-cache. @@ -99,10 +95,8 @@ static inline void flush_cache_4096(unsigned long start, (start < CACHE_OC_ADDRESS_ARRAY)) exec_offset = 0x20000000; - local_irq_save(flags); __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), exec_offset); - local_irq_restore(flags); } /* @@ -135,9 +129,8 @@ static void sh4_flush_dcache_page(void *page) /* TODO: Selective icache invalidation through IC address array.. */ static void __uses_jump_to_uncached flush_icache_all(void) { - unsigned long flags, ccr; + unsigned long ccr; - local_irq_save(flags); jump_to_uncached(); /* Flush I-cache */ @@ -149,9 +142,7 @@ static void __uses_jump_to_uncached flush_icache_all(void) * back_to_cached() will take care of the barrier for us, don't add * another one! */ - back_to_cached(); - local_irq_restore(flags); } static inline void flush_dcache_all(void) diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 467ff8e260f7..2f9dd6df00a6 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -34,28 +34,22 @@ static inline void sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, unsigned long paddr) { - local_irq_disable(); sh64_setup_tlb_slot(dtlb_cache_slot, eaddr, asid, paddr); } static inline void sh64_teardown_dtlb_cache_slot(void) { sh64_teardown_tlb_slot(dtlb_cache_slot); - local_irq_enable(); } static inline void sh64_icache_inv_all(void) { unsigned long long addr, flag, data; - unsigned long flags; addr = ICCR0; flag = ICCR0_ICI; data = 0; - /* Make this a critical section for safety (probably not strictly necessary.) */ - local_irq_save(flags); - /* Without %1 it gets unexplicably wrong */ __asm__ __volatile__ ( "getcfg %3, 0, %0\n\t" @@ -64,8 +58,6 @@ static inline void sh64_icache_inv_all(void) "synci" : "=&r" (data) : "0" (data), "r" (flag), "r" (addr)); - - local_irq_restore(flags); } static void sh64_icache_inv_kernel_range(unsigned long start, unsigned long end) @@ -90,7 +82,6 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long Also, eaddr is page-aligned. */ unsigned int cpu = smp_processor_id(); unsigned long long addr, end_addr; - unsigned long flags = 0; unsigned long running_asid, vma_asid; addr = eaddr; end_addr = addr + PAGE_SIZE; @@ -111,10 +102,9 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long running_asid = get_asid(); vma_asid = cpu_asid(cpu, vma->vm_mm); - if (running_asid != vma_asid) { - local_irq_save(flags); + if (running_asid != vma_asid) switch_and_save_asid(vma_asid); - } + while (addr < end_addr) { /* Worth unrolling a little */ __asm__ __volatile__("icbi %0, 0" : : "r" (addr)); @@ -123,10 +113,9 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long __asm__ __volatile__("icbi %0, 96" : : "r" (addr)); addr += 128; } - if (running_asid != vma_asid) { + + if (running_asid != vma_asid) switch_and_save_asid(running_asid); - local_irq_restore(flags); - } } static void sh64_icache_inv_user_page_range(struct mm_struct *mm, @@ -159,16 +148,12 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, unsigned long eaddr; unsigned long after_last_page_start; unsigned long mm_asid, current_asid; - unsigned long flags = 0; mm_asid = cpu_asid(smp_processor_id(), mm); current_asid = get_asid(); - if (mm_asid != current_asid) { - /* Switch ASID and run the invalidate loop under cli */ - local_irq_save(flags); + if (mm_asid != current_asid) switch_and_save_asid(mm_asid); - } aligned_start = start & PAGE_MASK; after_last_page_start = PAGE_SIZE + ((end - 1) & PAGE_MASK); @@ -194,10 +179,8 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, aligned_start = vma->vm_end; /* Skip to start of next region */ } - if (mm_asid != current_asid) { + if (mm_asid != current_asid) switch_and_save_asid(current_asid); - local_irq_restore(flags); - } } } diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 6293f57fa888..9dc38660e3de 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -81,7 +81,6 @@ static void sh7705_flush_icache_range(void *args) static void __flush_dcache_page(unsigned long phys) { unsigned long ways, waysize, addrstart; - unsigned long flags; phys |= SH_CACHE_VALID; @@ -98,7 +97,6 @@ static void __flush_dcache_page(unsigned long phys) * potential cache aliasing, therefore the optimisation is probably not * possible. */ - local_irq_save(flags); jump_to_uncached(); ways = current_cpu_data.dcache.ways; @@ -126,7 +124,6 @@ static void __flush_dcache_page(unsigned long phys) } while (--ways); back_to_cached(); - local_irq_restore(flags); } /* @@ -145,14 +142,9 @@ static void sh7705_flush_dcache_page(void *page) static void sh7705_flush_cache_all(void *args) { - unsigned long flags; - - local_irq_save(flags); jump_to_uncached(); - cache_wback_all(); back_to_cached(); - local_irq_restore(flags); } /* -- cgit From a5cf9e2444ec15de5407696ff21c32dd21ca0a8d Mon Sep 17 00:00:00 2001 From: Stuart Menefy Date: Mon, 24 Aug 2009 17:36:24 +0900 Subject: sh: Improve comments int SH4 cache flushing code This is a pure documentation, to try to explain why the cache flushing code for the SH4 is implemented the way it is. Signed-off-by: Stuart Menefy Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 5cfe08dbb59e..7ce816188313 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -581,6 +581,17 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys, * Break the 1, 2 and 4 way variants of this out into separate functions to * avoid nearly all the overhead of having the conditional stuff in the function * bodies (+ the 1 and 2 way cases avoid saving any registers too). + * + * We want to eliminate unnecessary bus transactions, so this code uses + * a non-obvious technique. + * + * Loop over a cache way sized block of, one cache line at a time. For each + * line, use movca.a to cause the current cache line contents to be written + * back, but without reading anything from main memory. However this has the + * side effect that the cache is now caching that memory location. So follow + * this with a cache invalidate to mark the cache line invalid. And do all + * this with interrupts disabled, to avoid the cache line being accidently + * evicted while it is holding garbage. */ static void __flush_dcache_segment_1way(unsigned long start, unsigned long extent_per_way) -- cgit From a1fce732359b80ead84efba23059a5f1b572b85a Mon Sep 17 00:00:00 2001 From: Stuart Menefy Date: Mon, 24 Aug 2009 18:29:25 +0900 Subject: sh: Fix overzealous checking in __ioremap() Allow peripherals before the start of RAM to be remapped. Signed-off-by: Stuart Menefy Signed-off-by: Paul Mundt --- arch/sh/mm/ioremap_32.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/ioremap_32.c b/arch/sh/mm/ioremap_32.c index da2f4186f2cd..c3250614e3ae 100644 --- a/arch/sh/mm/ioremap_32.c +++ b/arch/sh/mm/ioremap_32.c @@ -57,14 +57,6 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size, if (is_pci_memory_fixed_range(phys_addr, size)) return (void __iomem *)phys_addr; -#if !defined(CONFIG_PMB_FIXED) - /* - * Don't allow anybody to remap normal RAM that we're using.. - */ - if (phys_addr < virt_to_phys(high_memory)) - return NULL; -#endif - /* * Mappings have to be page-aligned */ -- cgit From ffad9d7a54a5e809007135595c778715aa0fb07a Mon Sep 17 00:00:00 2001 From: Stuart Menefy Date: Mon, 24 Aug 2009 18:39:39 +0900 Subject: sh: Fix problems with cache flushing when cache is in write-through mode Change the method used to flush the cache in write-through mode to avoid corrupted data being written back to memory. Signed-off-by: Stuart Menefy Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 7ce816188313..397c1030c7a6 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -592,6 +592,20 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys, * this with a cache invalidate to mark the cache line invalid. And do all * this with interrupts disabled, to avoid the cache line being accidently * evicted while it is holding garbage. + * + * This also breaks in a number of circumstances: + * - if there are modifications to the region of memory just above + * empty_zero_page (for example because a breakpoint has been placed + * there), then these can be lost. + * + * This is because the the memory address which the cache temporarily + * caches in the above description is empty_zero_page. So the + * movca.l hits the cache (it is assumed that it misses, or at least + * isn't dirty), modifies the line and then invalidates it, losing the + * required change. + * + * - If caches are disabled or configured in write-through mode, then + * the movca.l writes garbage directly into memory. */ static void __flush_dcache_segment_1way(unsigned long start, unsigned long extent_per_way) @@ -641,6 +655,25 @@ static void __flush_dcache_segment_1way(unsigned long start, } while (a0 < a0e); } +#ifdef CONFIG_CACHE_WRITETHROUGH +/* This method of cache flushing avoids the problems discussed + * in the comment above if writethrough caches are enabled. */ +static void __flush_dcache_segment_2way(unsigned long start, + unsigned long extent_per_way) +{ + unsigned long array_addr; + + array_addr = CACHE_OC_ADDRESS_ARRAY | + (start & cpu_data->dcache.entry_mask); + + while (extent_per_way) { + ctrl_outl(0, array_addr); + ctrl_outl(0, array_addr + cpu_data->dcache.way_incr); + array_addr += cpu_data->dcache.linesz; + extent_per_way -= cpu_data->dcache.linesz; + } +} +#else static void __flush_dcache_segment_2way(unsigned long start, unsigned long extent_per_way) { @@ -699,6 +732,7 @@ static void __flush_dcache_segment_2way(unsigned long start, a1 += linesz; } while (a0 < a0e); } +#endif static void __flush_dcache_segment_4way(unsigned long start, unsigned long extent_per_way) -- cgit From e76a0136a3cf1859fbc07f122e42293d22229558 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 27 Aug 2009 11:31:16 +0900 Subject: sh: Fix up sh4_flush_dcache_page() build on UP. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index e3b77f0fa470..2775f84d9aa3 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -103,8 +103,9 @@ static inline void flush_cache_4096(unsigned long start, * Write back & invalidate the D-cache of the page. * (To avoid "alias" issues) */ -static void sh4_flush_dcache_page(void *page) +static void sh4_flush_dcache_page(void *arg) { + struct page *page = arg; #ifndef CONFIG_SMP struct address_space *mapping = page_mapping(page); -- cgit From ce3f7cb96e67d6518c7fc7b361a76409c3817d64 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Tue, 1 Sep 2009 13:32:48 +0900 Subject: sh: Fix dcache flushing for N-way write-through caches. This adopts the special-cased 2-way write-through dcache flusher for N-ways and moves it in to the generic path. Assignment is done at runtime via the check for the CCR_CACHE_WT bit in the same path as the per-way writeback flushers. Signed-off-by: Matt Fleming Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 397c1030c7a6..b36a9c986a58 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -25,13 +25,14 @@ #define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ #define MAX_ICACHE_PAGES 32 +static void __flush_dcache_segment_writethrough(unsigned long start, + unsigned long extent); static void __flush_dcache_segment_1way(unsigned long start, unsigned long extent); static void __flush_dcache_segment_2way(unsigned long start, unsigned long extent); static void __flush_dcache_segment_4way(unsigned long start, unsigned long extent); - static void __flush_cache_4096(unsigned long addr, unsigned long phys, unsigned long exec_offset); @@ -95,10 +96,17 @@ static void __init emit_cache_params(void) */ void __init p3_cache_init(void) { + unsigned int wt_enabled = !!(__raw_readl(CCR) & CCR_CACHE_WT); + compute_alias(&boot_cpu_data.icache); compute_alias(&boot_cpu_data.dcache); compute_alias(&boot_cpu_data.scache); + if (wt_enabled) { + __flush_dcache_segment_fn = __flush_dcache_segment_writethrough; + goto out; + } + switch (boot_cpu_data.dcache.ways) { case 1: __flush_dcache_segment_fn = __flush_dcache_segment_1way; @@ -114,6 +122,7 @@ void __init p3_cache_init(void) break; } +out: emit_cache_params(); } @@ -607,6 +616,23 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys, * - If caches are disabled or configured in write-through mode, then * the movca.l writes garbage directly into memory. */ +static void __flush_dcache_segment_writethrough(unsigned long start, + unsigned long extent_per_way) +{ + unsigned long addr; + int i; + + addr = CACHE_OC_ADDRESS_ARRAY | (start & cpu_data->dcache.entry_mask); + + while (extent_per_way) { + for (i = 0; i < cpu_data->dcache.ways; i++) + __raw_writel(0, addr + cpu_data->dcache.way_incr * i); + + addr += cpu_data->dcache.linesz; + extent_per_way -= cpu_data->dcache.linesz; + } +} + static void __flush_dcache_segment_1way(unsigned long start, unsigned long extent_per_way) { @@ -655,25 +681,6 @@ static void __flush_dcache_segment_1way(unsigned long start, } while (a0 < a0e); } -#ifdef CONFIG_CACHE_WRITETHROUGH -/* This method of cache flushing avoids the problems discussed - * in the comment above if writethrough caches are enabled. */ -static void __flush_dcache_segment_2way(unsigned long start, - unsigned long extent_per_way) -{ - unsigned long array_addr; - - array_addr = CACHE_OC_ADDRESS_ARRAY | - (start & cpu_data->dcache.entry_mask); - - while (extent_per_way) { - ctrl_outl(0, array_addr); - ctrl_outl(0, array_addr + cpu_data->dcache.way_incr); - array_addr += cpu_data->dcache.linesz; - extent_per_way -= cpu_data->dcache.linesz; - } -} -#else static void __flush_dcache_segment_2way(unsigned long start, unsigned long extent_per_way) { @@ -732,7 +739,6 @@ static void __flush_dcache_segment_2way(unsigned long start, a1 += linesz; } while (a0 < a0e); } -#endif static void __flush_dcache_segment_4way(unsigned long start, unsigned long extent_per_way) -- cgit From 983f4c514c4c9ddac1077a2c805fd16cbe3f7487 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 1 Sep 2009 21:12:55 +0900 Subject: Revert "sh: Kill off now redundant local irq disabling." This reverts commit 64a6d72213dd810dd55bd0a503c36150af41c3c3. Unfortunately we can't use on_each_cpu() for all of the cache ops, as some of them only require preempt disabling. This seems to be the same issue that impacts the mips r4k caches, where this code was based on. This fixes up a deadlock that showed up in some IRQ context cases. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh2a.c | 6 ++++- arch/sh/mm/cache-sh4.c | 61 +++++++++++++++++++++++++++-------------------- arch/sh/mm/cache-sh5.c | 29 +++++++++++++++++----- arch/sh/mm/cache-sh7705.c | 8 +++++++ 4 files changed, 71 insertions(+), 33 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c index d783361e3f0a..975899d83564 100644 --- a/arch/sh/mm/cache-sh2a.c +++ b/arch/sh/mm/cache-sh2a.c @@ -102,10 +102,12 @@ static void sh2a_flush_icache_range(void *args) struct flusher_data *data = args; unsigned long start, end; unsigned long v; + unsigned long flags; start = data->addr1 & ~(L1_CACHE_BYTES-1); end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); + local_irq_save(flags); jump_to_uncached(); for (v = start; v < end; v+=L1_CACHE_BYTES) { @@ -120,10 +122,12 @@ static void sh2a_flush_icache_range(void *args) } } /* I-Cache invalidate */ - ctrl_outl(addr, CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); + ctrl_outl(addr, + CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); } back_to_cached(); + local_irq_restore(flags); } void __init sh2a_cache_init(void) diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 70fb906419dd..3ac4945cb493 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -48,44 +48,48 @@ static void sh4_flush_icache_range(void *args) struct flusher_data *data = args; int icacheaddr; unsigned long start, end; - unsigned long v; + unsigned long flags, v; int i; start = data->addr1; end = data->addr2; - /* If there are too many pages then just blow the caches */ - if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { - local_flush_cache_all(args); - } else { - /* selectively flush d-cache then invalidate the i-cache */ - /* this is inefficient, so only use for small ranges */ - start &= ~(L1_CACHE_BYTES-1); - end += L1_CACHE_BYTES-1; - end &= ~(L1_CACHE_BYTES-1); - - jump_to_uncached(); - - for (v = start; v < end; v+=L1_CACHE_BYTES) { - __ocbwb(v); - - icacheaddr = CACHE_IC_ADDRESS_ARRAY | - (v & cpu_data->icache.entry_mask); - - for (i = 0; i < cpu_data->icache.ways; - i++, icacheaddr += cpu_data->icache.way_incr) - /* Clear i-cache line valid-bit */ - ctrl_outl(0, icacheaddr); - } + /* If there are too many pages then just blow the caches */ + if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { + local_flush_cache_all(args); + } else { + /* selectively flush d-cache then invalidate the i-cache */ + /* this is inefficient, so only use for small ranges */ + start &= ~(L1_CACHE_BYTES-1); + end += L1_CACHE_BYTES-1; + end &= ~(L1_CACHE_BYTES-1); + + local_irq_save(flags); + jump_to_uncached(); + + for (v = start; v < end; v+=L1_CACHE_BYTES) { + asm volatile("ocbwb %0" + : /* no output */ + : "m" (__m(v))); + + icacheaddr = CACHE_IC_ADDRESS_ARRAY | ( + v & cpu_data->icache.entry_mask); + + for (i = 0; i < cpu_data->icache.ways; + i++, icacheaddr += cpu_data->icache.way_incr) + /* Clear i-cache line valid-bit */ + ctrl_outl(0, icacheaddr); + } back_to_cached(); + local_irq_restore(flags); } } static inline void flush_cache_4096(unsigned long start, unsigned long phys) { - unsigned long exec_offset = 0; + unsigned long flags, exec_offset = 0; /* * All types of SH-4 require PC to be in P2 to operate on the I-cache. @@ -95,8 +99,10 @@ static inline void flush_cache_4096(unsigned long start, (start < CACHE_OC_ADDRESS_ARRAY)) exec_offset = 0x20000000; + local_irq_save(flags); __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), exec_offset); + local_irq_restore(flags); } /* @@ -130,8 +136,9 @@ static void sh4_flush_dcache_page(void *arg) /* TODO: Selective icache invalidation through IC address array.. */ static void __uses_jump_to_uncached flush_icache_all(void) { - unsigned long ccr; + unsigned long flags, ccr; + local_irq_save(flags); jump_to_uncached(); /* Flush I-cache */ @@ -143,7 +150,9 @@ static void __uses_jump_to_uncached flush_icache_all(void) * back_to_cached() will take care of the barrier for us, don't add * another one! */ + back_to_cached(); + local_irq_restore(flags); } static inline void flush_dcache_all(void) diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 2f9dd6df00a6..467ff8e260f7 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -34,22 +34,28 @@ static inline void sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, unsigned long paddr) { + local_irq_disable(); sh64_setup_tlb_slot(dtlb_cache_slot, eaddr, asid, paddr); } static inline void sh64_teardown_dtlb_cache_slot(void) { sh64_teardown_tlb_slot(dtlb_cache_slot); + local_irq_enable(); } static inline void sh64_icache_inv_all(void) { unsigned long long addr, flag, data; + unsigned long flags; addr = ICCR0; flag = ICCR0_ICI; data = 0; + /* Make this a critical section for safety (probably not strictly necessary.) */ + local_irq_save(flags); + /* Without %1 it gets unexplicably wrong */ __asm__ __volatile__ ( "getcfg %3, 0, %0\n\t" @@ -58,6 +64,8 @@ static inline void sh64_icache_inv_all(void) "synci" : "=&r" (data) : "0" (data), "r" (flag), "r" (addr)); + + local_irq_restore(flags); } static void sh64_icache_inv_kernel_range(unsigned long start, unsigned long end) @@ -82,6 +90,7 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long Also, eaddr is page-aligned. */ unsigned int cpu = smp_processor_id(); unsigned long long addr, end_addr; + unsigned long flags = 0; unsigned long running_asid, vma_asid; addr = eaddr; end_addr = addr + PAGE_SIZE; @@ -102,9 +111,10 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long running_asid = get_asid(); vma_asid = cpu_asid(cpu, vma->vm_mm); - if (running_asid != vma_asid) + if (running_asid != vma_asid) { + local_irq_save(flags); switch_and_save_asid(vma_asid); - + } while (addr < end_addr) { /* Worth unrolling a little */ __asm__ __volatile__("icbi %0, 0" : : "r" (addr)); @@ -113,9 +123,10 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long __asm__ __volatile__("icbi %0, 96" : : "r" (addr)); addr += 128; } - - if (running_asid != vma_asid) + if (running_asid != vma_asid) { switch_and_save_asid(running_asid); + local_irq_restore(flags); + } } static void sh64_icache_inv_user_page_range(struct mm_struct *mm, @@ -148,12 +159,16 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, unsigned long eaddr; unsigned long after_last_page_start; unsigned long mm_asid, current_asid; + unsigned long flags = 0; mm_asid = cpu_asid(smp_processor_id(), mm); current_asid = get_asid(); - if (mm_asid != current_asid) + if (mm_asid != current_asid) { + /* Switch ASID and run the invalidate loop under cli */ + local_irq_save(flags); switch_and_save_asid(mm_asid); + } aligned_start = start & PAGE_MASK; after_last_page_start = PAGE_SIZE + ((end - 1) & PAGE_MASK); @@ -179,8 +194,10 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, aligned_start = vma->vm_end; /* Skip to start of next region */ } - if (mm_asid != current_asid) + if (mm_asid != current_asid) { switch_and_save_asid(current_asid); + local_irq_restore(flags); + } } } diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 9dc38660e3de..6293f57fa888 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -81,6 +81,7 @@ static void sh7705_flush_icache_range(void *args) static void __flush_dcache_page(unsigned long phys) { unsigned long ways, waysize, addrstart; + unsigned long flags; phys |= SH_CACHE_VALID; @@ -97,6 +98,7 @@ static void __flush_dcache_page(unsigned long phys) * potential cache aliasing, therefore the optimisation is probably not * possible. */ + local_irq_save(flags); jump_to_uncached(); ways = current_cpu_data.dcache.ways; @@ -124,6 +126,7 @@ static void __flush_dcache_page(unsigned long phys) } while (--ways); back_to_cached(); + local_irq_restore(flags); } /* @@ -142,9 +145,14 @@ static void sh7705_flush_dcache_page(void *page) static void sh7705_flush_cache_all(void *args) { + unsigned long flags; + + local_irq_save(flags); jump_to_uncached(); + cache_wback_all(); back_to_cached(); + local_irq_restore(flags); } /* -- cgit From 6f3795788b030c3c190fa063adfe519e016cc6fd Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 1 Sep 2009 21:21:36 +0900 Subject: sh: Fix up UP deadlock with SMP-aware cache ops. This builds on top of the previous reversion and implements a special on_each_cpu() variant that simple disables preemption across the call while leaving the interrupt state to the function itself. There were some unintended consequences with IRQ disabling in some of these paths on UP that ran in to a deadlock scenario with IRQs being missed. Signed-off-by: Paul Mundt --- arch/sh/mm/cache.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index 411fe6058429..db2b1c5beffd 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -34,6 +34,15 @@ static inline void noop__flush_region(void *start, int size) { } +static inline void cacheop_on_each_cpu(void (*func) (void *info), void *info, + int wait) +{ + preempt_disable(); + smp_call_function(func, info, wait); + func(info); + preempt_enable(); +} + void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long vaddr, void *dst, const void *src, unsigned long len) @@ -149,17 +158,17 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) void flush_cache_all(void) { - on_each_cpu(local_flush_cache_all, NULL, 1); + cacheop_on_each_cpu(local_flush_cache_all, NULL, 1); } void flush_cache_mm(struct mm_struct *mm) { - on_each_cpu(local_flush_cache_mm, mm, 1); + cacheop_on_each_cpu(local_flush_cache_mm, mm, 1); } void flush_cache_dup_mm(struct mm_struct *mm) { - on_each_cpu(local_flush_cache_dup_mm, mm, 1); + cacheop_on_each_cpu(local_flush_cache_dup_mm, mm, 1); } void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, @@ -171,7 +180,7 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, data.addr1 = addr; data.addr2 = pfn; - on_each_cpu(local_flush_cache_page, (void *)&data, 1); + cacheop_on_each_cpu(local_flush_cache_page, (void *)&data, 1); } void flush_cache_range(struct vm_area_struct *vma, unsigned long start, @@ -183,12 +192,12 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, data.addr1 = start; data.addr2 = end; - on_each_cpu(local_flush_cache_range, (void *)&data, 1); + cacheop_on_each_cpu(local_flush_cache_range, (void *)&data, 1); } void flush_dcache_page(struct page *page) { - on_each_cpu(local_flush_dcache_page, page, 1); + cacheop_on_each_cpu(local_flush_dcache_page, page, 1); } void flush_icache_range(unsigned long start, unsigned long end) @@ -199,18 +208,18 @@ void flush_icache_range(unsigned long start, unsigned long end) data.addr1 = start; data.addr2 = end; - on_each_cpu(local_flush_icache_range, (void *)&data, 1); + cacheop_on_each_cpu(local_flush_icache_range, (void *)&data, 1); } void flush_icache_page(struct vm_area_struct *vma, struct page *page) { /* Nothing uses the VMA, so just pass the struct page along */ - on_each_cpu(local_flush_icache_page, page, 1); + cacheop_on_each_cpu(local_flush_icache_page, page, 1); } void flush_cache_sigtramp(unsigned long address) { - on_each_cpu(local_flush_cache_sigtramp, (void *)address, 1); + cacheop_on_each_cpu(local_flush_cache_sigtramp, (void *)address, 1); } static void compute_alias(struct cache_info *c) -- cgit From 0906a3ad33a254094fb74828e3ddb9af8771a6da Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 3 Sep 2009 17:21:10 +0900 Subject: sh: Fix up and optimize the kmap_coherent() interface. This fixes up the kmap_coherent/kunmap_coherent() interface for recent changes both in the page fault path and the shared cache flushers, as well as adding in some optimizations. One of the key things to note here is that the TLB flush itself is deferred until the unmap, and the call in to update_mmu_cache() itself goes away, relying on the regular page fault path to handle the lazy dcache writeback if necessary. Signed-off-by: Paul Mundt --- arch/sh/mm/cache.c | 8 ++++---- arch/sh/mm/fault_32.c | 4 ++-- arch/sh/mm/init.c | 45 +++++++++++++++++++++++++-------------------- arch/sh/mm/kmap.c | 36 +++++++++++++++++------------------- arch/sh/mm/nommu.c | 2 +- 5 files changed, 49 insertions(+), 46 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index db2b1c5beffd..8e4a8d1ac4a9 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -51,7 +51,7 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page, !test_bit(PG_dcache_dirty, &page->flags)) { void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(vto, src, len); - kunmap_coherent(); + kunmap_coherent(vto); } else { memcpy(dst, src, len); if (boot_cpu_data.dcache.n_aliases) @@ -70,7 +70,7 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page, !test_bit(PG_dcache_dirty, &page->flags)) { void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); memcpy(dst, vfrom, len); - kunmap_coherent(); + kunmap_coherent(vfrom); } else { memcpy(dst, src, len); if (boot_cpu_data.dcache.n_aliases) @@ -89,7 +89,7 @@ void copy_user_highpage(struct page *to, struct page *from, !test_bit(PG_dcache_dirty, &from->flags)) { vfrom = kmap_coherent(from, vaddr); copy_page(vto, vfrom); - kunmap_coherent(); + kunmap_coherent(vfrom); } else { vfrom = kmap_atomic(from, KM_USER0); copy_page(vto, vfrom); @@ -150,7 +150,7 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) kaddr = kmap_coherent(page, vmaddr); __flush_wback_region((void *)kaddr, PAGE_SIZE); - kunmap_coherent(); + kunmap_coherent(kaddr); } else __flush_wback_region((void *)addr, PAGE_SIZE); } diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index f1c93c880ed4..781b413ff82d 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -82,8 +82,8 @@ static noinline int vmalloc_fault(unsigned long address) pmd_t *pmd_k; pte_t *pte_k; - /* Make sure we are in vmalloc area: */ - if (!(address >= VMALLOC_START && address < VMALLOC_END)) + /* Make sure we are in vmalloc/module/P3 area: */ + if (!(address >= VMALLOC_START && address < P3_ADDR_MAX)) return -1; /* diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 0a9b4d855bc9..edc842ff61ed 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -106,27 +106,31 @@ void __init page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd; pud_t *pud; pmd_t *pmd; - int pgd_idx; + pte_t *pte; + int i, j, k; unsigned long vaddr; - vaddr = start & PMD_MASK; - end = (end + PMD_SIZE - 1) & PMD_MASK; - pgd_idx = pgd_index(vaddr); - pgd = pgd_base + pgd_idx; - - for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - BUG_ON(pgd_none(*pgd)); - pud = pud_offset(pgd, 0); - BUG_ON(pud_none(*pud)); - pmd = pmd_offset(pud, 0); - - if (!pmd_present(*pmd)) { - pte_t *pte_table; - pte_table = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE); - pmd_populate_kernel(&init_mm, pmd, pte_table); + vaddr = start; + i = __pgd_offset(vaddr); + j = __pud_offset(vaddr); + k = __pmd_offset(vaddr); + pgd = pgd_base + i; + + for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) { + pud = (pud_t *)pgd; + for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) { + pmd = (pmd_t *)pud; + for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { + if (pmd_none(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + pmd_populate_kernel(&init_mm, pmd, pte); + BUG_ON(pte != pte_offset_kernel(pmd, 0)); + } + vaddr += PMD_SIZE; + } + k = 0; } - - vaddr += PMD_SIZE; + j = 0; } } #endif /* CONFIG_MMU */ @@ -137,7 +141,7 @@ void __init page_table_range_init(unsigned long start, unsigned long end, void __init paging_init(void) { unsigned long max_zone_pfns[MAX_NR_ZONES]; - unsigned long vaddr; + unsigned long vaddr, end; int nid; /* We don't need to map the kernel through the TLB, as @@ -155,7 +159,8 @@ void __init paging_init(void) * pte's will be filled in by __set_fixmap(). */ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - page_table_range_init(vaddr, 0, swapper_pg_dir); + end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK; + page_table_range_init(vaddr, end, swapper_pg_dir); kmap_coherent_init(); diff --git a/arch/sh/mm/kmap.c b/arch/sh/mm/kmap.c index 3eecf0d42f1a..c52cd8c40a64 100644 --- a/arch/sh/mm/kmap.c +++ b/arch/sh/mm/kmap.c @@ -24,9 +24,6 @@ void __init kmap_coherent_init(void) { unsigned long vaddr; - if (!boot_cpu_data.dcache.n_aliases) - return; - /* cache the first coherent kmap pte */ vaddr = __fix_to_virt(FIX_CMAP_BEGIN); kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); @@ -35,30 +32,31 @@ void __init kmap_coherent_init(void) void *kmap_coherent(struct page *page, unsigned long addr) { enum fixed_addresses idx; - unsigned long vaddr, flags; - pte_t pte; + unsigned long vaddr; BUG_ON(test_bit(PG_dcache_dirty, &page->flags)); - inc_preempt_count(); - - idx = (addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT; - vaddr = __fix_to_virt(FIX_CMAP_END - idx); - pte = mk_pte(page, PAGE_KERNEL); + pagefault_disable(); - local_irq_save(flags); - flush_tlb_one(get_asid(), vaddr); - local_irq_restore(flags); + idx = FIX_CMAP_END - + ((addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT); + vaddr = __fix_to_virt(idx); - update_mmu_cache(NULL, vaddr, pte); - - set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte); + BUG_ON(!pte_none(*(kmap_coherent_pte - idx))); + set_pte(kmap_coherent_pte - idx, mk_pte(page, PAGE_KERNEL)); return (void *)vaddr; } -void kunmap_coherent(void) +void kunmap_coherent(void *kvaddr) { - dec_preempt_count(); - preempt_check_resched(); + if (kvaddr >= (void *)FIXADDR_START) { + unsigned long vaddr = (unsigned long)kvaddr & PAGE_MASK; + enum fixed_addresses idx = __virt_to_fix(vaddr); + + pte_clear(&init_mm, vaddr, kmap_coherent_pte - idx); + local_flush_tlb_one(get_asid(), vaddr); + } + + pagefault_enable(); } diff --git a/arch/sh/mm/nommu.c b/arch/sh/mm/nommu.c index 51b54037216f..ac16c05917ef 100644 --- a/arch/sh/mm/nommu.c +++ b/arch/sh/mm/nommu.c @@ -81,7 +81,7 @@ void *kmap_coherent(struct page *page, unsigned long addr) return NULL; } -void kunmap_coherent(void) +void kunmap_coherent(void *kvaddr) { BUG(); } -- cgit From 6e4154d4c2dd3d7e61d19ddd2527322ce34c2f5a Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 8 Sep 2009 16:21:00 +0900 Subject: sh: Use more aggressive dcache purging in kmap teardown. This fixes up a number of outstanding issues observed with old mappings on the same colour hanging around. This requires some more optimal handling, but is a safe fallback until all of the corner cases have been handled. Signed-off-by: Paul Mundt --- arch/sh/mm/cache.c | 11 ++++++----- arch/sh/mm/kmap.c | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index 8e4a8d1ac4a9..35c37b7f717a 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -97,7 +97,7 @@ void copy_user_highpage(struct page *to, struct page *from, } if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) - __flush_wback_region(vto, PAGE_SIZE); + __flush_purge_region(vto, PAGE_SIZE); kunmap_atomic(vto, KM_USER1); /* Make sure this page is cleared on other CPU's too before using it */ @@ -112,7 +112,7 @@ void clear_user_highpage(struct page *page, unsigned long vaddr) clear_page(kaddr); if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) - __flush_wback_region(kaddr, PAGE_SIZE); + __flush_purge_region(kaddr, PAGE_SIZE); kunmap_atomic(kaddr, KM_USER0); } @@ -134,7 +134,7 @@ void __update_cache(struct vm_area_struct *vma, unsigned long addr = (unsigned long)page_address(page); if (pages_do_alias(addr, address & PAGE_MASK)) - __flush_wback_region((void *)addr, PAGE_SIZE); + __flush_purge_region((void *)addr, PAGE_SIZE); } } } @@ -149,10 +149,11 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) void *kaddr; kaddr = kmap_coherent(page, vmaddr); - __flush_wback_region((void *)kaddr, PAGE_SIZE); + /* XXX.. For now kunmap_coherent() does a purge */ + /* __flush_purge_region((void *)kaddr, PAGE_SIZE); */ kunmap_coherent(kaddr); } else - __flush_wback_region((void *)addr, PAGE_SIZE); + __flush_purge_region((void *)addr, PAGE_SIZE); } } diff --git a/arch/sh/mm/kmap.c b/arch/sh/mm/kmap.c index c52cd8c40a64..16e01b5fed04 100644 --- a/arch/sh/mm/kmap.c +++ b/arch/sh/mm/kmap.c @@ -54,6 +54,9 @@ void kunmap_coherent(void *kvaddr) unsigned long vaddr = (unsigned long)kvaddr & PAGE_MASK; enum fixed_addresses idx = __virt_to_fix(vaddr); + /* XXX.. Kill this later, here for sanity at the moment.. */ + __flush_purge_region((void *)vaddr, PAGE_SIZE); + pte_clear(&init_mm, vaddr, kmap_coherent_pte - idx); local_flush_tlb_one(get_asid(), vaddr); } -- cgit From 682f88ab74e55dae55ea3bf30b46f56f71b793bd Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 9 Sep 2009 13:19:46 +0900 Subject: sh: Cleanup whitespace damage in sh4_flush_icache_range(). There was quite a lot of tab->space damage done here from a former patch, clean it up once and for all. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh4.c | 63 ++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 30 deletions(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 3ac4945cb493..b2453bbef4cd 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -46,7 +46,6 @@ static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) = static void sh4_flush_icache_range(void *args) { struct flusher_data *data = args; - int icacheaddr; unsigned long start, end; unsigned long flags, v; int i; @@ -54,36 +53,40 @@ static void sh4_flush_icache_range(void *args) start = data->addr1; end = data->addr2; - /* If there are too many pages then just blow the caches */ - if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { - local_flush_cache_all(args); - } else { - /* selectively flush d-cache then invalidate the i-cache */ - /* this is inefficient, so only use for small ranges */ - start &= ~(L1_CACHE_BYTES-1); - end += L1_CACHE_BYTES-1; - end &= ~(L1_CACHE_BYTES-1); - - local_irq_save(flags); - jump_to_uncached(); - - for (v = start; v < end; v+=L1_CACHE_BYTES) { - asm volatile("ocbwb %0" - : /* no output */ - : "m" (__m(v))); - - icacheaddr = CACHE_IC_ADDRESS_ARRAY | ( - v & cpu_data->icache.entry_mask); - - for (i = 0; i < cpu_data->icache.ways; - i++, icacheaddr += cpu_data->icache.way_incr) - /* Clear i-cache line valid-bit */ - ctrl_outl(0, icacheaddr); - } - - back_to_cached(); - local_irq_restore(flags); + /* If there are too many pages then just blow away the caches */ + if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { + local_flush_cache_all(NULL); + return; + } + + /* + * Selectively flush d-cache then invalidate the i-cache. + * This is inefficient, so only use this for small ranges. + */ + start &= ~(L1_CACHE_BYTES-1); + end += L1_CACHE_BYTES-1; + end &= ~(L1_CACHE_BYTES-1); + + local_irq_save(flags); + jump_to_uncached(); + + for (v = start; v < end; v += L1_CACHE_BYTES) { + unsigned long icacheaddr; + + __ocbwb(v); + + icacheaddr = CACHE_IC_ADDRESS_ARRAY | (v & + cpu_data->icache.entry_mask); + + /* Clear i-cache line valid-bit */ + for (i = 0; i < cpu_data->icache.ways; i++) { + __raw_writel(0, icacheaddr); + icacheaddr += cpu_data->icache.way_incr; + } } + + back_to_cached(); + local_irq_restore(flags); } static inline void flush_cache_4096(unsigned long start, -- cgit From c8c2df9055074197ba12902c6d7e840667fb56d6 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 15 Sep 2009 09:47:35 +0900 Subject: sh: Fix up sh7705 flush_dcache_page() build. Type mismatch caused the page deref to blow up, fix it up as per the sh4 change. Signed-off-by: Paul Mundt --- arch/sh/mm/cache-sh7705.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/sh/mm') diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 6293f57fa888..2cadee2037ac 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -133,8 +133,9 @@ static void __flush_dcache_page(unsigned long phys) * Write back & invalidate the D-cache of the page. * (To avoid "alias" issues) */ -static void sh7705_flush_dcache_page(void *page) +static void sh7705_flush_dcache_page(void *arg) { + struct page *page = arg; struct address_space *mapping = page_mapping(page); if (mapping && !mapping_mapped(mapping)) -- cgit