diff options
author | Vasant Hegde <hegdevasant@linux.vnet.ibm.com> | 2020-12-17 12:29:28 +0530 |
---|---|---|
committer | Vasant Hegde <hegdevasant@linux.vnet.ibm.com> | 2020-12-18 12:08:43 +0530 |
commit | 47ab3a92298e72e44b9477a02b1312a09272a54a (patch) | |
tree | 5e02f13ed12e51c8faa258ee826b3e86107df7f6 | |
parent | 127a3ee2417a2a71b63cca5fd7055d9b64939bb1 (diff) | |
download | skiboot-47ab3a92298e72e44b9477a02b1312a09272a54a.zip skiboot-47ab3a92298e72e44b9477a02b1312a09272a54a.tar.gz skiboot-47ab3a92298e72e44b9477a02b1312a09272a54a.tar.bz2 |
SBE: Check timer state before scheduling timer
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>
-rw-r--r-- | hw/sbe-p9.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/hw/sbe-p9.c b/hw/sbe-p9.c index ae5aacb..75dc37a 100644 --- a/hw/sbe-p9.c +++ b/hw/sbe-p9.c @@ -768,8 +768,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); } |