Changelog * Extend flush_dcache page to flush compound pages. * Attempt to find a solution for sh3 and sh4's huge_update_mmu_cache which is likely very wrong. * Not built and not tested. This is the archicture I know the least about. Index: linux-2.6.9/include/asm-sh/pgtable.h =================================================================== --- linux-2.6.9.orig/include/asm-sh/pgtable.h 2004-10-21 12:01:24.000000000 -0700 +++ linux-2.6.9/include/asm-sh/pgtable.h 2004-10-25 15:05:33.000000000 -0700 @@ -249,6 +249,8 @@ struct vm_area_struct; extern void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte); +extern void huge_update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte); /* Encode and de-code a swap entry */ /* Index: linux-2.6.9/arch/sh/mm/cache-sh4.c =================================================================== --- linux-2.6.9.orig/arch/sh/mm/cache-sh4.c 2004-10-21 12:01:21.000000000 -0700 +++ linux-2.6.9/arch/sh/mm/cache-sh4.c 2004-10-25 15:18:53.000000000 -0700 @@ -206,13 +206,25 @@ void flush_dcache_page(struct page *page) { if (test_bit(PG_mapped, &page->flags)) { - unsigned long phys = PHYSADDR(page_address(page)); + unsigned long phys; + int nr = 1; - /* Loop all the D-cache */ - flush_cache_4096(CACHE_OC_ADDRESS_ARRAY, phys); - flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x1000, phys); - flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x2000, phys); - flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x3000, phys); + if (CompoundPage(page)) { + page = page->private; + nr = 1 << page[1].index; + } + + phys = PHYSADDR(page_address(page)); + + while (nr-- > 0) { + /* Loop all the D-cache */ + flush_cache_4096(CACHE_OC_ADDRESS_ARRAY, phys); + flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x1000, phys); + flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x2000, phys); + flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x3000, phys); + + phys += PAGE_SIZE; + } } } Index: linux-2.6.9/arch/sh/mm/tlb-nommu.c =================================================================== --- linux-2.6.9.orig/arch/sh/mm/tlb-nommu.c 2004-10-18 14:54:27.000000000 -0700 +++ linux-2.6.9/arch/sh/mm/tlb-nommu.c 2004-10-25 15:06:56.000000000 -0700 @@ -55,4 +55,9 @@ { BUG(); } +void huge_update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + BUG(); +} Index: linux-2.6.9/arch/sh/mm/cache-sh7705.c =================================================================== --- linux-2.6.9.orig/arch/sh/mm/cache-sh7705.c 2004-10-21 12:01:21.000000000 -0700 +++ linux-2.6.9/arch/sh/mm/cache-sh7705.c 2004-10-25 15:23:46.000000000 -0700 @@ -135,8 +135,22 @@ */ void flush_dcache_page(struct page *page) { - if (test_bit(PG_mapped, &page->flags)) - __flush_dcache_page(PHYSADDR(page_address(page))); + if (test_bit(PG_mapped, &page->flags)) { + if (!CompoundPage(page)) + __flush_dcache_page(PHYSADDR(page_address(page))); + else { + int nr; + unsigned long phy = PHYSADDR(page_address(page)); + + page = page->private; + nr = 1 << page[1].index; + + while (nr-- >0) { + __flush_dcache_page(phys); + phys += PAGE_SIZE; + } + } + } } void flush_cache_all(void) Index: linux-2.6.9/arch/sh/mm/tlb-sh3.c =================================================================== --- linux-2.6.9.orig/arch/sh/mm/tlb-sh3.c 2004-10-21 12:01:21.000000000 -0700 +++ linux-2.6.9/arch/sh/mm/tlb-sh3.c 2004-10-25 15:13:00.000000000 -0700 @@ -67,6 +67,48 @@ local_irq_restore(flags); } +void huge_update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + unsigned long flags; + unsigned long pteval; + unsigned long vpn; + + /* Ptrace may call this routine. */ + if (vma && current->active_mm != vma->vm_mm) + return; + +#if defined(CONFIG_SH7705_CACHE_32KB) + struct page *page; + page = pte_page(pte); + if (VALID_PAGE(page) && !test_bit(PG_mapped, &page->flags)) { + unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; + __flush_wback_region((void *)P1SEGADDR(phys), HPAGE_SIZE); + __set_bit(PG_mapped, &page->flags); + } +#endif + + local_irq_save(flags); + + /* FIXME: What exactly does the code below do? pte mapping ? */ + + /* Set PTEH register */ + vpn = (address & MMU_VPN_MASK) | get_asid(); + ctrl_outl(vpn, MMU_PTEH); + + pteval = pte_val(pte); + + /* Set PTEL register */ + pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ + /* conveniently, we want all the software flags to be 0 anyway */ + ctrl_outl(pteval, MMU_PTEL); + + /* Load the TLB */ + asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); + local_irq_restore(flags); +} + + void __flush_tlb_page(unsigned long asid, unsigned long page) { unsigned long addr, data; Index: linux-2.6.9/arch/sh/mm/tlb-sh4.c =================================================================== --- linux-2.6.9.orig/arch/sh/mm/tlb-sh4.c 2004-10-18 14:54:38.000000000 -0700 +++ linux-2.6.9/arch/sh/mm/tlb-sh4.c 2004-10-25 15:14:46.000000000 -0700 @@ -28,6 +28,56 @@ #include #include +void huge_update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + unsigned long flags; + unsigned long pteval; + unsigned long vpn; + struct page *page; + unsigned long pfn; + unsigned long ptea; + + /* Ptrace may call this routine. */ + if (vma && current->active_mm != vma->vm_mm) + return; + + pfn = pte_pfn(pte); + if (pfn_valid(pfn)) { + 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), HPAGE_SIZE); + __set_bit(PG_mapped, &page->flags); + } + } + + /* FIXME: code below likely needs to be fixed up for huge pages */ + local_irq_save(flags); + + /* Set PTEH register */ + vpn = (address & MMU_VPN_MASK) | get_asid(); + ctrl_outl(vpn, MMU_PTEH); + + pteval = pte_val(pte); + /* Set PTEA register */ + /* TODO: make this look less hacky */ + ptea = ((pteval >> 28) & 0xe) | (pteval & 0x1); + ctrl_outl(ptea, MMU_PTEA); + + /* Set PTEL register */ + pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ +#ifdef CONFIG_SH_WRITETHROUGH + pteval |= _PAGE_WT; +#endif + /* conveniently, we want all the software flags to be 0 anyway */ + ctrl_outl(pteval, MMU_PTEL); + + /* Load the TLB */ + asm volatile("ldtlb": /* no output */ : /* no input */ : "memory"); + local_irq_restore(flags); +} + void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) {