aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/rtas.c38
1 files changed, 29 insertions, 9 deletions
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index ee4c7609b649..d9a9974c6938 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -40,7 +40,7 @@
40#include <asm/atomic.h> 40#include <asm/atomic.h>
41 41
42struct rtas_t rtas = { 42struct rtas_t rtas = {
43 .lock = SPIN_LOCK_UNLOCKED 43 .lock = __RAW_SPIN_LOCK_UNLOCKED
44}; 44};
45EXPORT_SYMBOL(rtas); 45EXPORT_SYMBOL(rtas);
46 46
@@ -67,6 +67,28 @@ unsigned long rtas_rmo_buf;
67void (*rtas_flash_term_hook)(int); 67void (*rtas_flash_term_hook)(int);
68EXPORT_SYMBOL(rtas_flash_term_hook); 68EXPORT_SYMBOL(rtas_flash_term_hook);
69 69
70/* RTAS use home made raw locking instead of spin_lock_irqsave
71 * because those can be called from within really nasty contexts
72 * such as having the timebase stopped which would lockup with
73 * normal locks and spinlock debugging enabled
74 */
75static unsigned long lock_rtas(void)
76{
77 unsigned long flags;
78
79 local_irq_save(flags);
80 preempt_disable();
81 __raw_spin_lock_flags(&rtas.lock, flags);
82 return flags;
83}
84
85static void unlock_rtas(unsigned long flags)
86{
87 __raw_spin_unlock(&rtas.lock);
88 local_irq_restore(flags);
89 preempt_enable();
90}
91
70/* 92/*
71 * call_rtas_display_status and call_rtas_display_status_delay 93 * call_rtas_display_status and call_rtas_display_status_delay
72 * are designed only for very early low-level debugging, which 94 * are designed only for very early low-level debugging, which
@@ -79,7 +101,7 @@ static void call_rtas_display_status(char c)
79 101
80 if (!rtas.base) 102 if (!rtas.base)
81 return; 103 return;
82 spin_lock_irqsave(&rtas.lock, s); 104 s = lock_rtas();
83 105
84 args->token = 10; 106 args->token = 10;
85 args->nargs = 1; 107 args->nargs = 1;
@@ -89,7 +111,7 @@ static void call_rtas_display_status(char c)
89 111
90 enter_rtas(__pa(args)); 112 enter_rtas(__pa(args));
91 113
92 spin_unlock_irqrestore(&rtas.lock, s); 114 unlock_rtas(s);
93} 115}
94 116
95static void call_rtas_display_status_delay(char c) 117static void call_rtas_display_status_delay(char c)
@@ -411,8 +433,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
411 if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE) 433 if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
412 return -1; 434 return -1;
413 435
414 /* Gotta do something different here, use global lock for now... */ 436 s = lock_rtas();
415 spin_lock_irqsave(&rtas.lock, s);
416 rtas_args = &rtas.args; 437 rtas_args = &rtas.args;
417 438
418 rtas_args->token = token; 439 rtas_args->token = token;
@@ -439,8 +460,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
439 outputs[i] = rtas_args->rets[i+1]; 460 outputs[i] = rtas_args->rets[i+1];
440 ret = (nret > 0)? rtas_args->rets[0]: 0; 461 ret = (nret > 0)? rtas_args->rets[0]: 0;
441 462
442 /* Gotta do something different here, use global lock for now... */ 463 unlock_rtas(s);
443 spin_unlock_irqrestore(&rtas.lock, s);
444 464
445 if (buff_copy) { 465 if (buff_copy) {
446 log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); 466 log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0);
@@ -837,7 +857,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
837 857
838 buff_copy = get_errorlog_buffer(); 858 buff_copy = get_errorlog_buffer();
839 859
840 spin_lock_irqsave(&rtas.lock, flags); 860 flags = lock_rtas();
841 861
842 rtas.args = args; 862 rtas.args = args;
843 enter_rtas(__pa(&rtas.args)); 863 enter_rtas(__pa(&rtas.args));
@@ -848,7 +868,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
848 if (args.rets[0] == -1) 868 if (args.rets[0] == -1)
849 errbuf = __fetch_rtas_last_error(buff_copy); 869 errbuf = __fetch_rtas_last_error(buff_copy);
850 870
851 spin_unlock_irqrestore(&rtas.lock, flags); 871 unlock_rtas(flags);
852 872
853 if (buff_copy) { 873 if (buff_copy) {
854 if (errbuf) 874 if (errbuf)