diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2005-09-26 03:32:17 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-09-26 03:32:17 -0400 |
commit | 80dc0d6b44ce0f01df58d8899e46612690ed7d81 (patch) | |
tree | 570b8e834c0fae0793bdf75dd2fd2516b0fabf4f | |
parent | 56425306517ef28a9b480161cdb96d182172bc1d (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.c | 22 | ||||
-rw-r--r-- | arch/sparc64/kernel/entry.S | 27 | ||||
-rw-r--r-- | arch/sparc64/kernel/setup.c | 9 | ||||
-rw-r--r-- | arch/sparc64/kernel/smp.c | 21 | ||||
-rw-r--r-- | arch/sparc64/kernel/traps.c | 40 | ||||
-rw-r--r-- | include/asm-sparc64/cpudata.h | 10 |
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 | ||
855 | do_cheetah_plus_data_parity: | 854 | do_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 | ||
864 | cheetah_plus_dcpe_trap_vector_tl1: | 864 | cheetah_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 | ||
885 | do_cheetah_plus_insn_parity: | 885 | do_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 | ||
894 | cheetah_plus_icpe_trap_vector_tl1: | 895 | cheetah_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 |
924 | do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ | 925 | do_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 |
970 | do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ | 975 | do_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 *); | |||
605 | extern void smp_bogo(struct seq_file *); | 605 | extern void smp_bogo(struct seq_file *); |
606 | extern void mmu_info(struct seq_file *); | 606 | extern void mmu_info(struct seq_file *); |
607 | 607 | ||
608 | unsigned int dcache_parity_tl1_occurred; | ||
609 | unsigned int icache_parity_tl1_occurred; | ||
610 | |||
608 | static int show_cpuinfo(struct seq_file *m, void *__unused) | 611 | static 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 | ||
98 | static void smp_setup_percpu_timer(void); | 119 | static 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 | */ |
870 | static void __cheetah_flush_icache(void) | 870 | static 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 | ||
905 | static void cheetah_flush_dcache(void) | 910 | static 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 | */ |
922 | static void cheetah_plus_zap_dcache_parity(void) | 931 | static 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 | ||
27 | DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); | 37 | DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); |