mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 23:51:39 +00:00
[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>
This commit is contained in:
parent
5642530651
commit
80dc0d6b44
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
for (i = 0; i < (1 << 16); i += (1 << 5)) {
|
||||
dcache_size = local_cpu_data().dcache_size;
|
||||
dcache_line_size = local_cpu_data().dcache_line_size;
|
||||
|
||||
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;
|
||||
|
||||
for (i = 0; i < (1 << 16); i += (1 << 5)) {
|
||||
unsigned long tag = (i >> 14);
|
||||
unsigned long j;
|
||||
dcache_size = local_cpu_data().dcache_size;
|
||||
dcache_line_size = local_cpu_data().dcache_line_size;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user