diff options
-rw-r--r-- | arch/powerpc/include/asm/rtas.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/rtas.c | 38 |
2 files changed, 30 insertions, 10 deletions
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 01c12339b304..0af42d20b692 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h | |||
@@ -58,7 +58,7 @@ struct rtas_t { | |||
58 | unsigned long entry; /* physical address pointer */ | 58 | unsigned long entry; /* physical address pointer */ |
59 | unsigned long base; /* physical address pointer */ | 59 | unsigned long base; /* physical address pointer */ |
60 | unsigned long size; | 60 | unsigned long size; |
61 | spinlock_t lock; | 61 | raw_spinlock_t lock; |
62 | struct rtas_args args; | 62 | struct rtas_args args; |
63 | struct device_node *dev; /* virtual address pointer */ | 63 | struct device_node *dev; /* virtual address pointer */ |
64 | }; | 64 | }; |
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 | ||
42 | struct rtas_t rtas = { | 42 | struct rtas_t rtas = { |
43 | .lock = SPIN_LOCK_UNLOCKED | 43 | .lock = __RAW_SPIN_LOCK_UNLOCKED |
44 | }; | 44 | }; |
45 | EXPORT_SYMBOL(rtas); | 45 | EXPORT_SYMBOL(rtas); |
46 | 46 | ||
@@ -67,6 +67,28 @@ unsigned long rtas_rmo_buf; | |||
67 | void (*rtas_flash_term_hook)(int); | 67 | void (*rtas_flash_term_hook)(int); |
68 | EXPORT_SYMBOL(rtas_flash_term_hook); | 68 | EXPORT_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 | */ | ||
75 | static 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 | |||
85 | static 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 | ||
95 | static void call_rtas_display_status_delay(char c) | 117 | static 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) |