[xtensa-cvscommit] linux/arch/xtensa/mm cache.c,1.4,1.5 fault.c,1.4,1.5 mmu.c,1.5,1.6
Brought to you by:
zankel
|
From: <jn...@us...> - 2003-02-28 01:53:27
|
Update of /cvsroot/xtensa/linux/arch/xtensa/mm
In directory sc8-pr-cvs1:/tmp/cvs-serv6560/arch/xtensa/mm
Modified Files:
cache.c fault.c mmu.c
Log Message:
Added support for caches that have "ways" larger than PAGE_SIZE.
This was mostly copied from the sh-4 port which suffers from the
same feature. There are still some optimizations that can be done
with regard to defering some cache flusing, and reducing some complete
cache flushes to flushes of the appropriate cache lines.
When the cache way size is less than or equal to PAGE_SIZE, all
of these changes should be optimized away, and the port should run
exactly as it did prior to these changes.
Index: cache.c
===================================================================
RCS file: /cvsroot/xtensa/linux/arch/xtensa/mm/cache.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** cache.c 7 Feb 2003 01:49:06 -0000 1.4
--- cache.c 28 Feb 2003 01:53:09 -0000 1.5
***************
*** 32,42 ****
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <xtensa/hal.h>
! #if XCHAL_DCACHE_IS_WRITEBACK
void flush_cache_all(void)
--- 32,47 ----
#include <linux/sched.h>
#include <linux/mm.h>
+ #include <linux/init.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <xtensa/hal.h>
+ #include <asm/page.h>
+
+
!
! #if (XCHAL_DCACHE_IS_WRITEBACK > 0) || (XTENSA_CACHE_ALIAS > 0)
void flush_cache_all(void)
***************
*** 110,113 ****
--- 115,119 ----
pte_t *ptep;
+
/*
* If owns no valid ASID yet, cannot possibly have gotten
***************
*** 168,176 ****
--- 174,234 ----
}
+
+ #endif /* #if XCHAL_DCACHE_IS_WRITEBACK */
+
+
+
+
+
+
+
+ /* 20feb2003 -- jn
+ * some subset of these functions need to be available when
+ * cache aliasing is a problem and when the cache is writeback.
+ */
+
+ #if (XTENSA_CACHE_ALIAS || XCHALDCACHE_IS_WRITEBACK)
+
+ void flush_page_to_ram (struct page *page)
+ {
+ unsigned long addr = (unsigned long) page_address(page);
+ unsigned long flags;
+ save_and_cli(flags);
+ xthal_dcache_region_writeback_inv((void *)addr, PAGE_SIZE);
+ restore_flags(flags);
+ }
+
+
+ void flush_dcache_page (struct page *page)
+ {
+ unsigned long addr = (unsigned long) page_address(page);
+ unsigned long flags;
+ save_and_cli(flags);
+ #if 1
+ #if defined(XCHALDCACHE_IS_WRITEBACK)
+ xthal_dcache_region_writeback_inv((void *)addr, PAGE_SIZE);
+ #else
+ xthal_dcache_region_invalidate((void *)addr, PAGE_SIZE);
+ #endif
+ #else
+ /* XTFIXME -- this is just a test, going to flush the entire cache
+ * cache and see if that makes it start working.
+ */
+ // printk("flush_dcache_page: addr=0x%08x\n", addr);
+ xthal_dcache_all_writeback_inv();
+ #endif
+
+ restore_flags(flags);
+ }
+
void flush_icache_range(unsigned long start, unsigned long end)
{
unsigned long flags;
save_and_cli(flags);
+ #if defined(XCHALDCACHE_IS_WRITEBACK)
xthal_dcache_region_writeback_inv((void *)start, end - start);
+ #else
+ xthal_dcache_region_invalidate((void*)start, end - start);
+ #endif
xthal_icache_region_invalidate((void *)start, end - start);
restore_flags(flags);
***************
*** 200,223 ****
}
! void flush_page_to_ram (struct page *page)
{
! unsigned long addr = (unsigned long) page_address(page);
! unsigned long flags;
! save_and_cli(flags);
! xthal_dcache_region_writeback_inv((void *)addr, PAGE_SIZE);
! restore_flags(flags);
}
! /* Define only if dcache aliasing is a problem. It currently is not. */
#if 0
! void flush_dcache_page (struct page *page)
{
! unsigned long addr = (unsigned long) page_address(page);
! unsigned long flags;
! save_and_cli(flags);
! xthal_dcache_region_writeback_inv((void *)addr, PAGE_SIZE);
! restore_flags(flags);
}
- #endif
! #endif /* #if XCHAL_DCACHE_IS_WRITEBACK */
--- 258,342 ----
}
! #endif
!
!
!
! /* 20feb2003 -- jn
! * When the cache has the aliasing feature enabled, then we need to
! * implement a couple of special functions to keep the world at
! * large in peace and harmony.
! */
! #if XTENSA_CACHE_ALIAS
!
! static struct semaphore dealias_page_sem;
!
! void clear_user_page(void *to, unsigned long address)
{
! if ( (( (unsigned long)to ^ address) & XT_CACHE_ALIAS_BITS) == 0) {
! clear_page(to);
! } else {
! struct page *topage = virt_to_page(to);
!
! unsigned long new_to = (XTENSA_ALIAS_RESERVE_START);
! unsigned long vpnval;
! pte_t pteval;
!
! new_to = new_to + (address & XT_CACHE_ALIAS_BITS);
! vpnval = new_to + WIRED_WAY_FOR_COPY_USER_PAGE;
! pteval = mk_pte( topage, PAGE_KERNEL);
! down(&dealias_page_sem);
! write_dtlb_entry(pteval, vpnval);
! clear_page((void *)new_to);
! up(&dealias_page_sem);
! }
}
!
!
!
!
! void copy_user_page(void *to, void *from, unsigned long address)
! {
! struct page *topage = virt_to_page(to);
!
!
! set_bit(PG_mapped, &topage->flags);
!
! if (( (address ^ (unsigned long)to) & XT_CACHE_ALIAS_BITS) == 0) {
! copy_page(to, from);
! } else {
#if 0
! copy_page(to, from);
! flush_cache_all();
! #else
! unsigned long new_to = (XTENSA_ALIAS_RESERVE_START);
! unsigned long vpnval;
! pte_t pteval;
!
! new_to = new_to + (address & XT_CACHE_ALIAS_BITS);
! vpnval = new_to + WIRED_WAY_FOR_COPY_USER_PAGE;
! pteval = mk_pte( topage, PAGE_KERNEL);
! down(&dealias_page_sem);
! write_dtlb_entry(pteval, vpnval);
! copy_page((void *)new_to, from);
! up(&dealias_page_sem);
! #endif
! }
! }
!
!
! /* Have to init some pages that can be used as to "de-alias" the cache */
!
! void __init xtensa_cache_init(void)
{
! sema_init(&dealias_page_sem, 1);
}
!
! #endif /* XTENSA_CACHE_ALIAS */
!
!
!
!
!
!
Index: fault.c
===================================================================
RCS file: /cvsroot/xtensa/linux/arch/xtensa/mm/fault.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** fault.c 13 Feb 2003 18:19:21 -0000 1.4
--- fault.c 28 Feb 2003 01:53:09 -0000 1.5
***************
*** 41,44 ****
--- 41,87 ----
+ /* flush_tlb_page
+ * This is used when a "page cache page" is updated
+ * and there is a cache alias in that page.
+ */
+
+
+ #if XTENSA_CACHE_ALIAS
+ /* There can exist an alias between a page of
+ * ptes, and the actual page table. This function
+ * needs to be called when a page table entry is changed.
+ * It will writeback the entry in the page of ptes, and
+ * then invalidate the area of the page table causing the
+ * the auto-refill hardware to reload the correct pte value.
+ */
+
+ static inline void flush_pte_from_cache(pte_t *ptep, unsigned long excvaddr)
+ {
+ unsigned long pte_addr = (unsigned long)ptep;
+ unsigned long ptevaddr = PGTABLE_START;
+
+ ptevaddr = ptevaddr + (excvaddr >> (PAGE_SHIFT-2) );
+ if ( (pte_addr ^ ptevaddr) & XT_CACHE_ALIAS_BITS ) {
+ unsigned long flags;
+
+ #if 0
+ save_and_cli(flags);
+ #if ( XCHAL_DCACHE_IS_WRITEBACK )
+ xthal_dcache_region_writeback(ptep, 4);
+ #endif
+ xthal_dcache_line_invalidate(ptevaddr);
+ restore_flags(flags);
+ #endif
+ save_and_cli(flags);
+ xthal_dcache_all_invalidate();
+ restore_flags(flags);
+ }
+ }
+
+ #else
+ #define flush_pte_from_cache(pte, excvaddr) do { } while(0);
+ #endif
+
+
/*
* do_page_fault() could handle:
***************
*** 107,112 ****
* pte_alloc() and get_pte_slow() for more details. */
! if (pte_none(*pte))
invalidate_itlb_mapping(address);
write = 2; /* i-fetch */
--- 150,156 ----
* pte_alloc() and get_pte_slow() for more details. */
! if (pte_none(*pte)) {
invalidate_itlb_mapping(address);
+ }
write = 2; /* i-fetch */
***************
*** 123,126 ****
--- 167,174 ----
pte_val(*pte) |= (_PAGE_ACCESSED | _PAGE_VALID);
invalidate_itlb_mapping(address);
+
+ /* XXX -- jn */
+ flush_pte_from_cache(pte, regs->excvaddr);
+ // flush_cache_all();
return;
}
***************
*** 138,141 ****
--- 186,193 ----
pte_val(*pte) |= (_PAGE_ACCESSED | _PAGE_VALID);
invalidate_dtlb_mapping(address);
+
+ /* xxx jn */
+ flush_pte_from_cache(pte, regs->excvaddr);
+ // flush_cache_all();
return;
}
***************
*** 144,148 ****
case XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE:
-
if (pte_present(*pte) && pte_write(*pte)) {
--- 196,199 ----
***************
*** 153,156 ****
--- 204,211 ----
pte_val(*pte) |= (_PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID | _PAGE_DIRTY);
invalidate_dtlb_mapping(address);
+
+ /* xxx jn */
+ flush_pte_from_cache(pte, regs->excvaddr);
+ // flush_cache_all();
return;
}
***************
*** 164,169 ****
* get_pte_slow() for more details. */
! if (pte_none(*pte))
invalidate_dtlb_mapping(address);
/* XTFIXME: Use 3 for now, but is it correct? The
--- 219,226 ----
* get_pte_slow() for more details. */
! if (pte_none(*pte)) {
invalidate_dtlb_mapping(address);
+ }
+
/* XTFIXME: Use 3 for now, but is it correct? The
***************
*** 360,361 ****
--- 417,443 ----
}
+
+ void update_mmu_cache(struct vm_area_struct * vma,
+ unsigned long address,
+ pte_t pte)
+ {
+ #if (XTENSA_CACHE_ALIAS)
+ struct page *page;
+
+ page = pte_page(pte);
+ // flush_dcache_page(page);
+ // such a hack.... ick
+ flush_cache_all();
+ #if 0
+ if (VALID_PAGE(page) && !test_bit(PG_mapped, &page->flags)) {
+ flush_dcache_page(page);
+ set_bit(PG_mapped, &page->flags);
+ }
+ #endif
+ #endif
+
+ /* JN XTFIXME -- temporary hack */
+ /* not sure that this is required */
+ // flush_cache_all();
+ invalidate_page_table();
+ }
Index: mmu.c
===================================================================
RCS file: /cvsroot/xtensa/linux/arch/xtensa/mm/mmu.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** mmu.c 13 Feb 2003 18:19:22 -0000 1.5
--- mmu.c 28 Feb 2003 01:53:09 -0000 1.6
***************
*** 210,214 ****
** that information from the CHAL. */
! #define XT2000_MMU_DUMP 0
#if (XT2000_MMU_DUMP == 1)
--- 210,214 ----
** that information from the CHAL. */
! #define XT2000_MMU_DUMP 1
#if (XT2000_MMU_DUMP == 1)
|