aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasant Hegde <hegdevasant@linux.vnet.ibm.com>2020-12-17 12:29:28 +0530
committerVasant Hegde <hegdevasant@linux.vnet.ibm.com>2021-09-30 16:05:31 +0530
commit656e542df79789fd10982b45d6430b1bb3226f63 (patch)
tree49a5409b986c7cd8193379cf501286f494cb8f27
parent669aa5efffd15cd584b721de55c98f8e670d4599 (diff)
downloadskiboot-656e542df79789fd10982b45d6430b1bb3226f63.zip
skiboot-656e542df79789fd10982b45d6430b1bb3226f63.tar.gz
skiboot-656e542df79789fd10982b45d6430b1bb3226f63.tar.bz2
SBE: Check timer state before scheduling timer
[ Upstream commit 47ab3a92298e72e44b9477a02b1312a09272a54a ] Timer flow: - OPAL sends timer chip-op to SBE and waits for ACK - Until we get ACK interrupt from SBE we will not schedule any new timer - Once we get ACK either we wait for timer expiry -OR- schedule new one if new-timer-request < inflight-timer-timeout value. - If we get new timer request while processing current one p9_sbe_update_timer_expiry code sets `has_new_target` and we schedule it in ACK path (p9_sbe_timer_resp()). p9_sbe_timer_resp() is callback handler and its called without lock. It does not check whether timer message is busy or not (timer_ctrl_msg). So in theory we may hit below scenario and corrupt msg_list. CPU 1 -> Timer ACK (callback handler) -- its not holding any lock CPU 2 -> Grabbed sbe_timer_lock -> scheduled timer --> done CPU 3 -> p9_sbe_update_timer_expiry() -> see timer is busy -> sets has_new_timer -> done CPU 1 -> gets chance to grab sbe_timer_lock -> saw has_new_timer -> Called p9_sbe_timer_schedule() --> List corrupted ! This patch adds timer message busy check in p9_sbe_timer_resp(). Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com>
-rw-r--r--hw/sbe-p9.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/hw/sbe-p9.c b/hw/sbe-p9.c
index d52ada1..d6bc577 100644
--- a/hw/sbe-p9.c
+++ b/hw/sbe-p9.c
@@ -777,8 +777,10 @@ static void p9_sbe_timer_resp(struct p9_sbe_msg *msg)
lock(&sbe_timer_lock);
if (has_new_target) {
- has_new_target = false;
- p9_sbe_timer_schedule();
+ if (!p9_sbe_msg_busy(timer_ctrl_msg)) {
+ has_new_target = false;
+ p9_sbe_timer_schedule();
+ }
}
unlock(&sbe_timer_lock);
}