aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMichael Ellerman <mpe@ellerman.id.au>2015-12-16 05:01:42 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2015-12-17 06:40:55 -0500
commit209eb4e5cbaba53ab555f3e7b43aa27176f3a925 (patch)
treeb0b4ead78364930134cddcc293befe7a3a2359a6 /arch
parente4d54f71d29997344b4c4c8d47708240f9f23a5c (diff)
powerpc/rtas: Add rtas_call_unlocked()
Most users of RTAS (Run-Time Abstraction Services) use rtas_call(), which deals with locking as well as endian handling. However we have two users outside of rtas.c that can't use rtas_call() because they have different locking requirements. The hotplug CPU code can't take the RTAS lock because the CPU would go offline with the lock held and no other CPUs would be able to call RTAS until the CPU came back online. The xmon code doesn't want to take the lock because it would risk dead locking when we are trying to recover from a crash. Both sites required multiple patches when we added little endian support, proving that programmers can't do endian right. Although that ship has sailed, we can still clean the code up by providing an unlocked version of rtas_call() which avoids the need to open code the logic elsewhere. Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/rtas.h2
-rw-r--r--arch/powerpc/kernel/rtas.c44
2 files changed, 35 insertions, 11 deletions
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index b77ef369c0f0..6db1d6977a0d 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -338,6 +338,8 @@ extern void enter_rtas(unsigned long);
338extern int rtas_token(const char *service); 338extern int rtas_token(const char *service);
339extern int rtas_service_present(const char *service); 339extern int rtas_service_present(const char *service);
340extern int rtas_call(int token, int, int, int *, ...); 340extern int rtas_call(int token, int, int, int *, ...);
341void rtas_call_unlocked(struct rtas_args *args, int token, int nargs,
342 int nret, ...);
341extern void rtas_restart(char *cmd); 343extern void rtas_restart(char *cmd);
342extern void rtas_power_off(void); 344extern void rtas_power_off(void);
343extern void rtas_halt(void); 345extern void rtas_halt(void);
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 5a753fae8265..fcf2d653a6fe 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -418,6 +418,36 @@ static char *__fetch_rtas_last_error(char *altbuf)
418#define get_errorlog_buffer() NULL 418#define get_errorlog_buffer() NULL
419#endif 419#endif
420 420
421
422static void
423va_rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret,
424 va_list list)
425{
426 int i;
427
428 args->token = cpu_to_be32(token);
429 args->nargs = cpu_to_be32(nargs);
430 args->nret = cpu_to_be32(nret);
431 args->rets = &(args->args[nargs]);
432
433 for (i = 0; i < nargs; ++i)
434 args->args[i] = cpu_to_be32(va_arg(list, __u32));
435
436 for (i = 0; i < nret; ++i)
437 args->rets[i] = 0;
438
439 enter_rtas(__pa(args));
440}
441
442void rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, ...)
443{
444 va_list list;
445
446 va_start(list, nret);
447 va_rtas_call_unlocked(args, token, nargs, nret, list);
448 va_end(list);
449}
450
421int rtas_call(int token, int nargs, int nret, int *outputs, ...) 451int rtas_call(int token, int nargs, int nret, int *outputs, ...)
422{ 452{
423 va_list list; 453 va_list list;
@@ -431,22 +461,14 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
431 return -1; 461 return -1;
432 462
433 s = lock_rtas(); 463 s = lock_rtas();
464
465 /* We use the global rtas args buffer */
434 rtas_args = &rtas.args; 466 rtas_args = &rtas.args;
435 467
436 rtas_args->token = cpu_to_be32(token);
437 rtas_args->nargs = cpu_to_be32(nargs);
438 rtas_args->nret = cpu_to_be32(nret);
439 rtas_args->rets = &(rtas_args->args[nargs]);
440 va_start(list, outputs); 468 va_start(list, outputs);
441 for (i = 0; i < nargs; ++i) 469 va_rtas_call_unlocked(rtas_args, token, nargs, nret, list);
442 rtas_args->args[i] = cpu_to_be32(va_arg(list, __u32));
443 va_end(list); 470 va_end(list);
444 471
445 for (i = 0; i < nret; ++i)
446 rtas_args->rets[i] = 0;
447
448 enter_rtas(__pa(rtas_args));
449
450 /* A -1 return code indicates that the last command couldn't 472 /* A -1 return code indicates that the last command couldn't
451 be completed due to a hardware error. */ 473 be completed due to a hardware error. */
452 if (be32_to_cpu(rtas_args->rets[0]) == -1) 474 if (be32_to_cpu(rtas_args->rets[0]) == -1)