From 99700222a553bc40bd1d1c8a7d430ce2090ecc93 Mon Sep 17 00:00:00 2001 From: Abhiroop Kaginalkar Date: Fri, 16 Aug 2019 15:41:29 -0700 Subject: 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 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 Reviewed-by: Debarshi Dutta Reviewed-by: Alex Waterman GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/pmu/pmu.c | 14 +++++++++++--- drivers/gpu/nvgpu/include/nvgpu/pmu.h | 3 ++- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') 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 @@ /* - * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -167,6 +167,9 @@ void nvgpu_kill_task_pg_init(struct gk20a *g) nvgpu_udelay(2); } while (nvgpu_timeout_expired_msg(&timeout, "timeout - waiting PMU state machine thread stop") == 0); + + /* Reset the flag for next time */ + pmu->pg_init.state_destroy = false; } else { nvgpu_thread_join(&pmu->pg_init.state_task); } @@ -468,9 +471,14 @@ void nvgpu_pmu_state_change(struct gk20a *g, u32 pmu_state, pmu->pmu_state = pmu_state; + /* Set a sticky flag to indicate PMU state exit */ + if (pmu_state == PMU_STATE_EXIT) { + pmu->pg_init.state_destroy = true; + } + if (post_change_event) { pmu->pg_init.state_change = true; - nvgpu_cond_signal(&pmu->pg_init.wq); + nvgpu_cond_signal_interruptible(&pmu->pg_init.wq); } /* make status visible */ @@ -494,7 +502,7 @@ static int nvgpu_pg_init_task(void *arg) pmu->pg_init.state_change = false; pmu_state = NV_ACCESS_ONCE(pmu->pmu_state); - if (pmu_state == PMU_STATE_EXIT) { + if (pmu->pg_init.state_destroy) { nvgpu_pmu_dbg(g, "pmu state exit"); break; } diff --git a/drivers/gpu/nvgpu/include/nvgpu/pmu.h b/drivers/gpu/nvgpu/include/nvgpu/pmu.h index 00194ec0..dcd49481 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/pmu.h +++ b/drivers/gpu/nvgpu/include/nvgpu/pmu.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -301,6 +301,7 @@ struct pmu_sequence { struct nvgpu_pg_init { bool state_change; + bool state_destroy; struct nvgpu_cond wq; struct nvgpu_thread state_task; }; -- cgit v1.2.2