powerpc/rtas: Introduce rtas_get_sensor_fast() for IRQ handlers
authorThomas Huth <thuth@redhat.com>
Fri, 17 Jul 2015 10:46:58 +0000 (12:46 +0200)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 23 Jul 2015 09:43:11 +0000 (19:43 +1000)
The EPOW interrupt handler uses rtas_get_sensor(), which in turn
uses rtas_busy_delay() to wait for RTAS becoming ready in case it
is necessary. But rtas_busy_delay() is annotated with might_sleep()
and thus may not be used by interrupts handlers like the EPOW handler!
This leads to the following BUG when CONFIG_DEBUG_ATOMIC_SLEEP is
enabled:

 BUG: sleeping function called from invalid context at arch/powerpc/kernel/rtas.c:496
 in_atomic(): 1, irqs_disabled(): 1, pid: 0, name: swapper/1
 CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.2.0-rc2-thuth #6
 Call Trace:
 [c00000007ffe7b90] [c000000000807670] dump_stack+0xa0/0xdc (unreliable)
 [c00000007ffe7bc0] [c0000000000e1f14] ___might_sleep+0x134/0x180
 [c00000007ffe7c20] [c00000000002aec0] rtas_busy_delay+0x30/0xd0
 [c00000007ffe7c50] [c00000000002bde4] rtas_get_sensor+0x74/0xe0
 [c00000007ffe7ce0] [c000000000083264] ras_epow_interrupt+0x44/0x450
 [c00000007ffe7d90] [c000000000120260] handle_irq_event_percpu+0xa0/0x300
 [c00000007ffe7e70] [c000000000120524] handle_irq_event+0x64/0xc0
 [c00000007ffe7eb0] [c000000000124dbc] handle_fasteoi_irq+0xec/0x260
 [c00000007ffe7ef0] [c00000000011f4f0] generic_handle_irq+0x50/0x80
 [c00000007ffe7f20] [c000000000010f3c] __do_irq+0x8c/0x200
 [c00000007ffe7f90] [c0000000000236cc] call_do_irq+0x14/0x24
 [c00000007e6f39e0] [c000000000011144] do_IRQ+0x94/0x110
 [c00000007e6f3a30] [c000000000002594] hardware_interrupt_common+0x114/0x180

Fix this issue by introducing a new rtas_get_sensor_fast() function
that does not use rtas_busy_delay() - and thus can only be used for
sensors that do not cause a BUSY condition - known as "fast" sensors.

The EPOW sensor is defined to be "fast" in sPAPR - mpe.

Fixes: 587f83e8dd50 ("powerpc/pseries: Use rtas_get_sensor in RAS code")
Signed-off-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/rtas.h
arch/powerpc/kernel/rtas.c
arch/powerpc/platforms/pseries/ras.c

index 7a4ede16b283648a7edc0058211b8762cd6290b0..b77ef369c0f0ea9b3641201c049aa11378788db1 100644 (file)
@@ -343,6 +343,7 @@ extern void rtas_power_off(void);
 extern void rtas_halt(void);
 extern void rtas_os_term(char *str);
 extern int rtas_get_sensor(int sensor, int index, int *state);
+extern int rtas_get_sensor_fast(int sensor, int index, int *state);
 extern int rtas_get_power_level(int powerdomain, int *level);
 extern int rtas_set_power_level(int powerdomain, int level, int *setlevel);
 extern bool rtas_indicator_present(int token, int *maxindex);
index 10fb4024a0ce9aca99f89b2f6ed36c1e9351a41f..84bf934cf74874eab39926b292c6fa7534829d24 100644 (file)
@@ -585,6 +585,23 @@ int rtas_get_sensor(int sensor, int index, int *state)
 }
 EXPORT_SYMBOL(rtas_get_sensor);
 
+int rtas_get_sensor_fast(int sensor, int index, int *state)
+{
+       int token = rtas_token("get-sensor-state");
+       int rc;
+
+       if (token == RTAS_UNKNOWN_SERVICE)
+               return -ENOENT;
+
+       rc = rtas_call(token, 2, 2, state, sensor, index);
+       WARN_ON(rc == RTAS_BUSY || (rc >= RTAS_EXTENDED_DELAY_MIN &&
+                                   rc <= RTAS_EXTENDED_DELAY_MAX));
+
+       if (rc < 0)
+               return rtas_error_rc(rc);
+       return rc;
+}
+
 bool rtas_indicator_present(int token, int *maxindex)
 {
        int proplen, count, i;
index 02e4a17455164d6faf5f983fde85b44bcc04008a..3b6647e574b6d0f3fbabd7780f176fbcfef7f4f5 100644 (file)
@@ -189,7 +189,8 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
        int state;
        int critical;
 
-       status = rtas_get_sensor(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, &state);
+       status = rtas_get_sensor_fast(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX,
+                                     &state);
 
        if (state > 3)
                critical = 1;           /* Time Critical */
This page took 0.029697 seconds and 5 git commands to generate.