Commit 81b73dd9 authored by Haren Myneni's avatar Haren Myneni Committed by Paul Mackerras

[POWERPC] Fix might-sleep warning on removing cpus

Noticing the following might_sleep warning (dump_stack()) during kdump
testing when CONFIG_DEBUG_SPINLOCK_SLEEP is enabled. All secondary CPUs
will be calling rtas_set_indicator with interrupts disabled to remove
them from global interrupt queue.

BUG: sleeping function called from invalid context at
arch/powerpc/kernel/rtas.c:463
in_atomic():1, irqs_disabled():1
Call Trace:
[C00000000FFFB970] [C000000000010234] .show_stack+0x68/0x1b0 (unreliable)
[C00000000FFFBA10] [C000000000059354] .__might_sleep+0xd8/0xf4
[C00000000FFFBA90] [C00000000001D1BC] .rtas_busy_delay+0x20/0x5c
[C00000000FFFBB20] [C00000000001D8A8] .rtas_set_indicator+0x6c/0xcc
[C00000000FFFBBC0] [C000000000048BF4] .xics_teardown_cpu+0x118/0x134
[C00000000FFFBC40] [C00000000004539C]
.pseries_kexec_cpu_down_xics+0x74/0x8c
[C00000000FFFBCC0] [C00000000002DF08] .crash_ipi_callback+0x15c/0x188
[C00000000FFFBD50] [C0000000000296EC] .smp_message_recv+0x84/0xdc
[C00000000FFFBDC0] [C000000000048E08] .xics_ipi_dispatch+0xf0/0x130
[C00000000FFFBE50] [C00000000009EF10] .handle_IRQ_event+0x7c/0xf8
[C00000000FFFBF00] [C0000000000A0A14] .handle_percpu_irq+0x90/0x10c
[C00000000FFFBF90] [C00000000002659C] .call_handle_irq+0x1c/0x2c
[C00000000058B9C0] [C00000000000CA10] .do_IRQ+0xf4/0x1a4
[C00000000058BA50] [C0000000000044EC] hardware_interrupt_entry+0xc/0x10
 --- Exception: 501 at .plpar_hcall_norets+0x14/0x1c
   LR = .pseries_dedicated_idle_sleep+0x190/0x1d4
[C00000000058BD40] [C00000000058BDE0] 0xc00000000058bde0 (unreliable)
[C00000000058BDF0] [C00000000001270C] .cpu_idle+0x10c/0x1e0
[C00000000058BE70] [C000000000009274] .rest_init+0x44/0x5c

To fix this issue, rtas_set_indicator_fast() is added so that will not
wait for RTAS 'busy' delay and this new function is used for kdump (in
xics_teardown_cpu()) and for CPU hotplug ( xics_migrate_irqs_away() and
xics_setup_cpu()).

Note that the platform architecture spec says that set-indicator
on the indicator we're using here is not permitted to return the
busy or extended busy status codes.
Signed-off-by: default avatarHaren Myneni <haren@us.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent dcc42f48
...@@ -569,6 +569,27 @@ int rtas_set_indicator(int indicator, int index, int new_value) ...@@ -569,6 +569,27 @@ int rtas_set_indicator(int indicator, int index, int new_value)
} }
EXPORT_SYMBOL(rtas_set_indicator); EXPORT_SYMBOL(rtas_set_indicator);
/*
* Ignoring RTAS extended delay
*/
int rtas_set_indicator_fast(int indicator, int index, int new_value)
{
int rc;
int token = rtas_token("set-indicator");
if (token == RTAS_UNKNOWN_SERVICE)
return -ENOENT;
rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
WARN_ON(rc == -2 || (rc >= 9900 && rc <= 9905));
if (rc < 0)
return rtas_error_rc(rc);
return rc;
}
void rtas_restart(char *cmd) void rtas_restart(char *cmd)
{ {
if (rtas_flash_term_hook) if (rtas_flash_term_hook)
......
...@@ -467,7 +467,7 @@ void xics_setup_cpu(void) ...@@ -467,7 +467,7 @@ void xics_setup_cpu(void)
* *
* XXX: undo of teardown on kexec needs this too, as may hotplug * XXX: undo of teardown on kexec needs this too, as may hotplug
*/ */
rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
(1UL << interrupt_server_size) - 1 - default_distrib_server, 1); (1UL << interrupt_server_size) - 1 - default_distrib_server, 1);
} }
...@@ -796,7 +796,7 @@ void xics_teardown_cpu(int secondary) ...@@ -796,7 +796,7 @@ void xics_teardown_cpu(int secondary)
* so leave the master cpu in the group. * so leave the master cpu in the group.
*/ */
if (secondary) if (secondary)
rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
(1UL << interrupt_server_size) - 1 - (1UL << interrupt_server_size) - 1 -
default_distrib_server, 0); default_distrib_server, 0);
} }
...@@ -813,7 +813,7 @@ void xics_migrate_irqs_away(void) ...@@ -813,7 +813,7 @@ void xics_migrate_irqs_away(void)
xics_set_cpu_priority(cpu, 0); xics_set_cpu_priority(cpu, 0);
/* remove ourselves from the global interrupt queue */ /* remove ourselves from the global interrupt queue */
status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
(1UL << interrupt_server_size) - 1 - default_distrib_server, 0); (1UL << interrupt_server_size) - 1 - default_distrib_server, 0);
WARN_ON(status < 0); WARN_ON(status < 0);
......
...@@ -170,6 +170,7 @@ extern int rtas_get_sensor(int sensor, int index, int *state); ...@@ -170,6 +170,7 @@ extern int rtas_get_sensor(int sensor, int index, int *state);
extern int rtas_get_power_level(int powerdomain, int *level); extern int rtas_get_power_level(int powerdomain, int *level);
extern int rtas_set_power_level(int powerdomain, int level, int *setlevel); extern int rtas_set_power_level(int powerdomain, int level, int *setlevel);
extern int rtas_set_indicator(int indicator, int index, int new_value); extern int rtas_set_indicator(int indicator, int index, int new_value);
extern int rtas_set_indicator_fast(int indicator, int index, int new_value);
extern void rtas_progress(char *s, unsigned short hex); extern void rtas_progress(char *s, unsigned short hex);
extern void rtas_initialize(void); extern void rtas_initialize(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment