aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2005-09-26 00:32:17 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2005-09-26 00:32:17 -0700
commit80dc0d6b44ce0f01df58d8899e46612690ed7d81 (patch)
tree570b8e834c0fae0793bdf75dd2fd2516b0fabf4f
parent56425306517ef28a9b480161cdb96d182172bc1d (diff)
[SPARC64]: Probe D/I/E-cache config and use.
At boot time, determine the D-cache, I-cache and E-cache size and line-size. Use them in cache flushes when appropriate. This change was motivated by discovering that the D-cache on UltraSparc-IIIi and later are 64K not 32K, and the flushes done by the Cheetah error handlers were assuming a 32K size. There are still some pieces of code that are hard coding things and will need to be fixed up at some point. While we're here, fix the D-cache and I-cache parity error handlers to run with interrupts disabled, and when the trap occurs at trap level > 1 log the event via a counter displayed in /proc/cpuinfo. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc64/kernel/devices.c22
-rw-r--r--arch/sparc64/kernel/entry.S27
-rw-r--r--arch/sparc64/kernel/setup.c9
-rw-r--r--arch/sparc64/kernel/smp.c21
-rw-r--r--arch/sparc64/kernel/traps.c40
-rw-r--r--include/asm-sparc64/cpudata.h10
6 files changed, 106 insertions, 23 deletions
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index d710274e516..df9a1ca8fd7 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -135,6 +135,28 @@ void __init device_scan(void)
cpu_data(0).clock_tick = prom_getintdefault(cpu_node,
"clock-frequency",
0);
+ cpu_data(0).dcache_size = prom_getintdefault(cpu_node,
+ "dcache-size",
+ 16 * 1024);
+ cpu_data(0).dcache_line_size =
+ prom_getintdefault(cpu_node, "dcache-line-size", 32);
+ cpu_data(0).icache_size = prom_getintdefault(cpu_node,
+ "icache-size",
+ 16 * 1024);
+ cpu_data(0).icache_line_size =
+ prom_getintdefault(cpu_node, "icache-line-size", 32);
+ cpu_data(0).ecache_size = prom_getintdefault(cpu_node,
+ "ecache-size",
+ 4 * 1024 * 1024);
+ cpu_data(0).ecache_line_size =
+ prom_getintdefault(cpu_node, "ecache-line-size", 64);
+ printk("CPU[0]: Caches "
+ "D[sz(%d):line_sz(%d)] "
+ "I[sz(%d):line_sz(%d)] "
+ "E[sz(%d):line_sz(%d)]\n",
+ cpu_data(0).dcache_size, cpu_data(0).dcache_line_size,
+ cpu_data(0).icache_size, cpu_data(0).icache_line_size,
+ cpu_data(0).ecache_size, cpu_data(0).ecache_line_size);
}
#endif
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 45cd3bbdb7e..2879b107292 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -372,14 +372,13 @@ cheetah_plus_patch_fpdis:
*
* DATA 0: [low 32-bits] Address of function to call, jmp to this
* [high 32-bits] MMU Context Argument 0, place in %g5
- * DATA 1: Address Argument 1, place in %g6
+ * DATA 1: Address Argument 1, place in %g1
* DATA 2: Address Argument 2, place in %g7
*
* With this method we can do most of the cross-call tlb/cache
* flushing very quickly.
*
- * Current CPU's IRQ worklist table is locked into %g1,
- * don't touch.
+ * Current CPU's IRQ worklist table is locked into %g6, don't touch.
*/
.text
.align 32
@@ -853,13 +852,14 @@ cheetah_plus_dcpe_trap_vector:
nop
do_cheetah_plus_data_parity:
- ba,pt %xcc, etrap
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ ba,pt %xcc, etrap_irq
rd %pc, %g7
mov 0x0, %o0
call cheetah_plus_parity_error
add %sp, PTREGS_OFF, %o1
- ba,pt %xcc, rtrap
- clr %l6
+ ba,a,pt %xcc, rtrap_irq
cheetah_plus_dcpe_trap_vector_tl1:
membar #Sync
@@ -883,13 +883,14 @@ cheetah_plus_icpe_trap_vector:
nop
do_cheetah_plus_insn_parity:
- ba,pt %xcc, etrap
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ ba,pt %xcc, etrap_irq
rd %pc, %g7
mov 0x1, %o0
call cheetah_plus_parity_error
add %sp, PTREGS_OFF, %o1
- ba,pt %xcc, rtrap
- clr %l6
+ ba,a,pt %xcc, rtrap_irq
cheetah_plus_icpe_trap_vector_tl1:
membar #Sync
@@ -922,6 +923,10 @@ do_dcpe_tl1:
nop
wrpr %g1, %tl ! Restore original trap level
do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
+ sethi %hi(dcache_parity_tl1_occurred), %g2
+ lduw [%g2 + %lo(dcache_parity_tl1_occurred)], %g1
+ add %g1, 1, %g1
+ stw %g1, [%g2 + %lo(dcache_parity_tl1_occurred)]
/* Reset D-cache parity */
sethi %hi(1 << 16), %g1 ! D-cache size
mov (1 << 5), %g2 ! D-cache line size
@@ -968,6 +973,10 @@ do_icpe_tl1:
nop
wrpr %g1, %tl ! Restore original trap level
do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
+ sethi %hi(icache_parity_tl1_occurred), %g2
+ lduw [%g2 + %lo(icache_parity_tl1_occurred)], %g1
+ add %g1, 1, %g1
+ stw %g1, [%g2 + %lo(icache_parity_tl1_occurred)]
/* Flush I-cache */
sethi %hi(1 << 15), %g1 ! I-cache size
mov (1 << 5), %g2 ! I-cache line size
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index f4345d83728..8e8baf2354d 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -605,6 +605,9 @@ extern void smp_info(struct seq_file *);
extern void smp_bogo(struct seq_file *);
extern void mmu_info(struct seq_file *);
+unsigned int dcache_parity_tl1_occurred;
+unsigned int icache_parity_tl1_occurred;
+
static int show_cpuinfo(struct seq_file *m, void *__unused)
{
seq_printf(m,
@@ -615,6 +618,8 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
"type\t\t: sun4u\n"
"ncpus probed\t: %ld\n"
"ncpus active\t: %ld\n"
+ "D$ parity tl1\t: %u\n"
+ "I$ parity tl1\t: %u\n"
#ifndef CONFIG_SMP
"Cpu0Bogo\t: %lu.%02lu\n"
"Cpu0ClkTck\t: %016lx\n"
@@ -627,7 +632,9 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
(prom_prev >> 8) & 0xff,
prom_prev & 0xff,
(long)num_possible_cpus(),
- (long)num_online_cpus()
+ (long)num_online_cpus(),
+ dcache_parity_tl1_occurred,
+ icache_parity_tl1_occurred
#ifndef CONFIG_SMP
, cpu_data(0).udelay_val/(500000/HZ),
(cpu_data(0).udelay_val/(5000/HZ)) % 100,
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index b4fc6a5462b..590df5a16f5 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -93,6 +93,27 @@ void __init smp_store_cpu_info(int id)
cpu_data(id).pte_cache[1] = NULL;
cpu_data(id).pgd_cache = NULL;
cpu_data(id).idle_volume = 1;
+
+ cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size",
+ 16 * 1024);
+ cpu_data(id).dcache_line_size =
+ prom_getintdefault(cpu_node, "dcache-line-size", 32);
+ cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size",
+ 16 * 1024);
+ cpu_data(id).icache_line_size =
+ prom_getintdefault(cpu_node, "icache-line-size", 32);
+ cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size",
+ 4 * 1024 * 1024);
+ cpu_data(id).ecache_line_size =
+ prom_getintdefault(cpu_node, "ecache-line-size", 64);
+ printk("CPU[%d]: Caches "
+ "D[sz(%d):line_sz(%d)] "
+ "I[sz(%d):line_sz(%d)] "
+ "E[sz(%d):line_sz(%d)]\n",
+ id,
+ cpu_data(id).dcache_size, cpu_data(id).dcache_line_size,
+ cpu_data(id).icache_size, cpu_data(id).icache_line_size,
+ cpu_data(id).ecache_size, cpu_data(id).ecache_line_size);
}
static void smp_setup_percpu_timer(void);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index b280b2ef674..f8e7005fede 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -869,14 +869,19 @@ static void cheetah_flush_ecache_line(unsigned long physaddr)
*/
static void __cheetah_flush_icache(void)
{
- unsigned long i;
+ unsigned int icache_size, icache_line_size;
+ unsigned long addr;
+
+ icache_size = local_cpu_data().icache_size;
+ icache_line_size = local_cpu_data().icache_line_size;
/* Clear the valid bits in all the tags. */
- for (i = 0; i < (1 << 15); i += (1 << 5)) {
+ for (addr = 0; addr < icache_size; addr += icache_line_size) {
__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
"membar #Sync"
: /* no outputs */
- : "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
+ : "r" (addr | (2 << 3)),
+ "i" (ASI_IC_TAG));
}
}
@@ -904,13 +909,17 @@ static void cheetah_flush_icache(void)
static void cheetah_flush_dcache(void)
{
- unsigned long i;
+ unsigned int dcache_size, dcache_line_size;
+ unsigned long addr;
+
+ dcache_size = local_cpu_data().dcache_size;
+ dcache_line_size = local_cpu_data().dcache_line_size;
- for (i = 0; i < (1 << 16); i += (1 << 5)) {
+ for (addr = 0; addr < dcache_size; addr += dcache_line_size) {
__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
"membar #Sync"
: /* no outputs */
- : "r" (i), "i" (ASI_DCACHE_TAG));
+ : "r" (addr), "i" (ASI_DCACHE_TAG));
}
}
@@ -921,24 +930,29 @@ static void cheetah_flush_dcache(void)
*/
static void cheetah_plus_zap_dcache_parity(void)
{
- unsigned long i;
+ unsigned int dcache_size, dcache_line_size;
+ unsigned long addr;
+
+ dcache_size = local_cpu_data().dcache_size;
+ dcache_line_size = local_cpu_data().dcache_line_size;
- for (i = 0; i < (1 << 16); i += (1 << 5)) {
- unsigned long tag = (i >> 14);
- unsigned long j;
+ for (addr = 0; addr < dcache_size; addr += dcache_line_size) {
+ unsigned long tag = (addr >> 14);
+ unsigned long line;
__asm__ __volatile__("membar #Sync\n\t"
"stxa %0, [%1] %2\n\t"
"membar #Sync"
: /* no outputs */
- : "r" (tag), "r" (i),
+ : "r" (tag), "r" (addr),
"i" (ASI_DCACHE_UTAG));
- for (j = i; j < i + (1 << 5); j += (1 << 3))
+ for (line = addr; line < addr + dcache_line_size; line += 8)
__asm__ __volatile__("membar #Sync\n\t"
"stxa %%g0, [%0] %1\n\t"
"membar #Sync"
: /* no outputs */
- : "r" (j), "i" (ASI_DCACHE_DATA));
+ : "r" (line),
+ "i" (ASI_DCACHE_DATA));
}
}
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index 9a3a81f1cc5..74de79dca91 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -22,6 +22,16 @@ typedef struct {
unsigned int __pad1;
unsigned long *pte_cache[2];
unsigned long *pgd_cache;
+
+ /* Dcache line 3, rarely used */
+ unsigned int dcache_size;
+ unsigned int dcache_line_size;
+ unsigned int icache_size;
+ unsigned int icache_line_size;
+ unsigned int ecache_size;
+ unsigned int ecache_line_size;
+ unsigned int __pad2;
+ unsigned int __pad3;
} cpuinfo_sparc;
DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);