diff options
author | Paul Mackerras <paulus@samba.org> | 2005-10-26 03:05:24 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-10-26 03:05:24 -0400 |
commit | 033ef338b6e007dc081c6282a4f2a9dd761f8cd2 (patch) | |
tree | 3c77fad71c3d9ba04ddcdaea33063aaf7520ddb0 | |
parent | f9bd170a87948a9e077149b70fb192c563770fdf (diff) |
powerpc: Merge rtas.c into arch/powerpc/kernel
This splits arch/ppc64/kernel/rtas.c into arch/powerpc/kernel/rtas.c,
which contains generic RTAS functions useful on any CHRP platform,
and arch/powerpc/platforms/pseries/rtas-fw.[ch], which contain
some pSeries-specific firmware flashing bits. The parts of rtas.c
that are to do with pSeries-specific error logging are protected
by a new CONFIG_RTAS_ERROR_LOGGING symbol. The inclusion of rtas.o
is controlled by the CONFIG_PPC_RTAS symbol, and the relevant
platforms select that.
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/Kconfig | 13 | ||||
-rw-r--r-- | arch/powerpc/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_32.S | 12 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/rtas.c (renamed from arch/ppc64/kernel/rtas.c) | 255 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/Kconfig | 5 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/rtas-fw.c | 138 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/rtas-fw.h | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 10 | ||||
-rw-r--r-- | arch/ppc64/Kconfig | 5 | ||||
-rw-r--r-- | arch/ppc64/kernel/Makefile | 2 |
13 files changed, 256 insertions, 199 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 9f279e0d84f2..ce5100cadd34 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -276,6 +276,8 @@ config PPC_PSERIES | |||
276 | depends on PPC_MULTIPLATFORM && PPC64 | 276 | depends on PPC_MULTIPLATFORM && PPC64 |
277 | bool " IBM pSeries & new (POWER5-based) iSeries" | 277 | bool " IBM pSeries & new (POWER5-based) iSeries" |
278 | select PPC_I8259 | 278 | select PPC_I8259 |
279 | select PPC_RTAS | ||
280 | select RTAS_ERROR_LOGGING | ||
279 | default y | 281 | default y |
280 | 282 | ||
281 | config PPC_CHRP | 283 | config PPC_CHRP |
@@ -283,6 +285,7 @@ config PPC_CHRP | |||
283 | depends on PPC_MULTIPLATFORM && PPC32 | 285 | depends on PPC_MULTIPLATFORM && PPC32 |
284 | select PPC_I8259 | 286 | select PPC_I8259 |
285 | select PPC_INDIRECT_PCI | 287 | select PPC_INDIRECT_PCI |
288 | select PPC_RTAS | ||
286 | default y | 289 | default y |
287 | 290 | ||
288 | config PPC_PMAC | 291 | config PPC_PMAC |
@@ -317,6 +320,7 @@ config PPC_MAPLE | |||
317 | config PPC_BPA | 320 | config PPC_BPA |
318 | bool " Broadband Processor Architecture" | 321 | bool " Broadband Processor Architecture" |
319 | depends on PPC_MULTIPLATFORM && PPC64 | 322 | depends on PPC_MULTIPLATFORM && PPC64 |
323 | select PPC_RTAS | ||
320 | 324 | ||
321 | config PPC_OF | 325 | config PPC_OF |
322 | bool | 326 | bool |
@@ -338,6 +342,15 @@ config MPIC | |||
338 | bool | 342 | bool |
339 | default y | 343 | default y |
340 | 344 | ||
345 | config PPC_RTAS | ||
346 | bool | ||
347 | default n | ||
348 | |||
349 | config RTAS_ERROR_LOGGING | ||
350 | bool | ||
351 | depends on PPC_RTAS | ||
352 | default n | ||
353 | |||
341 | config MPIC_BROKEN_U3 | 354 | config MPIC_BROKEN_U3 |
342 | bool | 355 | bool |
343 | depends on PPC_MAPLE | 356 | depends on PPC_MAPLE |
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index f5d8038fed52..eaedb7e63315 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -16,6 +16,7 @@ obj-$(CONFIG_PPC64) += binfmt_elf32.o sys_ppc32.o ptrace32.o | |||
16 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o | 16 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o |
17 | obj-$(CONFIG_POWER4) += idle_power4.o | 17 | obj-$(CONFIG_POWER4) += idle_power4.o |
18 | obj-$(CONFIG_PPC_OF) += of_device.o | 18 | obj-$(CONFIG_PPC_OF) += of_device.o |
19 | obj-$(CONFIG_PPC_RTAS) += rtas.o | ||
19 | obj-$(CONFIG_IBMVIO) += vio.o | 20 | obj-$(CONFIG_IBMVIO) += vio.o |
20 | 21 | ||
21 | ifeq ($(CONFIG_PPC_MERGE),y) | 22 | ifeq ($(CONFIG_PPC_MERGE),y) |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 1c83abd9f37c..710336a9f0fd 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -36,11 +36,11 @@ | |||
36 | #include <asm/processor.h> | 36 | #include <asm/processor.h> |
37 | #include <asm/cputable.h> | 37 | #include <asm/cputable.h> |
38 | #include <asm/thread_info.h> | 38 | #include <asm/thread_info.h> |
39 | #include <asm/rtas.h> | ||
39 | #ifdef CONFIG_PPC64 | 40 | #ifdef CONFIG_PPC64 |
40 | #include <asm/paca.h> | 41 | #include <asm/paca.h> |
41 | #include <asm/lppaca.h> | 42 | #include <asm/lppaca.h> |
42 | #include <asm/iSeries/HvLpEvent.h> | 43 | #include <asm/iSeries/HvLpEvent.h> |
43 | #include <asm/rtas.h> | ||
44 | #include <asm/cache.h> | 44 | #include <asm/cache.h> |
45 | #include <asm/systemcfg.h> | 45 | #include <asm/systemcfg.h> |
46 | #include <asm/compat.h> | 46 | #include <asm/compat.h> |
@@ -97,7 +97,7 @@ int main(void) | |||
97 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); | 97 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); |
98 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); | 98 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); |
99 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); | 99 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); |
100 | #endif /* CONFIG_PPC64 */ | 100 | #endif /* CONFIG_PPC32 */ |
101 | 101 | ||
102 | #ifdef CONFIG_PPC64 | 102 | #ifdef CONFIG_PPC64 |
103 | DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size)); | 103 | DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size)); |
@@ -142,11 +142,11 @@ int main(void) | |||
142 | DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); | 142 | DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); |
143 | DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int)); | 143 | DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int)); |
144 | DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int)); | 144 | DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int)); |
145 | #endif /* CONFIG_PPC64 */ | ||
145 | 146 | ||
146 | /* RTAS */ | 147 | /* RTAS */ |
147 | DEFINE(RTASBASE, offsetof(struct rtas_t, base)); | 148 | DEFINE(RTASBASE, offsetof(struct rtas_t, base)); |
148 | DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); | 149 | DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); |
149 | #endif /* CONFIG_PPC64 */ | ||
150 | 150 | ||
151 | /* Interrupt register frame */ | 151 | /* Interrupt register frame */ |
152 | DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); | 152 | DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); |
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 37b4396ca978..960da7bea043 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -954,7 +954,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) | |||
954 | * here so it's easy to add arch-specific sections later. | 954 | * here so it's easy to add arch-specific sections later. |
955 | * -- Cort | 955 | * -- Cort |
956 | */ | 956 | */ |
957 | #ifdef CONFIG_PPC_OF | 957 | #ifdef CONFIG_PPC_RTAS |
958 | /* | 958 | /* |
959 | * On CHRP, the Run-Time Abstraction Services (RTAS) have to be | 959 | * On CHRP, the Run-Time Abstraction Services (RTAS) have to be |
960 | * called with the MMU off. | 960 | * called with the MMU off. |
@@ -963,14 +963,13 @@ _GLOBAL(enter_rtas) | |||
963 | stwu r1,-INT_FRAME_SIZE(r1) | 963 | stwu r1,-INT_FRAME_SIZE(r1) |
964 | mflr r0 | 964 | mflr r0 |
965 | stw r0,INT_FRAME_SIZE+4(r1) | 965 | stw r0,INT_FRAME_SIZE+4(r1) |
966 | lis r4,rtas_data@ha | 966 | LOADADDR(r4, rtas) |
967 | lwz r4,rtas_data@l(r4) | ||
968 | lis r6,1f@ha /* physical return address for rtas */ | 967 | lis r6,1f@ha /* physical return address for rtas */ |
969 | addi r6,r6,1f@l | 968 | addi r6,r6,1f@l |
970 | tophys(r6,r6) | 969 | tophys(r6,r6) |
971 | tophys(r7,r1) | 970 | tophys(r7,r1) |
972 | lis r8,rtas_entry@ha | 971 | lwz r8,RTASENTRY(r4) |
973 | lwz r8,rtas_entry@l(r8) | 972 | lwz r4,RTASBASE(r4) |
974 | mfmsr r9 | 973 | mfmsr r9 |
975 | stw r9,8(r1) | 974 | stw r9,8(r1) |
976 | LOAD_MSR_KERNEL(r0,MSR_KERNEL) | 975 | LOAD_MSR_KERNEL(r0,MSR_KERNEL) |
@@ -978,7 +977,6 @@ _GLOBAL(enter_rtas) | |||
978 | MTMSRD(r0) /* don't get trashed */ | 977 | MTMSRD(r0) /* don't get trashed */ |
979 | li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR) | 978 | li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR) |
980 | mtlr r6 | 979 | mtlr r6 |
981 | CLR_TOP32(r7) | ||
982 | mtspr SPRN_SPRG2,r7 | 980 | mtspr SPRN_SPRG2,r7 |
983 | mtspr SPRN_SRR0,r8 | 981 | mtspr SPRN_SRR0,r8 |
984 | mtspr SPRN_SRR1,r9 | 982 | mtspr SPRN_SRR1,r9 |
@@ -999,4 +997,4 @@ machine_check_in_rtas: | |||
999 | twi 31,0,0 | 997 | twi 31,0,0 |
1000 | /* XXX load up BATs and panic */ | 998 | /* XXX load up BATs and panic */ |
1001 | 999 | ||
1002 | #endif /* CONFIG_PPC_OF */ | 1000 | #endif /* CONFIG_PPC_RTAS */ |
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 8d0c78cbc0bc..16ac15e73b44 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -110,9 +110,6 @@ struct device_node *of_chosen; | |||
110 | struct device_node *dflt_interrupt_controller; | 110 | struct device_node *dflt_interrupt_controller; |
111 | int num_interrupt_controllers; | 111 | int num_interrupt_controllers; |
112 | 112 | ||
113 | u32 rtas_data; | ||
114 | u32 rtas_entry; | ||
115 | |||
116 | /* | 113 | /* |
117 | * Wrapper for allocating memory for various data that needs to be | 114 | * Wrapper for allocating memory for various data that needs to be |
118 | * attached to device nodes as they are processed at boot or when | 115 | * attached to device nodes as they are processed at boot or when |
diff --git a/arch/ppc64/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 36adab591bd3..4d22eeeeb91d 100644 --- a/arch/ppc64/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c | |||
@@ -25,29 +25,29 @@ | |||
25 | #include <asm/page.h> | 25 | #include <asm/page.h> |
26 | #include <asm/param.h> | 26 | #include <asm/param.h> |
27 | #include <asm/system.h> | 27 | #include <asm/system.h> |
28 | #include <asm/abs_addr.h> | ||
29 | #include <asm/udbg.h> | ||
30 | #include <asm/delay.h> | 28 | #include <asm/delay.h> |
31 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
30 | #include <asm/lmb.h> | ||
31 | #ifdef CONFIG_PPC64 | ||
32 | #include <asm/systemcfg.h> | 32 | #include <asm/systemcfg.h> |
33 | #include <asm/ppcdebug.h> | 33 | #endif |
34 | 34 | ||
35 | struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; | 35 | struct rtas_t rtas = { |
36 | |||
37 | struct rtas_t rtas = { | ||
38 | .lock = SPIN_LOCK_UNLOCKED | 36 | .lock = SPIN_LOCK_UNLOCKED |
39 | }; | 37 | }; |
40 | 38 | ||
41 | EXPORT_SYMBOL(rtas); | 39 | EXPORT_SYMBOL(rtas); |
42 | 40 | ||
43 | char rtas_err_buf[RTAS_ERROR_LOG_MAX]; | ||
44 | |||
45 | DEFINE_SPINLOCK(rtas_data_buf_lock); | 41 | DEFINE_SPINLOCK(rtas_data_buf_lock); |
46 | char rtas_data_buf[RTAS_DATA_BUF_SIZE]__page_aligned; | 42 | char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned; |
47 | unsigned long rtas_rmo_buf; | 43 | unsigned long rtas_rmo_buf; |
48 | 44 | ||
49 | void | 45 | /* |
50 | call_rtas_display_status(unsigned char c) | 46 | * call_rtas_display_status and call_rtas_display_status_delay |
47 | * are designed only for very early low-level debugging, which | ||
48 | * is why the token is hard-coded to 10. | ||
49 | */ | ||
50 | void call_rtas_display_status(unsigned char c) | ||
51 | { | 51 | { |
52 | struct rtas_args *args = &rtas.args; | 52 | struct rtas_args *args = &rtas.args; |
53 | unsigned long s; | 53 | unsigned long s; |
@@ -67,8 +67,7 @@ call_rtas_display_status(unsigned char c) | |||
67 | spin_unlock_irqrestore(&rtas.lock, s); | 67 | spin_unlock_irqrestore(&rtas.lock, s); |
68 | } | 68 | } |
69 | 69 | ||
70 | void | 70 | void call_rtas_display_status_delay(unsigned char c) |
71 | call_rtas_display_status_delay(unsigned char c) | ||
72 | { | 71 | { |
73 | static int pending_newline = 0; /* did last write end with unprinted newline? */ | 72 | static int pending_newline = 0; /* did last write end with unprinted newline? */ |
74 | static int width = 16; | 73 | static int width = 16; |
@@ -92,8 +91,7 @@ call_rtas_display_status_delay(unsigned char c) | |||
92 | } | 91 | } |
93 | } | 92 | } |
94 | 93 | ||
95 | void | 94 | void rtas_progress(char *s, unsigned short hex) |
96 | rtas_progress(char *s, unsigned short hex) | ||
97 | { | 95 | { |
98 | struct device_node *root; | 96 | struct device_node *root; |
99 | int width, *p; | 97 | int width, *p; |
@@ -209,18 +207,16 @@ rtas_progress(char *s, unsigned short hex) | |||
209 | spin_unlock(&progress_lock); | 207 | spin_unlock(&progress_lock); |
210 | } | 208 | } |
211 | 209 | ||
212 | int | 210 | int rtas_token(const char *service) |
213 | rtas_token(const char *service) | ||
214 | { | 211 | { |
215 | int *tokp; | 212 | int *tokp; |
216 | if (rtas.dev == NULL) { | 213 | if (rtas.dev == NULL) |
217 | PPCDBG(PPCDBG_RTAS,"\tNo rtas device in device-tree...\n"); | ||
218 | return RTAS_UNKNOWN_SERVICE; | 214 | return RTAS_UNKNOWN_SERVICE; |
219 | } | ||
220 | tokp = (int *) get_property(rtas.dev, service, NULL); | 215 | tokp = (int *) get_property(rtas.dev, service, NULL); |
221 | return tokp ? *tokp : RTAS_UNKNOWN_SERVICE; | 216 | return tokp ? *tokp : RTAS_UNKNOWN_SERVICE; |
222 | } | 217 | } |
223 | 218 | ||
219 | #ifdef CONFIG_RTAS_ERROR_LOGGING | ||
224 | /* | 220 | /* |
225 | * Return the firmware-specified size of the error log buffer | 221 | * Return the firmware-specified size of the error log buffer |
226 | * for all rtas calls that require an error buffer argument. | 222 | * for all rtas calls that require an error buffer argument. |
@@ -235,31 +231,38 @@ int rtas_get_error_log_max(void) | |||
235 | rtas_error_log_max = rtas_token ("rtas-error-log-max"); | 231 | rtas_error_log_max = rtas_token ("rtas-error-log-max"); |
236 | if ((rtas_error_log_max == RTAS_UNKNOWN_SERVICE) || | 232 | if ((rtas_error_log_max == RTAS_UNKNOWN_SERVICE) || |
237 | (rtas_error_log_max > RTAS_ERROR_LOG_MAX)) { | 233 | (rtas_error_log_max > RTAS_ERROR_LOG_MAX)) { |
238 | printk (KERN_WARNING "RTAS: bad log buffer size %d\n", rtas_error_log_max); | 234 | printk (KERN_WARNING "RTAS: bad log buffer size %d\n", |
235 | rtas_error_log_max); | ||
239 | rtas_error_log_max = RTAS_ERROR_LOG_MAX; | 236 | rtas_error_log_max = RTAS_ERROR_LOG_MAX; |
240 | } | 237 | } |
241 | return rtas_error_log_max; | 238 | return rtas_error_log_max; |
242 | } | 239 | } |
240 | EXPORT_SYMBOL(rtas_get_error_log_max); | ||
243 | 241 | ||
244 | 242 | ||
243 | char rtas_err_buf[RTAS_ERROR_LOG_MAX]; | ||
244 | int rtas_last_error_token; | ||
245 | |||
245 | /** Return a copy of the detailed error text associated with the | 246 | /** Return a copy of the detailed error text associated with the |
246 | * most recent failed call to rtas. Because the error text | 247 | * most recent failed call to rtas. Because the error text |
247 | * might go stale if there are any other intervening rtas calls, | 248 | * might go stale if there are any other intervening rtas calls, |
248 | * this routine must be called atomically with whatever produced | 249 | * this routine must be called atomically with whatever produced |
249 | * the error (i.e. with rtas.lock still held from the previous call). | 250 | * the error (i.e. with rtas.lock still held from the previous call). |
250 | */ | 251 | */ |
251 | static int | 252 | static char *__fetch_rtas_last_error(char *altbuf) |
252 | __fetch_rtas_last_error(void) | ||
253 | { | 253 | { |
254 | struct rtas_args err_args, save_args; | 254 | struct rtas_args err_args, save_args; |
255 | u32 bufsz; | 255 | u32 bufsz; |
256 | char *buf = NULL; | ||
257 | |||
258 | if (rtas_last_error_token == -1) | ||
259 | return NULL; | ||
256 | 260 | ||
257 | bufsz = rtas_get_error_log_max(); | 261 | bufsz = rtas_get_error_log_max(); |
258 | 262 | ||
259 | err_args.token = rtas_token("rtas-last-error"); | 263 | err_args.token = rtas_last_error_token; |
260 | err_args.nargs = 2; | 264 | err_args.nargs = 2; |
261 | err_args.nret = 1; | 265 | err_args.nret = 1; |
262 | |||
263 | err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); | 266 | err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); |
264 | err_args.args[1] = bufsz; | 267 | err_args.args[1] = bufsz; |
265 | err_args.args[2] = 0; | 268 | err_args.args[2] = 0; |
@@ -272,23 +275,38 @@ __fetch_rtas_last_error(void) | |||
272 | err_args = rtas.args; | 275 | err_args = rtas.args; |
273 | rtas.args = save_args; | 276 | rtas.args = save_args; |
274 | 277 | ||
275 | return err_args.args[2]; | 278 | /* Log the error in the unlikely case that there was one. */ |
279 | if (unlikely(err_args.args[2] == 0)) { | ||
280 | if (altbuf) { | ||
281 | buf = altbuf; | ||
282 | } else { | ||
283 | buf = rtas_err_buf; | ||
284 | if (mem_init_done) | ||
285 | buf = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); | ||
286 | } | ||
287 | if (buf) | ||
288 | memcpy(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX); | ||
289 | } | ||
290 | |||
291 | return buf; | ||
276 | } | 292 | } |
277 | 293 | ||
294 | #define get_errorlog_buffer() kmalloc(RTAS_ERROR_LOG_MAX, GFP_KERNEL) | ||
295 | |||
296 | #else /* CONFIG_RTAS_ERROR_LOGGING */ | ||
297 | #define __fetch_rtas_last_error(x) NULL | ||
298 | #define get_errorlog_buffer() NULL | ||
299 | #endif | ||
300 | |||
278 | int rtas_call(int token, int nargs, int nret, int *outputs, ...) | 301 | int rtas_call(int token, int nargs, int nret, int *outputs, ...) |
279 | { | 302 | { |
280 | va_list list; | 303 | va_list list; |
281 | int i, logit = 0; | 304 | int i; |
282 | unsigned long s; | 305 | unsigned long s; |
283 | struct rtas_args *rtas_args; | 306 | struct rtas_args *rtas_args; |
284 | char * buff_copy = NULL; | 307 | char *buff_copy = NULL; |
285 | int ret; | 308 | int ret; |
286 | 309 | ||
287 | PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); | ||
288 | PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); | ||
289 | PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); | ||
290 | PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); | ||
291 | PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); | ||
292 | if (token == RTAS_UNKNOWN_SERVICE) | 310 | if (token == RTAS_UNKNOWN_SERVICE) |
293 | return -1; | 311 | return -1; |
294 | 312 | ||
@@ -301,46 +319,25 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) | |||
301 | rtas_args->nret = nret; | 319 | rtas_args->nret = nret; |
302 | rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); | 320 | rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); |
303 | va_start(list, outputs); | 321 | va_start(list, outputs); |
304 | for (i = 0; i < nargs; ++i) { | 322 | for (i = 0; i < nargs; ++i) |
305 | rtas_args->args[i] = va_arg(list, rtas_arg_t); | 323 | rtas_args->args[i] = va_arg(list, rtas_arg_t); |
306 | PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%x\n", i, rtas_args->args[i]); | ||
307 | } | ||
308 | va_end(list); | 324 | va_end(list); |
309 | 325 | ||
310 | for (i = 0; i < nret; ++i) | 326 | for (i = 0; i < nret; ++i) |
311 | rtas_args->rets[i] = 0; | 327 | rtas_args->rets[i] = 0; |
312 | 328 | ||
313 | PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", | ||
314 | __pa(rtas_args)); | ||
315 | enter_rtas(__pa(rtas_args)); | 329 | enter_rtas(__pa(rtas_args)); |
316 | PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); | ||
317 | 330 | ||
318 | /* A -1 return code indicates that the last command couldn't | 331 | /* A -1 return code indicates that the last command couldn't |
319 | be completed due to a hardware error. */ | 332 | be completed due to a hardware error. */ |
320 | if (rtas_args->rets[0] == -1) | 333 | if (rtas_args->rets[0] == -1) |
321 | logit = (__fetch_rtas_last_error() == 0); | 334 | buff_copy = __fetch_rtas_last_error(NULL); |
322 | |||
323 | ifppcdebug(PPCDBG_RTAS) { | ||
324 | for(i=0; i < nret ;i++) | ||
325 | udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); | ||
326 | } | ||
327 | 335 | ||
328 | if (nret > 1 && outputs != NULL) | 336 | if (nret > 1 && outputs != NULL) |
329 | for (i = 0; i < nret-1; ++i) | 337 | for (i = 0; i < nret-1; ++i) |
330 | outputs[i] = rtas_args->rets[i+1]; | 338 | outputs[i] = rtas_args->rets[i+1]; |
331 | ret = (nret > 0)? rtas_args->rets[0]: 0; | 339 | ret = (nret > 0)? rtas_args->rets[0]: 0; |
332 | 340 | ||
333 | /* Log the error in the unlikely case that there was one. */ | ||
334 | if (unlikely(logit)) { | ||
335 | buff_copy = rtas_err_buf; | ||
336 | if (mem_init_done) { | ||
337 | buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); | ||
338 | if (buff_copy) | ||
339 | memcpy(buff_copy, rtas_err_buf, | ||
340 | RTAS_ERROR_LOG_MAX); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /* Gotta do something different here, use global lock for now... */ | 341 | /* Gotta do something different here, use global lock for now... */ |
345 | spin_unlock_irqrestore(&rtas.lock, s); | 342 | spin_unlock_irqrestore(&rtas.lock, s); |
346 | 343 | ||
@@ -355,8 +352,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) | |||
355 | /* Given an RTAS status code of 990n compute the hinted delay of 10^n | 352 | /* Given an RTAS status code of 990n compute the hinted delay of 10^n |
356 | * (last digit) milliseconds. For now we bound at n=5 (100 sec). | 353 | * (last digit) milliseconds. For now we bound at n=5 (100 sec). |
357 | */ | 354 | */ |
358 | unsigned int | 355 | unsigned int rtas_extended_busy_delay_time(int status) |
359 | rtas_extended_busy_delay_time(int status) | ||
360 | { | 356 | { |
361 | int order = status - 9900; | 357 | int order = status - 9900; |
362 | unsigned long ms; | 358 | unsigned long ms; |
@@ -367,7 +363,7 @@ rtas_extended_busy_delay_time(int status) | |||
367 | order = 5; /* bound */ | 363 | order = 5; /* bound */ |
368 | 364 | ||
369 | /* Use microseconds for reasonable accuracy */ | 365 | /* Use microseconds for reasonable accuracy */ |
370 | for (ms=1; order > 0; order--) | 366 | for (ms = 1; order > 0; order--) |
371 | ms *= 10; | 367 | ms *= 10; |
372 | 368 | ||
373 | return ms; | 369 | return ms; |
@@ -494,112 +490,23 @@ int rtas_set_indicator(int indicator, int index, int new_value) | |||
494 | return rc; | 490 | return rc; |
495 | } | 491 | } |
496 | 492 | ||
497 | #define FLASH_BLOCK_LIST_VERSION (1UL) | 493 | void rtas_restart(char *cmd) |
498 | static void | ||
499 | rtas_flash_firmware(void) | ||
500 | { | ||
501 | unsigned long image_size; | ||
502 | struct flash_block_list *f, *next, *flist; | ||
503 | unsigned long rtas_block_list; | ||
504 | int i, status, update_token; | ||
505 | |||
506 | update_token = rtas_token("ibm,update-flash-64-and-reboot"); | ||
507 | if (update_token == RTAS_UNKNOWN_SERVICE) { | ||
508 | printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot is not available -- not a service partition?\n"); | ||
509 | printk(KERN_ALERT "FLASH: firmware will not be flashed\n"); | ||
510 | return; | ||
511 | } | ||
512 | |||
513 | /* NOTE: the "first" block list is a global var with no data | ||
514 | * blocks in the kernel data segment. We do this because | ||
515 | * we want to ensure this block_list addr is under 4GB. | ||
516 | */ | ||
517 | rtas_firmware_flash_list.num_blocks = 0; | ||
518 | flist = (struct flash_block_list *)&rtas_firmware_flash_list; | ||
519 | rtas_block_list = virt_to_abs(flist); | ||
520 | if (rtas_block_list >= 4UL*1024*1024*1024) { | ||
521 | printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); | ||
522 | return; | ||
523 | } | ||
524 | |||
525 | printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n"); | ||
526 | /* Update the block_list in place. */ | ||
527 | image_size = 0; | ||
528 | for (f = flist; f; f = next) { | ||
529 | /* Translate data addrs to absolute */ | ||
530 | for (i = 0; i < f->num_blocks; i++) { | ||
531 | f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data); | ||
532 | image_size += f->blocks[i].length; | ||
533 | } | ||
534 | next = f->next; | ||
535 | /* Don't translate NULL pointer for last entry */ | ||
536 | if (f->next) | ||
537 | f->next = (struct flash_block_list *)virt_to_abs(f->next); | ||
538 | else | ||
539 | f->next = NULL; | ||
540 | /* make num_blocks into the version/length field */ | ||
541 | f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16); | ||
542 | } | ||
543 | |||
544 | printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size); | ||
545 | printk(KERN_ALERT "FLASH: performing flash and reboot\n"); | ||
546 | rtas_progress("Flashing \n", 0x0); | ||
547 | rtas_progress("Please Wait... ", 0x0); | ||
548 | printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n"); | ||
549 | status = rtas_call(update_token, 1, 1, NULL, rtas_block_list); | ||
550 | switch (status) { /* should only get "bad" status */ | ||
551 | case 0: | ||
552 | printk(KERN_ALERT "FLASH: success\n"); | ||
553 | break; | ||
554 | case -1: | ||
555 | printk(KERN_ALERT "FLASH: hardware error. Firmware may not be not flashed\n"); | ||
556 | break; | ||
557 | case -3: | ||
558 | printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform. Firmware not flashed\n"); | ||
559 | break; | ||
560 | case -4: | ||
561 | printk(KERN_ALERT "FLASH: flash failed when partially complete. System may not reboot\n"); | ||
562 | break; | ||
563 | default: | ||
564 | printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status); | ||
565 | break; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | void rtas_flash_bypass_warning(void) | ||
570 | { | ||
571 | printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n"); | ||
572 | printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n"); | ||
573 | } | ||
574 | |||
575 | |||
576 | void | ||
577 | rtas_restart(char *cmd) | ||
578 | { | 494 | { |
579 | if (rtas_firmware_flash_list.next) | ||
580 | rtas_flash_firmware(); | ||
581 | |||
582 | printk("RTAS system-reboot returned %d\n", | 495 | printk("RTAS system-reboot returned %d\n", |
583 | rtas_call(rtas_token("system-reboot"), 0, 1, NULL)); | 496 | rtas_call(rtas_token("system-reboot"), 0, 1, NULL)); |
584 | for (;;); | 497 | for (;;); |
585 | } | 498 | } |
586 | 499 | ||
587 | void | 500 | void rtas_power_off(void) |
588 | rtas_power_off(void) | ||
589 | { | 501 | { |
590 | if (rtas_firmware_flash_list.next) | ||
591 | rtas_flash_bypass_warning(); | ||
592 | /* allow power on only with power button press */ | 502 | /* allow power on only with power button press */ |
593 | printk("RTAS power-off returned %d\n", | 503 | printk("RTAS power-off returned %d\n", |
594 | rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1)); | 504 | rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1)); |
595 | for (;;); | 505 | for (;;); |
596 | } | 506 | } |
597 | 507 | ||
598 | void | 508 | void rtas_halt(void) |
599 | rtas_halt(void) | ||
600 | { | 509 | { |
601 | if (rtas_firmware_flash_list.next) | ||
602 | rtas_flash_bypass_warning(); | ||
603 | rtas_power_off(); | 510 | rtas_power_off(); |
604 | } | 511 | } |
605 | 512 | ||
@@ -632,9 +539,8 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) | |||
632 | { | 539 | { |
633 | struct rtas_args args; | 540 | struct rtas_args args; |
634 | unsigned long flags; | 541 | unsigned long flags; |
635 | char * buff_copy; | 542 | char *buff_copy, *errbuf = NULL; |
636 | int nargs; | 543 | int nargs; |
637 | int err_rc = 0; | ||
638 | 544 | ||
639 | if (!capable(CAP_SYS_ADMIN)) | 545 | if (!capable(CAP_SYS_ADMIN)) |
640 | return -EPERM; | 546 | return -EPERM; |
@@ -653,7 +559,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) | |||
653 | nargs * sizeof(rtas_arg_t)) != 0) | 559 | nargs * sizeof(rtas_arg_t)) != 0) |
654 | return -EFAULT; | 560 | return -EFAULT; |
655 | 561 | ||
656 | buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_KERNEL); | 562 | buff_copy = get_errorlog_buffer(); |
657 | 563 | ||
658 | spin_lock_irqsave(&rtas.lock, flags); | 564 | spin_lock_irqsave(&rtas.lock, flags); |
659 | 565 | ||
@@ -665,19 +571,14 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) | |||
665 | 571 | ||
666 | /* A -1 return code indicates that the last command couldn't | 572 | /* A -1 return code indicates that the last command couldn't |
667 | be completed due to a hardware error. */ | 573 | be completed due to a hardware error. */ |
668 | if (args.rets[0] == -1) { | 574 | if (args.rets[0] == -1) |
669 | err_rc = __fetch_rtas_last_error(); | 575 | errbuf = __fetch_rtas_last_error(buff_copy); |
670 | if ((err_rc == 0) && buff_copy) { | ||
671 | memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); | ||
672 | } | ||
673 | } | ||
674 | 576 | ||
675 | spin_unlock_irqrestore(&rtas.lock, flags); | 577 | spin_unlock_irqrestore(&rtas.lock, flags); |
676 | 578 | ||
677 | if (buff_copy) { | 579 | if (buff_copy) { |
678 | if ((args.rets[0] == -1) && (err_rc == 0)) { | 580 | if (errbuf) |
679 | log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); | 581 | log_error(errbuf, ERR_TYPE_RTAS_LOG, 0); |
680 | } | ||
681 | kfree(buff_copy); | 582 | kfree(buff_copy); |
682 | } | 583 | } |
683 | 584 | ||
@@ -690,6 +591,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) | |||
690 | return 0; | 591 | return 0; |
691 | } | 592 | } |
692 | 593 | ||
594 | #ifdef CONFIG_SMP | ||
693 | /* This version can't take the spinlock, because it never returns */ | 595 | /* This version can't take the spinlock, because it never returns */ |
694 | 596 | ||
695 | struct rtas_args rtas_stop_self_args = { | 597 | struct rtas_args rtas_stop_self_args = { |
@@ -714,6 +616,7 @@ void rtas_stop_self(void) | |||
714 | 616 | ||
715 | panic("Alas, I survived.\n"); | 617 | panic("Alas, I survived.\n"); |
716 | } | 618 | } |
619 | #endif | ||
717 | 620 | ||
718 | /* | 621 | /* |
719 | * Call early during boot, before mem init or bootmem, to retreive the RTAS | 622 | * Call early during boot, before mem init or bootmem, to retreive the RTAS |
@@ -722,6 +625,8 @@ void rtas_stop_self(void) | |||
722 | */ | 625 | */ |
723 | void __init rtas_initialize(void) | 626 | void __init rtas_initialize(void) |
724 | { | 627 | { |
628 | unsigned long rtas_region = RTAS_INSTANTIATE_MAX; | ||
629 | |||
725 | /* Get RTAS dev node and fill up our "rtas" structure with infos | 630 | /* Get RTAS dev node and fill up our "rtas" structure with infos |
726 | * about it. | 631 | * about it. |
727 | */ | 632 | */ |
@@ -743,26 +648,27 @@ void __init rtas_initialize(void) | |||
743 | } else | 648 | } else |
744 | rtas.dev = NULL; | 649 | rtas.dev = NULL; |
745 | } | 650 | } |
651 | if (!rtas.dev) | ||
652 | return; | ||
653 | |||
746 | /* If RTAS was found, allocate the RMO buffer for it and look for | 654 | /* If RTAS was found, allocate the RMO buffer for it and look for |
747 | * the stop-self token if any | 655 | * the stop-self token if any |
748 | */ | 656 | */ |
749 | if (rtas.dev) { | 657 | #ifdef CONFIG_PPC64 |
750 | unsigned long rtas_region = RTAS_INSTANTIATE_MAX; | 658 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) |
751 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) | 659 | rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); |
752 | rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); | 660 | #endif |
753 | 661 | rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region); | |
754 | rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, | ||
755 | rtas_region); | ||
756 | 662 | ||
757 | #ifdef CONFIG_HOTPLUG_CPU | 663 | #ifdef CONFIG_HOTPLUG_CPU |
758 | rtas_stop_self_args.token = rtas_token("stop-self"); | 664 | rtas_stop_self_args.token = rtas_token("stop-self"); |
759 | #endif /* CONFIG_HOTPLUG_CPU */ | 665 | #endif /* CONFIG_HOTPLUG_CPU */ |
760 | } | 666 | #ifdef CONFIG_RTAS_ERROR_LOGGING |
761 | 667 | rtas_last_error_token = rtas_token("rtas-last-error"); | |
668 | #endif | ||
762 | } | 669 | } |
763 | 670 | ||
764 | 671 | ||
765 | EXPORT_SYMBOL(rtas_firmware_flash_list); | ||
766 | EXPORT_SYMBOL(rtas_token); | 672 | EXPORT_SYMBOL(rtas_token); |
767 | EXPORT_SYMBOL(rtas_call); | 673 | EXPORT_SYMBOL(rtas_call); |
768 | EXPORT_SYMBOL(rtas_data_buf); | 674 | EXPORT_SYMBOL(rtas_data_buf); |
@@ -772,4 +678,3 @@ EXPORT_SYMBOL(rtas_get_sensor); | |||
772 | EXPORT_SYMBOL(rtas_get_power_level); | 678 | EXPORT_SYMBOL(rtas_get_power_level); |
773 | EXPORT_SYMBOL(rtas_set_power_level); | 679 | EXPORT_SYMBOL(rtas_set_power_level); |
774 | EXPORT_SYMBOL(rtas_set_indicator); | 680 | EXPORT_SYMBOL(rtas_set_indicator); |
775 | EXPORT_SYMBOL(rtas_get_error_log_max); | ||
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 7a3b6fc4d976..2d57f588151d 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig | |||
@@ -21,11 +21,6 @@ config EEH | |||
21 | depends on PPC_PSERIES | 21 | depends on PPC_PSERIES |
22 | default y if !EMBEDDED | 22 | default y if !EMBEDDED |
23 | 23 | ||
24 | config PPC_RTAS | ||
25 | bool | ||
26 | depends on PPC_PSERIES || PPC_BPA | ||
27 | default y | ||
28 | |||
29 | config RTAS_PROC | 24 | config RTAS_PROC |
30 | bool "Proc interface to RTAS" | 25 | bool "Proc interface to RTAS" |
31 | depends on PPC_RTAS | 26 | depends on PPC_RTAS |
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 4c817304fc21..d5c160b789e3 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ | 1 | obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ |
2 | setup.o iommu.o ras.o | 2 | setup.o iommu.o rtas-fw.o ras.o |
3 | obj-$(CONFIG_SMP) += smp.o | 3 | obj-$(CONFIG_SMP) += smp.o |
4 | obj-$(CONFIG_IBMVIO) += vio.o | 4 | obj-$(CONFIG_IBMVIO) += vio.o |
diff --git a/arch/powerpc/platforms/pseries/rtas-fw.c b/arch/powerpc/platforms/pseries/rtas-fw.c new file mode 100644 index 000000000000..15d81d758ca0 --- /dev/null +++ b/arch/powerpc/platforms/pseries/rtas-fw.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Procedures for firmware flash updates on pSeries systems. | ||
4 | * | ||
5 | * Peter Bergner, IBM March 2001. | ||
6 | * Copyright (C) 2001 IBM. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <stdarg.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | |||
21 | #include <asm/prom.h> | ||
22 | #include <asm/rtas.h> | ||
23 | #include <asm/semaphore.h> | ||
24 | #include <asm/machdep.h> | ||
25 | #include <asm/page.h> | ||
26 | #include <asm/param.h> | ||
27 | #include <asm/system.h> | ||
28 | #include <asm/abs_addr.h> | ||
29 | #include <asm/udbg.h> | ||
30 | #include <asm/delay.h> | ||
31 | #include <asm/uaccess.h> | ||
32 | #include <asm/systemcfg.h> | ||
33 | |||
34 | #include "rtas-fw.h" | ||
35 | |||
36 | struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; | ||
37 | |||
38 | #define FLASH_BLOCK_LIST_VERSION (1UL) | ||
39 | |||
40 | static void rtas_flash_firmware(void) | ||
41 | { | ||
42 | unsigned long image_size; | ||
43 | struct flash_block_list *f, *next, *flist; | ||
44 | unsigned long rtas_block_list; | ||
45 | int i, status, update_token; | ||
46 | |||
47 | update_token = rtas_token("ibm,update-flash-64-and-reboot"); | ||
48 | if (update_token == RTAS_UNKNOWN_SERVICE) { | ||
49 | printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot is not available -- not a service partition?\n"); | ||
50 | printk(KERN_ALERT "FLASH: firmware will not be flashed\n"); | ||
51 | return; | ||
52 | } | ||
53 | |||
54 | /* NOTE: the "first" block list is a global var with no data | ||
55 | * blocks in the kernel data segment. We do this because | ||
56 | * we want to ensure this block_list addr is under 4GB. | ||
57 | */ | ||
58 | rtas_firmware_flash_list.num_blocks = 0; | ||
59 | flist = (struct flash_block_list *)&rtas_firmware_flash_list; | ||
60 | rtas_block_list = virt_to_abs(flist); | ||
61 | if (rtas_block_list >= 4UL*1024*1024*1024) { | ||
62 | printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n"); | ||
67 | /* Update the block_list in place. */ | ||
68 | image_size = 0; | ||
69 | for (f = flist; f; f = next) { | ||
70 | /* Translate data addrs to absolute */ | ||
71 | for (i = 0; i < f->num_blocks; i++) { | ||
72 | f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data); | ||
73 | image_size += f->blocks[i].length; | ||
74 | } | ||
75 | next = f->next; | ||
76 | /* Don't translate NULL pointer for last entry */ | ||
77 | if (f->next) | ||
78 | f->next = (struct flash_block_list *)virt_to_abs(f->next); | ||
79 | else | ||
80 | f->next = NULL; | ||
81 | /* make num_blocks into the version/length field */ | ||
82 | f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16); | ||
83 | } | ||
84 | |||
85 | printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size); | ||
86 | printk(KERN_ALERT "FLASH: performing flash and reboot\n"); | ||
87 | rtas_progress("Flashing \n", 0x0); | ||
88 | rtas_progress("Please Wait... ", 0x0); | ||
89 | printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n"); | ||
90 | status = rtas_call(update_token, 1, 1, NULL, rtas_block_list); | ||
91 | switch (status) { /* should only get "bad" status */ | ||
92 | case 0: | ||
93 | printk(KERN_ALERT "FLASH: success\n"); | ||
94 | break; | ||
95 | case -1: | ||
96 | printk(KERN_ALERT "FLASH: hardware error. Firmware may not be not flashed\n"); | ||
97 | break; | ||
98 | case -3: | ||
99 | printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform. Firmware not flashed\n"); | ||
100 | break; | ||
101 | case -4: | ||
102 | printk(KERN_ALERT "FLASH: flash failed when partially complete. System may not reboot\n"); | ||
103 | break; | ||
104 | default: | ||
105 | printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status); | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | void rtas_flash_bypass_warning(void) | ||
111 | { | ||
112 | printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n"); | ||
113 | printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n"); | ||
114 | } | ||
115 | |||
116 | |||
117 | void rtas_fw_restart(char *cmd) | ||
118 | { | ||
119 | if (rtas_firmware_flash_list.next) | ||
120 | rtas_flash_firmware(); | ||
121 | rtas_restart(cmd); | ||
122 | } | ||
123 | |||
124 | void rtas_fw_power_off(void) | ||
125 | { | ||
126 | if (rtas_firmware_flash_list.next) | ||
127 | rtas_flash_bypass_warning(); | ||
128 | rtas_power_off(); | ||
129 | } | ||
130 | |||
131 | void rtas_fw_halt(void) | ||
132 | { | ||
133 | if (rtas_firmware_flash_list.next) | ||
134 | rtas_flash_bypass_warning(); | ||
135 | rtas_halt(); | ||
136 | } | ||
137 | |||
138 | EXPORT_SYMBOL(rtas_firmware_flash_list); | ||
diff --git a/arch/powerpc/platforms/pseries/rtas-fw.h b/arch/powerpc/platforms/pseries/rtas-fw.h new file mode 100644 index 000000000000..e70fa69974a3 --- /dev/null +++ b/arch/powerpc/platforms/pseries/rtas-fw.h | |||
@@ -0,0 +1,3 @@ | |||
1 | void rtas_fw_restart(char *cmd); | ||
2 | void rtas_fw_power_off(void); | ||
3 | void rtas_fw_halt(void); | ||
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 0fa5beae6d1b..7e7e556e6b48 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/arch/ppc/kernel/setup.c | 2 | * 64-bit pSeries and RS/6000 setup code. |
3 | * | 3 | * |
4 | * Copyright (C) 1995 Linus Torvalds | 4 | * Copyright (C) 1995 Linus Torvalds |
5 | * Adapted from 'alpha' version by Gary Thomas | 5 | * Adapted from 'alpha' version by Gary Thomas |
@@ -67,6 +67,8 @@ | |||
67 | #include <asm/i8259.h> | 67 | #include <asm/i8259.h> |
68 | #include <asm/udbg.h> | 68 | #include <asm/udbg.h> |
69 | 69 | ||
70 | #include "rtas-fw.h" | ||
71 | |||
70 | #ifdef DEBUG | 72 | #ifdef DEBUG |
71 | #define DBG(fmt...) udbg_printf(fmt) | 73 | #define DBG(fmt...) udbg_printf(fmt) |
72 | #else | 74 | #else |
@@ -589,9 +591,9 @@ struct machdep_calls __initdata pSeries_md = { | |||
589 | .pcibios_fixup = pSeries_final_fixup, | 591 | .pcibios_fixup = pSeries_final_fixup, |
590 | .pci_probe_mode = pSeries_pci_probe_mode, | 592 | .pci_probe_mode = pSeries_pci_probe_mode, |
591 | .irq_bus_setup = pSeries_irq_bus_setup, | 593 | .irq_bus_setup = pSeries_irq_bus_setup, |
592 | .restart = rtas_restart, | 594 | .restart = rtas_fw_restart, |
593 | .power_off = rtas_power_off, | 595 | .power_off = rtas_fw_power_off, |
594 | .halt = rtas_halt, | 596 | .halt = rtas_fw_halt, |
595 | .panic = rtas_os_term, | 597 | .panic = rtas_os_term, |
596 | .cpu_die = pSeries_mach_cpu_die, | 598 | .cpu_die = pSeries_mach_cpu_die, |
597 | .get_boot_time = rtas_get_boot_time, | 599 | .get_boot_time = rtas_get_boot_time, |
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 963f519b7713..8cc73cc1b4c4 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig | |||
@@ -318,6 +318,11 @@ config PPC_RTAS | |||
318 | depends on PPC_PSERIES || PPC_BPA | 318 | depends on PPC_PSERIES || PPC_BPA |
319 | default y | 319 | default y |
320 | 320 | ||
321 | config RTAS_ERROR_LOGGING | ||
322 | bool | ||
323 | depends on PPC_RTAS | ||
324 | default y | ||
325 | |||
321 | config RTAS_PROC | 326 | config RTAS_PROC |
322 | bool "Proc interface to RTAS" | 327 | bool "Proc interface to RTAS" |
323 | depends on PPC_RTAS | 328 | depends on PPC_RTAS |
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 2c541c6652b2..83ecefdcfef7 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile | |||
@@ -43,7 +43,7 @@ obj-$(CONFIG_MODULES) += module.o | |||
43 | ifneq ($(CONFIG_PPC_MERGE),y) | 43 | ifneq ($(CONFIG_PPC_MERGE),y) |
44 | obj-$(CONFIG_MODULES) += ppc_ksyms.o | 44 | obj-$(CONFIG_MODULES) += ppc_ksyms.o |
45 | endif | 45 | endif |
46 | obj-$(CONFIG_PPC_RTAS) += rtas.o rtas_pci.o | 46 | obj-$(CONFIG_PPC_RTAS) += rtas_pci.o |
47 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o | 47 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o |
48 | obj-$(CONFIG_SCANLOG) += scanlog.o | 48 | obj-$(CONFIG_SCANLOG) += scanlog.o |
49 | obj-$(CONFIG_LPARCFG) += lparcfg.o | 49 | obj-$(CONFIG_LPARCFG) += lparcfg.o |