aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-10-26 03:05:24 -0400
committerPaul Mackerras <paulus@samba.org>2005-10-26 03:05:24 -0400
commit033ef338b6e007dc081c6282a4f2a9dd761f8cd2 (patch)
tree3c77fad71c3d9ba04ddcdaea33063aaf7520ddb0
parentf9bd170a87948a9e077149b70fb192c563770fdf (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/Kconfig13
-rw-r--r--arch/powerpc/kernel/Makefile1
-rw-r--r--arch/powerpc/kernel/asm-offsets.c6
-rw-r--r--arch/powerpc/kernel/entry_32.S12
-rw-r--r--arch/powerpc/kernel/prom.c3
-rw-r--r--arch/powerpc/kernel/rtas.c (renamed from arch/ppc64/kernel/rtas.c)255
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig5
-rw-r--r--arch/powerpc/platforms/pseries/Makefile2
-rw-r--r--arch/powerpc/platforms/pseries/rtas-fw.c138
-rw-r--r--arch/powerpc/platforms/pseries/rtas-fw.h3
-rw-r--r--arch/powerpc/platforms/pseries/setup.c10
-rw-r--r--arch/ppc64/Kconfig5
-rw-r--r--arch/ppc64/kernel/Makefile2
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
281config PPC_CHRP 283config 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
288config PPC_PMAC 291config PPC_PMAC
@@ -317,6 +320,7 @@ config PPC_MAPLE
317config PPC_BPA 320config 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
321config PPC_OF 325config PPC_OF
322 bool 326 bool
@@ -338,6 +342,15 @@ config MPIC
338 bool 342 bool
339 default y 343 default y
340 344
345config PPC_RTAS
346 bool
347 default n
348
349config RTAS_ERROR_LOGGING
350 bool
351 depends on PPC_RTAS
352 default n
353
341config MPIC_BROKEN_U3 354config 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
16obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o 16obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
17obj-$(CONFIG_POWER4) += idle_power4.o 17obj-$(CONFIG_POWER4) += idle_power4.o
18obj-$(CONFIG_PPC_OF) += of_device.o 18obj-$(CONFIG_PPC_OF) += of_device.o
19obj-$(CONFIG_PPC_RTAS) += rtas.o
19obj-$(CONFIG_IBMVIO) += vio.o 20obj-$(CONFIG_IBMVIO) += vio.o
20 21
21ifeq ($(CONFIG_PPC_MERGE),y) 22ifeq ($(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;
110struct device_node *dflt_interrupt_controller; 110struct device_node *dflt_interrupt_controller;
111int num_interrupt_controllers; 111int num_interrupt_controllers;
112 112
113u32 rtas_data;
114u32 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
35struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; 35struct rtas_t rtas = {
36
37struct rtas_t rtas = {
38 .lock = SPIN_LOCK_UNLOCKED 36 .lock = SPIN_LOCK_UNLOCKED
39}; 37};
40 38
41EXPORT_SYMBOL(rtas); 39EXPORT_SYMBOL(rtas);
42 40
43char rtas_err_buf[RTAS_ERROR_LOG_MAX];
44
45DEFINE_SPINLOCK(rtas_data_buf_lock); 41DEFINE_SPINLOCK(rtas_data_buf_lock);
46char rtas_data_buf[RTAS_DATA_BUF_SIZE]__page_aligned; 42char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
47unsigned long rtas_rmo_buf; 43unsigned long rtas_rmo_buf;
48 44
49void 45/*
50call_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 */
50void 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
70void 70void call_rtas_display_status_delay(unsigned char c)
71call_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
95void 94void rtas_progress(char *s, unsigned short hex)
96rtas_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
212int 210int rtas_token(const char *service)
213rtas_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}
240EXPORT_SYMBOL(rtas_get_error_log_max);
243 241
244 242
243char rtas_err_buf[RTAS_ERROR_LOG_MAX];
244int 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 */
251static int 252static 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
278int rtas_call(int token, int nargs, int nret, int *outputs, ...) 301int 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 */
358unsigned int 355unsigned int rtas_extended_busy_delay_time(int status)
359rtas_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) 493void rtas_restart(char *cmd)
498static void
499rtas_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
569void 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
576void
577rtas_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
587void 500void rtas_power_off(void)
588rtas_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
598void 508void rtas_halt(void)
599rtas_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
695struct rtas_args rtas_stop_self_args = { 597struct 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 */
723void __init rtas_initialize(void) 626void __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
765EXPORT_SYMBOL(rtas_firmware_flash_list);
766EXPORT_SYMBOL(rtas_token); 672EXPORT_SYMBOL(rtas_token);
767EXPORT_SYMBOL(rtas_call); 673EXPORT_SYMBOL(rtas_call);
768EXPORT_SYMBOL(rtas_data_buf); 674EXPORT_SYMBOL(rtas_data_buf);
@@ -772,4 +678,3 @@ EXPORT_SYMBOL(rtas_get_sensor);
772EXPORT_SYMBOL(rtas_get_power_level); 678EXPORT_SYMBOL(rtas_get_power_level);
773EXPORT_SYMBOL(rtas_set_power_level); 679EXPORT_SYMBOL(rtas_set_power_level);
774EXPORT_SYMBOL(rtas_set_indicator); 680EXPORT_SYMBOL(rtas_set_indicator);
775EXPORT_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
24config PPC_RTAS
25 bool
26 depends on PPC_PSERIES || PPC_BPA
27 default y
28
29config RTAS_PROC 24config 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 @@
1obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ 1obj-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
3obj-$(CONFIG_SMP) += smp.o 3obj-$(CONFIG_SMP) += smp.o
4obj-$(CONFIG_IBMVIO) += vio.o 4obj-$(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
36struct flash_block_list_header rtas_firmware_flash_list = {0, NULL};
37
38#define FLASH_BLOCK_LIST_VERSION (1UL)
39
40static 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
110void 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
117void rtas_fw_restart(char *cmd)
118{
119 if (rtas_firmware_flash_list.next)
120 rtas_flash_firmware();
121 rtas_restart(cmd);
122}
123
124void rtas_fw_power_off(void)
125{
126 if (rtas_firmware_flash_list.next)
127 rtas_flash_bypass_warning();
128 rtas_power_off();
129}
130
131void rtas_fw_halt(void)
132{
133 if (rtas_firmware_flash_list.next)
134 rtas_flash_bypass_warning();
135 rtas_halt();
136}
137
138EXPORT_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 @@
1void rtas_fw_restart(char *cmd);
2void rtas_fw_power_off(void);
3void 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
321config RTAS_ERROR_LOGGING
322 bool
323 depends on PPC_RTAS
324 default y
325
321config RTAS_PROC 326config 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
43ifneq ($(CONFIG_PPC_MERGE),y) 43ifneq ($(CONFIG_PPC_MERGE),y)
44obj-$(CONFIG_MODULES) += ppc_ksyms.o 44obj-$(CONFIG_MODULES) += ppc_ksyms.o
45endif 45endif
46obj-$(CONFIG_PPC_RTAS) += rtas.o rtas_pci.o 46obj-$(CONFIG_PPC_RTAS) += rtas_pci.o
47obj-$(CONFIG_RTAS_PROC) += rtas-proc.o 47obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
48obj-$(CONFIG_SCANLOG) += scanlog.o 48obj-$(CONFIG_SCANLOG) += scanlog.o
49obj-$(CONFIG_LPARCFG) += lparcfg.o 49obj-$(CONFIG_LPARCFG) += lparcfg.o