diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-25 01:08:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-25 01:08:34 -0400 |
commit | 881d021ab0d675f519b68df916fde969940ef988 (patch) | |
tree | b4b60a1d2a0a25c8b1f1fbf322a44d89817a22da | |
parent | 83ef64b9dea6e3ed287a45d56166913bffcd2497 (diff) |
sparc64: Add generic interface for registering a dimm printing handler.
The way to do this varies by platform type and the exact memory
controller the cpu uses.
For Spitfire cpus we currently just use prom_getunumber() and hope
that works.
For Cheetah cpus we have a memory controller driver that can
compute this information.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/sparc/include/asm/memctrl.h | 9 | ||||
-rw-r--r-- | arch/sparc64/kernel/chmc.c | 21 | ||||
-rw-r--r-- | arch/sparc64/kernel/traps.c | 62 |
3 files changed, 79 insertions, 13 deletions
diff --git a/arch/sparc/include/asm/memctrl.h b/arch/sparc/include/asm/memctrl.h new file mode 100644 index 000000000000..4065c56af7b6 --- /dev/null +++ b/arch/sparc/include/asm/memctrl.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef _SPARC_MEMCTRL_H | ||
2 | #define _SPARC_MEMCTRL_H | ||
3 | |||
4 | typedef int (*dimm_printer_t)(int synd_code, unsigned long paddr, char *buf, int buflen); | ||
5 | |||
6 | int register_dimm_printer(dimm_printer_t func); | ||
7 | void unregister_dimm_printer(dimm_printer_t func); | ||
8 | |||
9 | #endif /* _SPARC_MEMCTRL_H */ | ||
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c index 2f73ddc8676d..a3c79fd5dd31 100644 --- a/arch/sparc64/kernel/chmc.c +++ b/arch/sparc64/kernel/chmc.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
23 | #include <asm/head.h> | 23 | #include <asm/head.h> |
24 | #include <asm/io.h> | 24 | #include <asm/io.h> |
25 | #include <asm/memctrl.h> | ||
25 | 26 | ||
26 | #define DRV_MODULE_NAME "chmc" | 27 | #define DRV_MODULE_NAME "chmc" |
27 | #define PFX DRV_MODULE_NAME ": " | 28 | #define PFX DRV_MODULE_NAME ": " |
@@ -158,9 +159,9 @@ static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr) | |||
158 | /* This is the main purpose of this driver. */ | 159 | /* This is the main purpose of this driver. */ |
159 | #define SYNDROME_MIN -1 | 160 | #define SYNDROME_MIN -1 |
160 | #define SYNDROME_MAX 144 | 161 | #define SYNDROME_MAX 144 |
161 | int chmc_getunumber(int syndrome_code, | 162 | static int chmc_print_dimm(int syndrome_code, |
162 | unsigned long phys_addr, | 163 | unsigned long phys_addr, |
163 | char *buf, int buflen) | 164 | char *buf, int buflen) |
164 | { | 165 | { |
165 | struct chmc_bank_info *bp; | 166 | struct chmc_bank_info *bp; |
166 | struct chmc_obp_mem_layout *prop; | 167 | struct chmc_obp_mem_layout *prop; |
@@ -466,16 +467,26 @@ static inline bool chmc_platform(void) | |||
466 | 467 | ||
467 | static int __init chmc_init(void) | 468 | static int __init chmc_init(void) |
468 | { | 469 | { |
470 | int ret; | ||
471 | |||
469 | if (!chmc_platform()) | 472 | if (!chmc_platform()) |
470 | return -ENODEV; | 473 | return -ENODEV; |
471 | 474 | ||
472 | return of_register_driver(&chmc_driver, &of_bus_type); | 475 | ret = register_dimm_printer(chmc_print_dimm); |
476 | if (!ret) { | ||
477 | ret = of_register_driver(&chmc_driver, &of_bus_type); | ||
478 | if (ret) | ||
479 | unregister_dimm_printer(chmc_print_dimm); | ||
480 | } | ||
481 | return ret; | ||
473 | } | 482 | } |
474 | 483 | ||
475 | static void __exit chmc_cleanup(void) | 484 | static void __exit chmc_cleanup(void) |
476 | { | 485 | { |
477 | if (chmc_platform()) | 486 | if (chmc_platform()) { |
487 | unregister_dimm_printer(chmc_print_dimm); | ||
478 | of_unregister_driver(&chmc_driver); | 488 | of_unregister_driver(&chmc_driver); |
489 | } | ||
479 | } | 490 | } |
480 | 491 | ||
481 | module_init(chmc_init); | 492 | module_init(chmc_init); |
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 3d924121c796..17880ccfa3cd 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <asm/timer.h> | 37 | #include <asm/timer.h> |
38 | #include <asm/head.h> | 38 | #include <asm/head.h> |
39 | #include <asm/prom.h> | 39 | #include <asm/prom.h> |
40 | #include <asm/memctrl.h> | ||
40 | 41 | ||
41 | #include "entry.h" | 42 | #include "entry.h" |
42 | #include "kstack.h" | 43 | #include "kstack.h" |
@@ -128,6 +129,55 @@ void do_BUG(const char *file, int line) | |||
128 | } | 129 | } |
129 | #endif | 130 | #endif |
130 | 131 | ||
132 | static DEFINE_SPINLOCK(dimm_handler_lock); | ||
133 | static dimm_printer_t dimm_handler; | ||
134 | |||
135 | static int sprintf_dimm(int synd_code, unsigned long paddr, char *buf, int buflen) | ||
136 | { | ||
137 | unsigned long flags; | ||
138 | int ret = -ENODEV; | ||
139 | |||
140 | spin_lock_irqsave(&dimm_handler_lock, flags); | ||
141 | if (dimm_handler) { | ||
142 | ret = dimm_handler(synd_code, paddr, buf, buflen); | ||
143 | } else if (tlb_type == spitfire) { | ||
144 | if (prom_getunumber(synd_code, paddr, buf, buflen) == -1) | ||
145 | ret = -EINVAL; | ||
146 | else | ||
147 | ret = 0; | ||
148 | } else | ||
149 | ret = -ENODEV; | ||
150 | spin_unlock_irqrestore(&dimm_handler_lock, flags); | ||
151 | |||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | int register_dimm_printer(dimm_printer_t func) | ||
156 | { | ||
157 | unsigned long flags; | ||
158 | int ret = 0; | ||
159 | |||
160 | spin_lock_irqsave(&dimm_handler_lock, flags); | ||
161 | if (!dimm_handler) | ||
162 | dimm_handler = func; | ||
163 | else | ||
164 | ret = -EEXIST; | ||
165 | spin_unlock_irqrestore(&dimm_handler_lock, flags); | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | void unregister_dimm_printer(dimm_printer_t func) | ||
171 | { | ||
172 | unsigned long flags; | ||
173 | |||
174 | spin_lock_irqsave(&dimm_handler_lock, flags); | ||
175 | if (dimm_handler == func) | ||
176 | dimm_handler = NULL; | ||
177 | spin_unlock_irqrestore(&dimm_handler_lock, flags); | ||
178 | } | ||
179 | |||
180 | |||
131 | void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) | 181 | void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) |
132 | { | 182 | { |
133 | siginfo_t info; | 183 | siginfo_t info; |
@@ -375,8 +425,7 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un | |||
375 | 425 | ||
376 | if (udbl & bit) { | 426 | if (udbl & bit) { |
377 | scode = ecc_syndrome_table[udbl & 0xff]; | 427 | scode = ecc_syndrome_table[udbl & 0xff]; |
378 | if (prom_getunumber(scode, afar, | 428 | if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0) |
379 | memmod_str, sizeof(memmod_str)) == -1) | ||
380 | p = syndrome_unknown; | 429 | p = syndrome_unknown; |
381 | else | 430 | else |
382 | p = memmod_str; | 431 | p = memmod_str; |
@@ -387,8 +436,7 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un | |||
387 | 436 | ||
388 | if (udbh & bit) { | 437 | if (udbh & bit) { |
389 | scode = ecc_syndrome_table[udbh & 0xff]; | 438 | scode = ecc_syndrome_table[udbh & 0xff]; |
390 | if (prom_getunumber(scode, afar, | 439 | if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0) |
391 | memmod_str, sizeof(memmod_str)) == -1) | ||
392 | p = syndrome_unknown; | 440 | p = syndrome_unknown; |
393 | else | 441 | else |
394 | p = memmod_str; | 442 | p = memmod_str; |
@@ -1061,8 +1109,6 @@ static const char *cheetah_get_string(unsigned long bit) | |||
1061 | return "???"; | 1109 | return "???"; |
1062 | } | 1110 | } |
1063 | 1111 | ||
1064 | extern int chmc_getunumber(int, unsigned long, char *, int); | ||
1065 | |||
1066 | static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info, | 1112 | static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info, |
1067 | unsigned long afsr, unsigned long afar, int recoverable) | 1113 | unsigned long afsr, unsigned long afar, int recoverable) |
1068 | { | 1114 | { |
@@ -1104,7 +1150,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in | |||
1104 | 1150 | ||
1105 | syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT; | 1151 | syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT; |
1106 | syndrome = cheetah_ecc_syntab[syndrome]; | 1152 | syndrome = cheetah_ecc_syntab[syndrome]; |
1107 | ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum)); | 1153 | ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum)); |
1108 | if (ret != -1) | 1154 | if (ret != -1) |
1109 | printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n", | 1155 | printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n", |
1110 | (recoverable ? KERN_WARNING : KERN_CRIT), | 1156 | (recoverable ? KERN_WARNING : KERN_CRIT), |
@@ -1115,7 +1161,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in | |||
1115 | 1161 | ||
1116 | syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT; | 1162 | syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT; |
1117 | syndrome = cheetah_mtag_syntab[syndrome]; | 1163 | syndrome = cheetah_mtag_syntab[syndrome]; |
1118 | ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum)); | 1164 | ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum)); |
1119 | if (ret != -1) | 1165 | if (ret != -1) |
1120 | printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n", | 1166 | printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n", |
1121 | (recoverable ? KERN_WARNING : KERN_CRIT), | 1167 | (recoverable ? KERN_WARNING : KERN_CRIT), |