Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

parisc: Replace regular spinlock with spin_trylock on panic path

The panic notifiers' callbacks execute in an atomic context, with
interrupts/preemption disabled, and all CPUs not running the panic
function are off, so it's very dangerous to wait on a regular
spinlock, there's a risk of deadlock.

Refactor the panic notifier of parisc/power driver to make use
of spin_trylock - for that, we've added a second version of the
soft-power function. Also, some comments were reorganized and
trailing white spaces, useless header inclusion and blank lines
were removed.

Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
Cc: Jeroen Roovers <jer@xs4all.nl>
Acked-by: Helge Deller <deller@gmx.de> # parisc
Signed-off-by: Guilherme G. Piccoli <gpiccoli@igalia.com>
Signed-off-by: Helge Deller <deller@gmx.de>

authored by

Guilherme G. Piccoli and committed by
Helge Deller
829632da e0838a99

+34 -10
+1
arch/parisc/include/asm/pdc.h
··· 80 80 int pdc_do_reset(void); 81 81 int pdc_soft_power_info(unsigned long *power_reg); 82 82 int pdc_soft_power_button(int sw_control); 83 + int pdc_soft_power_button_panic(int sw_control); 83 84 void pdc_io_reset(void); 84 85 void pdc_io_reset_devices(void); 85 86 int pdc_iodc_getc(void);
+23 -4
arch/parisc/kernel/firmware.c
··· 1232 1232 } 1233 1233 1234 1234 /* 1235 - * pdc_soft_power_button - Control the soft power button behaviour 1236 - * @sw_control: 0 for hardware control, 1 for software control 1235 + * pdc_soft_power_button{_panic} - Control the soft power button behaviour 1236 + * @sw_control: 0 for hardware control, 1 for software control 1237 1237 * 1238 1238 * 1239 1239 * This PDC function places the soft power button under software or 1240 1240 * hardware control. 1241 - * Under software control the OS may control to when to allow to shut 1242 - * down the system. Under hardware control pressing the power button 1241 + * Under software control the OS may control to when to allow to shut 1242 + * down the system. Under hardware control pressing the power button 1243 1243 * powers off the system immediately. 1244 + * 1245 + * The _panic version relies on spin_trylock to prevent deadlock 1246 + * on panic path. 1244 1247 */ 1245 1248 int pdc_soft_power_button(int sw_control) 1246 1249 { ··· 1251 1248 unsigned long flags; 1252 1249 1253 1250 spin_lock_irqsave(&pdc_lock, flags); 1251 + retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control); 1252 + spin_unlock_irqrestore(&pdc_lock, flags); 1253 + 1254 + return retval; 1255 + } 1256 + 1257 + int pdc_soft_power_button_panic(int sw_control) 1258 + { 1259 + int retval; 1260 + unsigned long flags; 1261 + 1262 + if (!spin_trylock_irqsave(&pdc_lock, flags)) { 1263 + pr_emerg("Couldn't enable soft power button\n"); 1264 + return -EBUSY; /* ignored by the panic notifier */ 1265 + } 1266 + 1254 1267 retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control); 1255 1268 spin_unlock_irqrestore(&pdc_lock, flags); 1256 1269
+10 -6
drivers/parisc/power.c
··· 37 37 #include <linux/module.h> 38 38 #include <linux/init.h> 39 39 #include <linux/kernel.h> 40 - #include <linux/notifier.h> 41 40 #include <linux/panic_notifier.h> 42 41 #include <linux/reboot.h> 43 42 #include <linux/sched/signal.h> ··· 174 175 175 176 176 177 177 - /* parisc_panic_event() is called by the panic handler. 178 - * As soon as a panic occurs, our tasklets above will not be 179 - * executed any longer. This function then re-enables the 180 - * soft-power switch and allows the user to switch off the system 178 + /* 179 + * parisc_panic_event() is called by the panic handler. 180 + * 181 + * As soon as a panic occurs, our tasklets above will not 182 + * be executed any longer. This function then re-enables 183 + * the soft-power switch and allows the user to switch off 184 + * the system. We rely in pdc_soft_power_button_panic() 185 + * since this version spin_trylocks (instead of regular 186 + * spinlock), preventing deadlocks on panic path. 181 187 */ 182 188 static int parisc_panic_event(struct notifier_block *this, 183 189 unsigned long event, void *ptr) 184 190 { 185 191 /* re-enable the soft-power switch */ 186 - pdc_soft_power_button(0); 192 + pdc_soft_power_button_panic(0); 187 193 return NOTIFY_DONE; 188 194 } 189 195