From: NIIBE Y. <gn...@m1...> - 2001-08-06 09:21:17
|
OK, with this patch, I've finally got reliable implementation. Some clean up is still needed, but I think that all the bugs are gone. I've changed the logic to defer the actual flusing. I've introduced, PG_mapped_with_alias flag. This flag will be set at update_mmu_cache, if it maps with the address of alias. We can do this, because all the vma areas are aligned to 16KB. The flag will be cleard when the PTE gets cleared. * include/asm-sh/pgtable.h (PG_mapped_with_alias): New macro. (PG_dcache_dirty: Deleted. (ptep_get_and_clear, ptep_test_and_clear_young, ptep_test_and_clear_dirty, ptep_set_wrprotect, ptep_mkdirty, pte_same): Define here (was: included by <asm-generic/pgtable.h>). * arch/sh/mm/cache-sh4.c (flush_dcache_page): New implementation. Check if it's mapped or not. (ptep_get_and_clear): New function (was: generic implementation). * arch/sh/mm/fault.c (update_mmu_cache): Flush the cache when it's mapped at first, and mark the page as it's mapped. Bug fix: check the page is VALID or not. * arch/sh/mm/cache-sh4.c (CACHE_ALIAS): Moved to ... * include/asm-sh/pgtable.h (CACHE_ALIAS): ... here. Index: arch/sh/mm/cache-sh4.c =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/cache-sh4.c,v retrieving revision 1.10 diff -u -p -r1.10 cache-sh4.c --- arch/sh/mm/cache-sh4.c 2001/08/06 02:19:56 1.10 +++ arch/sh/mm/cache-sh4.c 2001/08/06 09:05:45 @@ -41,9 +41,6 @@ #define CACHE_IC_NUM_ENTRIES 256 #define CACHE_OC_NUM_ENTRIES 512 -/* Page is 4K, OC size is 16K, there are four lines. */ -#define CACHE_ALIAS 0x00003000 - static void __init detect_cpu_and_cache_system(void) { @@ -206,7 +203,7 @@ void __flush_cache_page(unsigned long ph unsigned long addr, data; unsigned long flags; - phys|=CACHE_VALID; + phys |= CACHE_VALID; save_and_cli(flags); jump_to_P2(); @@ -274,19 +271,10 @@ void __flush_icache_page(unsigned long u * Write back & invalidate the I/D-cache of the page. * (To avoid "alias" issues) */ -void flush_dcache_page(struct page *pg) +void flush_dcache_page(struct page *page) { - if (!pg->mapping - || pg->mapping->i_mmap || pg->mapping->i_mmap_shared) { - unsigned long phys; - - phys = PHYSADDR(page_address(pg)); - if (pg->mapping) - __flush_cache_page(phys, 1); - else - __flush_cache_page(phys, 0); - } else - set_bit(PG_dcache_dirty, &pg->flags); + if (test_bit(PG_mapped_with_alias, &page->flags)) + __flush_cache_page(PHYSADDR(page_address(page)), 1); } void flush_cache_all(void) @@ -535,4 +523,18 @@ void copy_user_page(void *to, void *from pte_clear(pte); up(&p3map_sem[(address & CACHE_ALIAS)>>12]); } +} + +pte_t ptep_get_and_clear(pte_t *ptep) +{ + pte_t pte = *ptep; + + if (!pte_not_present(pte)) { + struct page *page = pte_page(pte); + if (VALID_PAGE(page)&& + (!page->mapping || !(page->mapping->i_mmap_shared))) + __clear_bit(PG_mapped_with_alias, &page->flags); + } + pte_clear(ptep); + return pte; } Index: arch/sh/mm/fault.c =================================================================== RCS file: /cvsroot/linuxsh/kernel/arch/sh/mm/fault.c,v retrieving revision 1.44 diff -u -p -r1.44 fault.c --- arch/sh/mm/fault.c 2001/07/18 04:27:38 1.44 +++ arch/sh/mm/fault.c 2001/08/06 09:05:45 @@ -290,15 +290,15 @@ void update_mmu_cache(struct vm_area_str return; #if defined(__SH4__) - page = pte_page(pte); - - if (__test_and_clear_bit(PG_dcache_dirty, &page->flags)) - if (page->mapping) { - unsigned long phys; - /* Physical address of this page */ - phys = PHYSADDR(pte_val(pte)&PAGE_MASK); + if ((address ^ pte_val(pte)) & CACHE_ALIAS) { + page = pte_page(pte); + if (VALID_PAGE(page) && + !test_bit(PG_mapped_with_alias, &page->flags)) { + unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; __flush_cache_page(phys, 1); + set_bit(PG_mapped_with_alias, &page->flags); } + } #endif save_and_cli(flags); Index: include/asm-sh/pgtable.h =================================================================== RCS file: /cvsroot/linuxsh/kernel/include/asm-sh/pgtable.h,v retrieving revision 1.40 diff -u -p -r1.40 pgtable.h --- include/asm-sh/pgtable.h 2001/08/05 01:54:18 1.40 +++ include/asm-sh/pgtable.h 2001/08/06 09:05:47 @@ -75,6 +75,11 @@ extern void __flush_icache_page(unsigned /* Initialization of P3 area for copy_user_page */ extern void p3_cache_init(void); + +#define PG_mapped_with_alias PG_arch_1 + +/* We provide our own get_unmapped_area to avoid cache alias issue */ +#define HAVE_ARCH_UNMAPPED_AREA #endif /* @@ -290,9 +295,60 @@ extern void update_mmu_cache(struct vm_a * * We just can use generic implementation, as SuperH has no SMP feature. * (We needed atomic implementation for SMP) + * */ -#include <asm-generic/pgtable.h> +#if defined(__SH4__) +/* Page is 4K, OC size is 16K, there are four lines. */ +#define CACHE_ALIAS 0x00003000 +/* + * For SH-4, we have our own implementation for ptep_get_and_clear + */ +extern pte_t ptep_get_and_clear(pte_t *ptep); +#else +static inline pte_t ptep_get_and_clear(pte_t *ptep) +{ + pte_t pte = *ptep; + pte_clear(ptep); + return pte; +} +#endif + +/* + * Following functions are same as generic ones. + */ +static inline int ptep_test_and_clear_young(pte_t *ptep) +{ + pte_t pte = *ptep; + if (!pte_young(pte)) + return 0; + set_pte(ptep, pte_mkold(pte)); + return 1; +} + +static inline int ptep_test_and_clear_dirty(pte_t *ptep) +{ + pte_t pte = *ptep; + if (!pte_dirty(pte)) + return 0; + set_pte(ptep, pte_mkclean(pte)); + return 1; +} + +static inline void ptep_set_wrprotect(pte_t *ptep) +{ + pte_t old_pte = *ptep; + set_pte(ptep, pte_wrprotect(old_pte)); +} + +static inline void ptep_mkdirty(pte_t *ptep) +{ + pte_t old_pte = *ptep; + set_pte(ptep, pte_mkdirty(old_pte)); +} + +#define pte_same(A,B) (pte_val(A) == pte_val(B)) + #endif /* !__ASSEMBLY__ */ /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ @@ -300,12 +356,5 @@ extern void update_mmu_cache(struct vm_a #define kern_addr_valid(addr) (1) #define io_remap_page_range remap_page_range - -#if defined(__SH4__) -#define PG_dcache_dirty PG_arch_1 - -/* We provide our own get_unmapped_area to avoid cache alias issue */ -#define HAVE_ARCH_UNMAPPED_AREA -#endif #endif /* __ASM_SH_PAGE_H */ -- |