aboutsummaryrefslogtreecommitdiff
path: root/core/timebase.c
diff options
context:
space:
mode:
authorMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>2015-09-14 16:39:44 +0530
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-09-15 11:15:16 +1000
commit1764f2452565bc7203f6e4523a3ea59bfffc35ee (patch)
treeff96c2b73dad358be5cdd2a0678d83faf96fb800 /core/timebase.c
parent1311068c72f82a0ccfd8cb539d7f7f062d077a23 (diff)
downloadskiboot-1764f2452565bc7203f6e4523a3ea59bfffc35ee.zip
skiboot-1764f2452565bc7203f6e4523a3ea59bfffc35ee.tar.gz
skiboot-1764f2452565bc7203f6e4523a3ea59bfffc35ee.tar.bz2
opal: Fix hang in time_wait* calls on HMI for TB errors.
On TOD/TB errors timebase register stops/freezes until HMI error recovery gets TOD/TB back into running state. However, while HMI recovery is in progress there are chances where some code path may invoke time_wait*() calls which depends on running TB value. In an event of TB not moving, time_wait* calls would keep looping resulting into a hang on that CPU. On OpenPower systems we are seeing system hang on TOD/TB errors. The hang is seen inside OPAL HMI handler while invoking prlog/perror(). The reason is, on OpenPower systems prlog/perror() depends on LPC UART console driver to flush log messages to the console. UART read/write calls invoke time_wait_nopoll() inside opb_[read|write]() functions. When TB is in stopped state this causes a hang in prlog/perror() calls. This patch fixes this issue by modifying time_wait_[no]poll() to check for TB validity and return immediately. Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'core/timebase.c')
-rw-r--r--core/timebase.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/core/timebase.c b/core/timebase.c
index b1d8196..4fcfae5 100644
--- a/core/timebase.c
+++ b/core/timebase.c
@@ -25,6 +25,11 @@ static void time_wait_poll(unsigned long duration)
unsigned long end = mftb() + duration;
unsigned long period = msecs_to_tb(5);
+ if (this_cpu()->tb_invalid) {
+ cpu_relax();
+ return;
+ }
+
while (tb_compare(mftb(), end) != TB_AAFTERB) {
/* Call pollers periodically but not continually to avoid
* bouncing cachelines due to lock contention. */
@@ -57,6 +62,11 @@ void time_wait_nopoll(unsigned long duration)
{
unsigned long end = mftb() + duration;
+ if (this_cpu()->tb_invalid) {
+ cpu_relax();
+ return;
+ }
+
while(tb_compare(mftb(), end) != TB_AAFTERB)
cpu_relax();
}