| From 15fd2566bf54ee4d4781d8f170acfc9472a1541f Mon Sep 17 00:00:00 2001 |
| From: Gilad Ben-Yossef <gilad@benyossef.com> |
| Date: Thu, 16 Jan 2020 12:14:43 +0200 |
| Subject: crypto: ccree - fix PM race condition |
| |
| From: Gilad Ben-Yossef <gilad@benyossef.com> |
| |
| commit 15fd2566bf54ee4d4781d8f170acfc9472a1541f upstream. |
| |
| The PM code was racy, possibly causing the driver to submit |
| requests to a powered down device. Fix the race and while |
| at it simplify the PM code. |
| |
| Signed-off-by: Gilad Ben-Yossef <gilad@benyossef.com> |
| Fixes: 1358c13a48c4 ("crypto: ccree - fix resume race condition on init") |
| Cc: stable@kernel.org # v4.20 |
| Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/crypto/ccree/cc_driver.h | 1 |
| drivers/crypto/ccree/cc_pm.c | 28 ++++--------------- |
| drivers/crypto/ccree/cc_request_mgr.c | 50 ---------------------------------- |
| drivers/crypto/ccree/cc_request_mgr.h | 8 ----- |
| 4 files changed, 7 insertions(+), 80 deletions(-) |
| |
| --- a/drivers/crypto/ccree/cc_driver.h |
| +++ b/drivers/crypto/ccree/cc_driver.h |
| @@ -131,6 +131,7 @@ struct cc_drvdata { |
| u32 axim_mon_offset; |
| u32 sig_offset; |
| u32 ver_offset; |
| + bool pm_on; |
| }; |
| |
| struct cc_crypto_alg { |
| --- a/drivers/crypto/ccree/cc_pm.c |
| +++ b/drivers/crypto/ccree/cc_pm.c |
| @@ -23,14 +23,8 @@ const struct dev_pm_ops ccree_pm = { |
| int cc_pm_suspend(struct device *dev) |
| { |
| struct cc_drvdata *drvdata = dev_get_drvdata(dev); |
| - int rc; |
| |
| dev_dbg(dev, "set HOST_POWER_DOWN_EN\n"); |
| - rc = cc_suspend_req_queue(drvdata); |
| - if (rc) { |
| - dev_err(dev, "cc_suspend_req_queue (%x)\n", rc); |
| - return rc; |
| - } |
| fini_cc_regs(drvdata); |
| cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE); |
| cc_clk_off(drvdata); |
| @@ -59,13 +53,6 @@ int cc_pm_resume(struct device *dev) |
| /* check if tee fips error occurred during power down */ |
| cc_tee_handle_fips_error(drvdata); |
| |
| - rc = cc_resume_req_queue(drvdata); |
| - if (rc) { |
| - dev_err(dev, "cc_resume_req_queue (%x)\n", rc); |
| - return rc; |
| - } |
| - |
| - /* must be after the queue resuming as it uses the HW queue*/ |
| cc_init_hash_sram(drvdata); |
| |
| cc_init_iv_sram(drvdata); |
| @@ -77,10 +64,8 @@ int cc_pm_get(struct device *dev) |
| int rc = 0; |
| struct cc_drvdata *drvdata = dev_get_drvdata(dev); |
| |
| - if (cc_req_queue_suspended(drvdata)) |
| + if (drvdata->pm_on) |
| rc = pm_runtime_get_sync(dev); |
| - else |
| - pm_runtime_get_noresume(dev); |
| |
| return (rc == 1 ? 0 : rc); |
| } |
| @@ -90,14 +75,11 @@ int cc_pm_put_suspend(struct device *dev |
| int rc = 0; |
| struct cc_drvdata *drvdata = dev_get_drvdata(dev); |
| |
| - if (!cc_req_queue_suspended(drvdata)) { |
| + if (drvdata->pm_on) { |
| pm_runtime_mark_last_busy(dev); |
| rc = pm_runtime_put_autosuspend(dev); |
| - } else { |
| - /* Something wrong happens*/ |
| - dev_err(dev, "request to suspend already suspended queue"); |
| - rc = -EBUSY; |
| } |
| + |
| return rc; |
| } |
| |
| @@ -108,7 +90,7 @@ int cc_pm_init(struct cc_drvdata *drvdat |
| /* must be before the enabling to avoid resdundent suspending */ |
| pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT); |
| pm_runtime_use_autosuspend(dev); |
| - /* activate the PM module */ |
| + /* set us as active - note we won't do PM ops until cc_pm_go()! */ |
| return pm_runtime_set_active(dev); |
| } |
| |
| @@ -116,9 +98,11 @@ int cc_pm_init(struct cc_drvdata *drvdat |
| void cc_pm_go(struct cc_drvdata *drvdata) |
| { |
| pm_runtime_enable(drvdata_to_dev(drvdata)); |
| + drvdata->pm_on = true; |
| } |
| |
| void cc_pm_fini(struct cc_drvdata *drvdata) |
| { |
| pm_runtime_disable(drvdata_to_dev(drvdata)); |
| + drvdata->pm_on = false; |
| } |
| --- a/drivers/crypto/ccree/cc_request_mgr.c |
| +++ b/drivers/crypto/ccree/cc_request_mgr.c |
| @@ -41,7 +41,6 @@ struct cc_req_mgr_handle { |
| #else |
| struct tasklet_struct comptask; |
| #endif |
| - bool is_runtime_suspended; |
| }; |
| |
| struct cc_bl_item { |
| @@ -661,52 +660,3 @@ static void comp_handler(unsigned long d |
| |
| cc_proc_backlog(drvdata); |
| } |
| - |
| -/* |
| - * resume the queue configuration - no need to take the lock as this happens |
| - * inside the spin lock protection |
| - */ |
| -#if defined(CONFIG_PM) |
| -int cc_resume_req_queue(struct cc_drvdata *drvdata) |
| -{ |
| - struct cc_req_mgr_handle *request_mgr_handle = |
| - drvdata->request_mgr_handle; |
| - |
| - spin_lock_bh(&request_mgr_handle->hw_lock); |
| - request_mgr_handle->is_runtime_suspended = false; |
| - spin_unlock_bh(&request_mgr_handle->hw_lock); |
| - |
| - return 0; |
| -} |
| - |
| -/* |
| - * suspend the queue configuration. Since it is used for the runtime suspend |
| - * only verify that the queue can be suspended. |
| - */ |
| -int cc_suspend_req_queue(struct cc_drvdata *drvdata) |
| -{ |
| - struct cc_req_mgr_handle *request_mgr_handle = |
| - drvdata->request_mgr_handle; |
| - |
| - /* lock the send_request */ |
| - spin_lock_bh(&request_mgr_handle->hw_lock); |
| - if (request_mgr_handle->req_queue_head != |
| - request_mgr_handle->req_queue_tail) { |
| - spin_unlock_bh(&request_mgr_handle->hw_lock); |
| - return -EBUSY; |
| - } |
| - request_mgr_handle->is_runtime_suspended = true; |
| - spin_unlock_bh(&request_mgr_handle->hw_lock); |
| - |
| - return 0; |
| -} |
| - |
| -bool cc_req_queue_suspended(struct cc_drvdata *drvdata) |
| -{ |
| - struct cc_req_mgr_handle *request_mgr_handle = |
| - drvdata->request_mgr_handle; |
| - |
| - return request_mgr_handle->is_runtime_suspended; |
| -} |
| - |
| -#endif |
| --- a/drivers/crypto/ccree/cc_request_mgr.h |
| +++ b/drivers/crypto/ccree/cc_request_mgr.h |
| @@ -40,12 +40,4 @@ void complete_request(struct cc_drvdata |
| |
| void cc_req_mgr_fini(struct cc_drvdata *drvdata); |
| |
| -#if defined(CONFIG_PM) |
| -int cc_resume_req_queue(struct cc_drvdata *drvdata); |
| - |
| -int cc_suspend_req_queue(struct cc_drvdata *drvdata); |
| - |
| -bool cc_req_queue_suspended(struct cc_drvdata *drvdata); |
| -#endif |
| - |
| #endif /*__REQUEST_MGR_H__*/ |