aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2005-09-26 03:32:17 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-09-26 03:32:17 -0400
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 d710274e516b..df9a1ca8fd77 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -135,6 +135,28 @@ void __init device_scan(void)
135 cpu_data(0).clock_tick = prom_getintdefault(cpu_node, 135 cpu_data(0).clock_tick = prom_getintdefault(cpu_node,
136 "clock-frequency", 136 "clock-frequency",
137 0); 137 0);
138 cpu_data(0).dcache_size = prom_getintdefault(cpu_node,
139 "dcache-size",
140 16 * 1024);
141 cpu_data(0).dcache_line_size =
142 prom_getintdefault(cpu_node, "dcache-line-size", 32);
143 cpu_data(0).icache_size = prom_getintdefault(cpu_node,
144 "icache-size",
145 16 * 1024);
146 cpu_data(0).icache_line_size =
147 prom_getintdefault(cpu_node, "icache-line-size", 32);
148 cpu_data(0).ecache_size = prom_getintdefault(cpu_node,
149 "ecache-size",
150 4 * 1024 * 1024);
151 cpu_data(0).ecache_line_size =
152 prom_getintdefault(cpu_node, "ecache-line-size", 64);
153 printk("CPU[0]: Caches "
154 "D[sz(%d):line_sz(%d)] "
155 "I[sz(%d):line_sz(%d)] "
156 "E[sz(%d):line_sz(%d)]\n",
157 cpu_data(0).dcache_size, cpu_data(0).dcache_line_size,
158 cpu_data(0).icache_size, cpu_data(0).icache_line_size,
159 cpu_data(0).ecache_size, cpu_data(0).ecache_line_size);
138 } 160 }
139#endif 161#endif
140 162
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 45cd3bbdb7e0..2879b1072921 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -372,14 +372,13 @@ cheetah_plus_patch_fpdis:
372 * 372 *
373 * DATA 0: [low 32-bits] Address of function to call, jmp to this 373 * DATA 0: [low 32-bits] Address of function to call, jmp to this
374 * [high 32-bits] MMU Context Argument 0, place in %g5 374 * [high 32-bits] MMU Context Argument 0, place in %g5
375 * DATA 1: Address Argument 1, place in %g6 375 * DATA 1: Address Argument 1, place in %g1
376 * DATA 2: Address Argument 2, place in %g7 376 * DATA 2: Address Argument 2, place in %g7
377 * 377 *
378 * With this method we can do most of the cross-call tlb/cache 378 * With this method we can do most of the cross-call tlb/cache
379 * flushing very quickly. 379 * flushing very quickly.
380 * 380 *
381 * Current CPU's IRQ worklist table is locked into %g1, 381 * Current CPU's IRQ worklist table is locked into %g6, don't touch.
382 * don't touch.
383 */ 382 */
384 .text 383 .text
385 .align 32 384 .align 32
@@ -853,13 +852,14 @@ cheetah_plus_dcpe_trap_vector:
853 nop 852 nop
854 853
855do_cheetah_plus_data_parity: 854do_cheetah_plus_data_parity:
856 ba,pt %xcc, etrap 855 rdpr %pil, %g2
856 wrpr %g0, 15, %pil
857 ba,pt %xcc, etrap_irq
857 rd %pc, %g7 858 rd %pc, %g7
858 mov 0x0, %o0 859 mov 0x0, %o0
859 call cheetah_plus_parity_error 860 call cheetah_plus_parity_error
860 add %sp, PTREGS_OFF, %o1 861 add %sp, PTREGS_OFF, %o1
861 ba,pt %xcc, rtrap 862 ba,a,pt %xcc, rtrap_irq
862 clr %l6
863 863
864cheetah_plus_dcpe_trap_vector_tl1: 864cheetah_plus_dcpe_trap_vector_tl1:
865 membar #Sync 865 membar #Sync
@@ -883,13 +883,14 @@ cheetah_plus_icpe_trap_vector:
883 nop 883 nop
884 884
885do_cheetah_plus_insn_parity: 885do_cheetah_plus_insn_parity:
886 ba,pt %xcc, etrap 886 rdpr %pil, %g2
887 wrpr %g0, 15, %pil
888 ba,pt %xcc, etrap_irq
887 rd %pc, %g7 889 rd %pc, %g7
888 mov 0x1, %o0 890 mov 0x1, %o0
889 call cheetah_plus_parity_error 891 call cheetah_plus_parity_error
890 add %sp, PTREGS_OFF, %o1 892 add %sp, PTREGS_OFF, %o1
891 ba,pt %xcc, rtrap 893 ba,a,pt %xcc, rtrap_irq
892 clr %l6
893 894
894cheetah_plus_icpe_trap_vector_tl1: 895cheetah_plus_icpe_trap_vector_tl1:
895 membar #Sync 896 membar #Sync
@@ -922,6 +923,10 @@ do_dcpe_tl1:
922 nop 923 nop
923 wrpr %g1, %tl ! Restore original trap level 924 wrpr %g1, %tl ! Restore original trap level
924do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ 925do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
926 sethi %hi(dcache_parity_tl1_occurred), %g2
927 lduw [%g2 + %lo(dcache_parity_tl1_occurred)], %g1
928 add %g1, 1, %g1
929 stw %g1, [%g2 + %lo(dcache_parity_tl1_occurred)]
925 /* Reset D-cache parity */ 930 /* Reset D-cache parity */
926 sethi %hi(1 << 16), %g1 ! D-cache size 931 sethi %hi(1 << 16), %g1 ! D-cache size
927 mov (1 << 5), %g2 ! D-cache line size 932 mov (1 << 5), %g2 ! D-cache line size
@@ -968,6 +973,10 @@ do_icpe_tl1:
968 nop 973 nop
969 wrpr %g1, %tl ! Restore original trap level 974 wrpr %g1, %tl ! Restore original trap level
970do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ 975do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
976 sethi %hi(icache_parity_tl1_occurred), %g2
977 lduw [%g2 + %lo(icache_parity_tl1_occurred)], %g1
978 add %g1, 1, %g1
979 stw %g1, [%g2 + %lo(icache_parity_tl1_occurred)]
971 /* Flush I-cache */ 980 /* Flush I-cache */
972 sethi %hi(1 << 15), %g1 ! I-cache size 981 sethi %hi(1 << 15), %g1 ! I-cache size
973 mov (1 << 5), %g2 ! I-cache line size 982 mov (1 << 5), %g2 ! I-cache line size
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index f4345d837284..8e8baf2354df 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -605,6 +605,9 @@ extern void smp_info(struct seq_file *);
605extern void smp_bogo(struct seq_file *); 605extern void smp_bogo(struct seq_file *);
606extern void mmu_info(struct seq_file *); 606extern void mmu_info(struct seq_file *);
607 607
608unsigned int dcache_parity_tl1_occurred;
609unsigned int icache_parity_tl1_occurred;
610
608static int show_cpuinfo(struct seq_file *m, void *__unused) 611static int show_cpuinfo(struct seq_file *m, void *__unused)
609{ 612{
610 seq_printf(m, 613 seq_printf(m,
@@ -615,6 +618,8 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
615 "type\t\t: sun4u\n" 618 "type\t\t: sun4u\n"
616 "ncpus probed\t: %ld\n" 619 "ncpus probed\t: %ld\n"
617 "ncpus active\t: %ld\n" 620 "ncpus active\t: %ld\n"
621 "D$ parity tl1\t: %u\n"
622 "I$ parity tl1\t: %u\n"
618#ifndef CONFIG_SMP 623#ifndef CONFIG_SMP
619 "Cpu0Bogo\t: %lu.%02lu\n" 624 "Cpu0Bogo\t: %lu.%02lu\n"
620 "Cpu0ClkTck\t: %016lx\n" 625 "Cpu0ClkTck\t: %016lx\n"
@@ -627,7 +632,9 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
627 (prom_prev >> 8) & 0xff, 632 (prom_prev >> 8) & 0xff,
628 prom_prev & 0xff, 633 prom_prev & 0xff,
629 (long)num_possible_cpus(), 634 (long)num_possible_cpus(),
630 (long)num_online_cpus() 635 (long)num_online_cpus(),
636 dcache_parity_tl1_occurred,
637 icache_parity_tl1_occurred
631#ifndef CONFIG_SMP 638#ifndef CONFIG_SMP
632 , cpu_data(0).udelay_val/(500000/HZ), 639 , cpu_data(0).udelay_val/(500000/HZ),
633 (cpu_data(0).udelay_val/(5000/HZ)) % 100, 640 (cpu_data(0).udelay_val/(5000/HZ)) % 100,
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index b4fc6a5462b2..590df5a16f5a 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)
93 cpu_data(id).pte_cache[1] = NULL; 93 cpu_data(id).pte_cache[1] = NULL;
94 cpu_data(id).pgd_cache = NULL; 94 cpu_data(id).pgd_cache = NULL;
95 cpu_data(id).idle_volume = 1; 95 cpu_data(id).idle_volume = 1;
96
97 cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size",
98 16 * 1024);
99 cpu_data(id).dcache_line_size =
100 prom_getintdefault(cpu_node, "dcache-line-size", 32);
101 cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size",
102 16 * 1024);
103 cpu_data(id).icache_line_size =
104 prom_getintdefault(cpu_node, "icache-line-size", 32);
105 cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size",
106 4 * 1024 * 1024);
107 cpu_data(id).ecache_line_size =
108 prom_getintdefault(cpu_node, "ecache-line-size", 64);
109 printk("CPU[%d]: Caches "
110 "D[sz(%d):line_sz(%d)] "
111 "I[sz(%d):line_sz(%d)] "
112 "E[sz(%d):line_sz(%d)]\n",
113 id,
114 cpu_data(id).dcache_size, cpu_data(id).dcache_line_size,
115 cpu_data(id).icache_size, cpu_data(id).icache_line_size,
116 cpu_data(id).ecache_size, cpu_data(id).ecache_line_size);
96} 117}
97 118
98static void smp_setup_percpu_timer(void); 119static void smp_setup_percpu_timer(void);
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index b280b2ef674f..f8e7005fede9 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)
869 */ 869 */
870static void __cheetah_flush_icache(void) 870static void __cheetah_flush_icache(void)
871{ 871{
872 unsigned long i; 872 unsigned int icache_size, icache_line_size;
873 unsigned long addr;
874
875 icache_size = local_cpu_data().icache_size;
876 icache_line_size = local_cpu_data().icache_line_size;
873 877
874 /* Clear the valid bits in all the tags. */ 878 /* Clear the valid bits in all the tags. */
875 for (i = 0; i < (1 << 15); i += (1 << 5)) { 879 for (addr = 0; addr < icache_size; addr += icache_line_size) {
876 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" 880 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
877 "membar #Sync" 881 "membar #Sync"
878 : /* no outputs */ 882 : /* no outputs */
879 : "r" (i | (2 << 3)), "i" (ASI_IC_TAG)); 883 : "r" (addr | (2 << 3)),
884 "i" (ASI_IC_TAG));
880 } 885 }
881} 886}
882 887
@@ -904,13 +909,17 @@ static void cheetah_flush_icache(void)
904 909
905static void cheetah_flush_dcache(void) 910static void cheetah_flush_dcache(void)
906{ 911{
907 unsigned long i; 912 unsigned int dcache_size, dcache_line_size;
913 unsigned long addr;
914
915 dcache_size = local_cpu_data().dcache_size;
916 dcache_line_size = local_cpu_data().dcache_line_size;
908 917
909 for (i = 0; i < (1 << 16); i += (1 << 5)) { 918 for (addr = 0; addr < dcache_size; addr += dcache_line_size) {
910 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" 919 __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
911 "membar #Sync" 920 "membar #Sync"
912 : /* no outputs */ 921 : /* no outputs */
913 : "r" (i), "i" (ASI_DCACHE_TAG)); 922 : "r" (addr), "i" (ASI_DCACHE_TAG));
914 } 923 }
915} 924}
916 925
@@ -921,24 +930,29 @@ static void cheetah_flush_dcache(void)
921 */ 930 */
922static void cheetah_plus_zap_dcache_parity(void) 931static void cheetah_plus_zap_dcache_parity(void)
923{ 932{
924 unsigned long i; 933 unsigned int dcache_size, dcache_line_size;
934 unsigned long addr;
935
936 dcache_size = local_cpu_data().dcache_size;
937 dcache_line_size = local_cpu_data().dcache_line_size;
925 938
926 for (i = 0; i < (1 << 16); i += (1 << 5)) { 939 for (addr = 0; addr < dcache_size; addr += dcache_line_size) {
927 unsigned long tag = (i >> 14); 940 unsigned long tag = (addr >> 14);
928 unsigned long j; 941 unsigned long line;
929 942
930 __asm__ __volatile__("membar #Sync\n\t" 943 __asm__ __volatile__("membar #Sync\n\t"
931 "stxa %0, [%1] %2\n\t" 944 "stxa %0, [%1] %2\n\t"
932 "membar #Sync" 945 "membar #Sync"
933 : /* no outputs */ 946 : /* no outputs */
934 : "r" (tag), "r" (i), 947 : "r" (tag), "r" (addr),
935 "i" (ASI_DCACHE_UTAG)); 948 "i" (ASI_DCACHE_UTAG));
936 for (j = i; j < i + (1 << 5); j += (1 << 3)) 949 for (line = addr; line < addr + dcache_line_size; line += 8)
937 __asm__ __volatile__("membar #Sync\n\t" 950 __asm__ __volatile__("membar #Sync\n\t"
938 "stxa %%g0, [%0] %1\n\t" 951 "stxa %%g0, [%0] %1\n\t"
939 "membar #Sync" 952 "membar #Sync"
940 : /* no outputs */ 953 : /* no outputs */
941 : "r" (j), "i" (ASI_DCACHE_DATA)); 954 : "r" (line),
955 "i" (ASI_DCACHE_DATA));
942 } 956 }
943} 957}
944 958
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index 9a3a81f1cc58..74de79dca915 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -22,6 +22,16 @@ typedef struct {
22 unsigned int __pad1; 22 unsigned int __pad1;
23 unsigned long *pte_cache[2]; 23 unsigned long *pte_cache[2];
24 unsigned long *pgd_cache; 24 unsigned long *pgd_cache;
25
26 /* Dcache line 3, rarely used */
27 unsigned int dcache_size;
28 unsigned int dcache_line_size;
29 unsigned int icache_size;
30 unsigned int icache_line_size;
31 unsigned int ecache_size;
32 unsigned int ecache_line_size;
33 unsigned int __pad2;
34 unsigned int __pad3;
25} cpuinfo_sparc; 35} cpuinfo_sparc;
26 36
27DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); 37DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);