diff options
author | Abhiroop Kaginalkar <akaginalkar@nvidia.com> | 2019-08-16 18:41:29 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2019-09-23 12:25:58 -0400 |
commit | 99700222a553bc40bd1d1c8a7d430ce2090ecc93 (patch) | |
tree | b55fec5b749d668c55894187f8f34fdcf4cbfe69 /drivers/gpu/nvgpu/common/pmu/pmu.c | |
parent | bb47dcf2ab38eb0b0206a2dcb3a84696d17791f2 (diff) |
gpu: nvgpu: Fix PMU destroy sequence
A call to exit the PMU state machine/kthread must
be prioritized over any other state change.
It was possible to set the state as PMU_STATE_EXIT,
signal the kthread and overwrite the state before
the kthread has had the chance to exit its loop.
This may lead to a "lost" signal, resulting in
indefinite wait during the destroy sequence.
Faulting sequence:
1. pmu_state = PMU_STATE_EXIT in nvgpu_pmu_destroy()
2. cond_signal()
3. pmu_state = PMU_STATE_LOADING_PG_BUF
4. PMU kthread wakes up
5. PMU kthread processes PMU_STATE_LOADING_PG_BUF
6. PMU kthread sleeps
7. nvgpu_pmu_destroy() waits indefinitely
This patch adds a sticky flag to indicate PMU_STATE_EXIT,
irrespective of any subsequent changes to pmu_state.
The PMU PG init kthread may wait on a call to
NVGPU_COND_WAIT_INTERRUPTIBLE, which requires a
corresponding call to nvgpu_cond_signal_interruptible()
as the core kernel code requires this task mask to
wake-up an interruptible task.
Bug 2658750
Bug 200532122
Change-Id: I61beae80673486f83bf60c703a8af88b066a1c36
Signed-off-by: Abhiroop Kaginalkar <akaginalkar@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/2177112
(cherry picked from commit afa49fb073a324c49a820e142aaaf80e4656dcc6)
Reviewed-on: https://git-master.nvidia.com/r/2190733
Tested-by: Divya Singhatwaria <dsinghatwari@nvidia.com>
Reviewed-by: Debarshi Dutta <ddutta@nvidia.com>
Reviewed-by: Alex Waterman <alexw@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/common/pmu/pmu.c')
-rw-r--r-- | drivers/gpu/nvgpu/common/pmu/pmu.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/gpu/nvgpu/common/pmu/pmu.c b/drivers/gpu/nvgpu/common/pmu/pmu.c index b9cfd033..8d051e5a 100644 --- a/drivers/gpu/nvgpu/common/pmu/pmu.c +++ b/drivers/gpu/nvgpu/common/pmu/pmu.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. | 2 | * Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved. |
3 | * | 3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), | 5 | * copy of this software and associated documentation files (the "Software"), |
@@ -167,6 +167,9 @@ void nvgpu_kill_task_pg_init(struct gk20a *g) | |||
167 | nvgpu_udelay(2); | 167 | nvgpu_udelay(2); |
168 | } while (nvgpu_timeout_expired_msg(&timeout, | 168 | } while (nvgpu_timeout_expired_msg(&timeout, |
169 | "timeout - waiting PMU state machine thread stop") == 0); | 169 | "timeout - waiting PMU state machine thread stop") == 0); |
170 | |||
171 | /* Reset the flag for next time */ | ||
172 | pmu->pg_init.state_destroy = false; | ||
170 | } else { | 173 | } else { |
171 | nvgpu_thread_join(&pmu->pg_init.state_task); | 174 | nvgpu_thread_join(&pmu->pg_init.state_task); |
172 | } | 175 | } |
@@ -468,9 +471,14 @@ void nvgpu_pmu_state_change(struct gk20a *g, u32 pmu_state, | |||
468 | 471 | ||
469 | pmu->pmu_state = pmu_state; | 472 | pmu->pmu_state = pmu_state; |
470 | 473 | ||
474 | /* Set a sticky flag to indicate PMU state exit */ | ||
475 | if (pmu_state == PMU_STATE_EXIT) { | ||
476 | pmu->pg_init.state_destroy = true; | ||
477 | } | ||
478 | |||
471 | if (post_change_event) { | 479 | if (post_change_event) { |
472 | pmu->pg_init.state_change = true; | 480 | pmu->pg_init.state_change = true; |
473 | nvgpu_cond_signal(&pmu->pg_init.wq); | 481 | nvgpu_cond_signal_interruptible(&pmu->pg_init.wq); |
474 | } | 482 | } |
475 | 483 | ||
476 | /* make status visible */ | 484 | /* make status visible */ |
@@ -494,7 +502,7 @@ static int nvgpu_pg_init_task(void *arg) | |||
494 | pmu->pg_init.state_change = false; | 502 | pmu->pg_init.state_change = false; |
495 | pmu_state = NV_ACCESS_ONCE(pmu->pmu_state); | 503 | pmu_state = NV_ACCESS_ONCE(pmu->pmu_state); |
496 | 504 | ||
497 | if (pmu_state == PMU_STATE_EXIT) { | 505 | if (pmu->pg_init.state_destroy) { |
498 | nvgpu_pmu_dbg(g, "pmu state exit"); | 506 | nvgpu_pmu_dbg(g, "pmu state exit"); |
499 | break; | 507 | break; |
500 | } | 508 | } |