aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRavi K. Nittala <ravi.nittala@in.ibm.com>2011-10-03 17:49:53 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-11-24 22:11:29 -0500
commitdf17f56d8a1a3a533b6b3e3a49a624626a49b197 (patch)
treef88a555f03a8d1933d829c8b14ac252cc3f33420 /arch
parentcc35b6766878e31accc95c3fdae945bdadc73a46 (diff)
powerpc/pseries: Cancel RTAS event scan before firmware flash
The RTAS firmware flash update is conducted using an RTAS call that is serialized by lock_rtas() which uses spin_lock. While the flash is in progress, rtasd performs scan for any RTAS events that are generated by the system. rtasd keeps scanning for the RTAS events generated on the machine. This is performed via workqueue mechanism. The rtas_event_scan() also uses an RTAS call to scan the events, eventually trying to acquire the spin_lock before issuing the request. The flash update takes a while to complete and during this time, any other RTAS call has to wait. In this case, rtas_event_scan() waits for a long time on the spin_lock resulting in a soft lockup. Fix: Just before the flash update is performed, the queued rtas_event_scan() work item is cancelled from the work queue so that there is no other RTAS call issued while the flash is in progress. After the flash completes, the system reboots and the rtas_event_scan() is rescheduled. Signed-off-by: Suzuki Poulose <suzuki@in.ibm.com> Signed-off-by: Ravi Nittala <ravi.nittala@in.ibm.com> Reported-by: Divya Vikas <divya.vikas@in.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/rtas.h6
-rw-r--r--arch/powerpc/kernel/rtas_flash.c6
-rw-r--r--arch/powerpc/kernel/rtasd.c7
3 files changed, 19 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 41f69ae79d4e..1646b76bd3d2 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -245,6 +245,12 @@ extern int early_init_dt_scan_rtas(unsigned long node,
245 245
246extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal); 246extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
247 247
248#ifdef CONFIG_PPC_RTAS_DAEMON
249extern void rtas_cancel_event_scan(void);
250#else
251static inline void rtas_cancel_event_scan(void) { }
252#endif
253
248/* Error types logged. */ 254/* Error types logged. */
249#define ERR_FLAG_ALREADY_LOGGED 0x0 255#define ERR_FLAG_ALREADY_LOGGED 0x0
250#define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */ 256#define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
index e037c7494fd8..4174b4b23246 100644
--- a/arch/powerpc/kernel/rtas_flash.c
+++ b/arch/powerpc/kernel/rtas_flash.c
@@ -568,6 +568,12 @@ static void rtas_flash_firmware(int reboot_type)
568 } 568 }
569 569
570 /* 570 /*
571 * Just before starting the firmware flash, cancel the event scan work
572 * to avoid any soft lockup issues.
573 */
574 rtas_cancel_event_scan();
575
576 /*
571 * NOTE: the "first" block must be under 4GB, so we create 577 * NOTE: the "first" block must be under 4GB, so we create
572 * an entry with no data blocks in the reserved buffer in 578 * an entry with no data blocks in the reserved buffer in
573 * the kernel data segment. 579 * the kernel data segment.
diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c
index 481ef064c8f1..1045ff49cc6d 100644
--- a/arch/powerpc/kernel/rtasd.c
+++ b/arch/powerpc/kernel/rtasd.c
@@ -472,6 +472,13 @@ static void start_event_scan(void)
472 &event_scan_work, event_scan_delay); 472 &event_scan_work, event_scan_delay);
473} 473}
474 474
475/* Cancel the rtas event scan work */
476void rtas_cancel_event_scan(void)
477{
478 cancel_delayed_work_sync(&event_scan_work);
479}
480EXPORT_SYMBOL_GPL(rtas_cancel_event_scan);
481
475static int __init rtas_init(void) 482static int __init rtas_init(void)
476{ 483{
477 struct proc_dir_entry *entry; 484 struct proc_dir_entry *entry;