Commit b638d0b9 authored by Richard Curnow's avatar Richard Curnow Committed by Paul Mundt

sh: Optimized cache handling for SH-4/SH-4A caches.

This reworks some of the SH-4 cache handling code to more easily
accomodate newer-style caches (particularly for the > direct-mapped
case), as well as optimizing some of the old code.
Signed-off-by: default avatarRichard Curnow <richard.curnow@st.com>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent fdfc74f9
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* CPU init code * CPU init code
* *
* Copyright (C) 2002, 2003 Paul Mundt * Copyright (C) 2002, 2003 Paul Mundt
* Copyright (C) 2003 Richard Curnow
* *
* This file is subject to the terms and conditions of the GNU General Public * 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 * License. See the file "COPYING" in the main directory of this archive
...@@ -51,7 +52,15 @@ static void __init cache_init(void) ...@@ -51,7 +52,15 @@ static void __init cache_init(void)
ccr = ctrl_inl(CCR); ccr = ctrl_inl(CCR);
/* /*
* If the cache is already enabled .. flush it. * At this point we don't know whether the cache is enabled or not - a
* bootloader may have enabled it. There are at least 2 things that
* could be dirty in the cache at this point:
* 1. kernel command line set up by boot loader
* 2. spilled registers from the prolog of this function
* => before re-initialising the cache, we must do a purge of the whole
* cache out to memory for safety. As long as nothing is spilled
* during the loop to lines that have already been done, this is safe.
* - RPC
*/ */
if (ccr & CCR_CACHE_ENABLE) { if (ccr & CCR_CACHE_ENABLE) {
unsigned long ways, waysize, addrstart; unsigned long ways, waysize, addrstart;
...@@ -98,6 +107,8 @@ static void __init cache_init(void) ...@@ -98,6 +107,8 @@ static void __init cache_init(void)
/* Force EMODE if possible */ /* Force EMODE if possible */
if (cpu_data->dcache.ways > 1) if (cpu_data->dcache.ways > 1)
flags |= CCR_CACHE_EMODE; flags |= CCR_CACHE_EMODE;
else
flags &= ~CCR_CACHE_EMODE;
#endif #endif
#ifdef CONFIG_SH_WRITETHROUGH #ifdef CONFIG_SH_WRITETHROUGH
...@@ -112,6 +123,9 @@ static void __init cache_init(void) ...@@ -112,6 +123,9 @@ static void __init cache_init(void)
/* Turn on OCRAM -- halve the OC */ /* Turn on OCRAM -- halve the OC */
flags |= CCR_CACHE_ORA; flags |= CCR_CACHE_ORA;
cpu_data->dcache.sets >>= 1; cpu_data->dcache.sets >>= 1;
cpu_data->dcache.way_size = cpu_data->dcache.sets *
cpu_data->dcache.linesz;
#endif #endif
ctrl_outl(flags, CCR); ctrl_outl(flags, CCR);
......
...@@ -113,6 +113,11 @@ int __init detect_cpu_and_cache_system(void) ...@@ -113,6 +113,11 @@ int __init detect_cpu_and_cache_system(void)
break; break;
} }
#ifdef CONFIG_SH_DIRECT_MAPPED
cpu_data->icache.ways = 1;
cpu_data->dcache.ways = 1;
#endif
/* /*
* On anything that's not a direct-mapped cache, look to the CVR * On anything that's not a direct-mapped cache, look to the CVR
* for I/D-cache specifics. * for I/D-cache specifics.
...@@ -125,6 +130,9 @@ int __init detect_cpu_and_cache_system(void) ...@@ -125,6 +130,9 @@ int __init detect_cpu_and_cache_system(void)
(cpu_data->icache.way_incr - (1 << 5)); (cpu_data->icache.way_incr - (1 << 5));
} }
cpu_data->icache.way_size = cpu_data->icache.sets *
cpu_data->icache.linesz;
if (cpu_data->dcache.ways > 1) { if (cpu_data->dcache.ways > 1) {
size = sizes[(cvr >> 16) & 0xf]; size = sizes[(cvr >> 16) & 0xf];
cpu_data->dcache.way_incr = (size >> 1); cpu_data->dcache.way_incr = (size >> 1);
...@@ -133,6 +141,9 @@ int __init detect_cpu_and_cache_system(void) ...@@ -133,6 +141,9 @@ int __init detect_cpu_and_cache_system(void)
(cpu_data->dcache.way_incr - (1 << 5)); (cpu_data->dcache.way_incr - (1 << 5));
} }
cpu_data->dcache.way_size = cpu_data->dcache.sets *
cpu_data->dcache.linesz;
return 0; return 0;
} }
This diff is collapsed.
...@@ -193,102 +193,5 @@ ENTRY(__clear_user_page) ...@@ -193,102 +193,5 @@ ENTRY(__clear_user_page)
nop nop
.L4096: .word 4096 .L4096: .word 4096
ENTRY(__flush_cache_4096)
mov.l 1f,r3
add r6,r3
mov r4,r0
mov #64,r2
shll r2
mov #64,r6
jmp @r3
mov #96,r7
.align 2
1: .long 2f
2:
.rept 32
mov.l r5,@r0
mov.l r5,@(32,r0)
mov.l r5,@(r0,r6)
mov.l r5,@(r0,r7)
add r2,r5
add r2,r0
.endr
nop
nop
nop
nop
nop
nop
nop
rts
nop
ENTRY(__flush_dcache_all)
mov.l 2f,r0
mov.l 3f,r4
and r0,r4 ! r4 = (unsigned long)&empty_zero_page[0] & ~0xffffc000
stc sr,r1 ! save SR
mov.l 4f,r2
or r1,r2
mov #32,r3
shll2 r3
1:
ldc r2,sr ! set BL bit
movca.l r0,@r4
ocbi @r4
add #32,r4
movca.l r0,@r4
ocbi @r4
add #32,r4
movca.l r0,@r4
ocbi @r4
add #32,r4
movca.l r0,@r4
ocbi @r4
ldc r1,sr ! restore SR
dt r3
bf/s 1b
add #32,r4
rts
nop
.align 2
2: .long 0xffffc000
3: .long empty_zero_page
4: .long 0x10000000 ! BL bit
/* __flush_cache_4096_all(unsigned long addr) */
ENTRY(__flush_cache_4096_all)
mov.l 2f,r0
mov.l 3f,r2
and r0,r2
or r2,r4 ! r4 = addr | (unsigned long)&empty_zero_page[0] & ~0x3fff
stc sr,r1 ! save SR
mov.l 4f,r2
or r1,r2
mov #32,r3
1:
ldc r2,sr ! set BL bit
movca.l r0,@r4
ocbi @r4
add #32,r4
movca.l r0,@r4
ocbi @r4
add #32,r4
movca.l r0,@r4
ocbi @r4
add #32,r4
movca.l r0,@r4
ocbi @r4
ldc r1,sr ! restore SR
dt r3
bf/s 1b
add #32,r4
rts
nop
.align 2
2: .long 0xffffc000
3: .long empty_zero_page
4: .long 0x10000000 ! BL bit
#endif #endif
...@@ -23,15 +23,29 @@ ...@@ -23,15 +23,29 @@
#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) #define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
struct cache_info { struct cache_info {
unsigned int ways; unsigned int ways; /* Number of cache ways */
unsigned int sets; unsigned int sets; /* Number of cache sets */
unsigned int linesz; unsigned int linesz; /* Cache line size (bytes) */
unsigned int way_incr; unsigned int way_size; /* sets * line size */
/*
* way_incr is the address offset for accessing the next way
* in memory mapped cache array ops.
*/
unsigned int way_incr;
unsigned int entry_shift; unsigned int entry_shift;
unsigned int entry_mask; unsigned int entry_mask;
/*
* Compute a mask which selects the address bits which overlap between
* 1. those used to select the cache set during indexing
* 2. those in the physical page number.
*/
unsigned int alias_mask;
unsigned int n_aliases; /* Number of aliases */
unsigned long flags; unsigned long flags;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment