Skip to content

Commit

Permalink
crypto: ccree - fix PM race condition
Browse files Browse the repository at this point in the history
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: 1358c13 ("crypto: ccree - fix resume race condition on init")
Cc: stable@kernel.org # v4.20
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
  • Loading branch information
gby authored and herbertx committed Jan 22, 2020
1 parent 5c83e8e commit 15fd256
Show file tree
Hide file tree
Showing 4 changed files with 7 additions and 80 deletions.
1 change: 1 addition & 0 deletions drivers/crypto/ccree/cc_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ struct cc_drvdata {
int std_bodies;
bool sec_disabled;
u32 comp_mask;
bool pm_on;
};

struct cc_crypto_alg {
Expand Down
28 changes: 6 additions & 22 deletions drivers/crypto/ccree/cc_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,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);
Expand Down Expand Up @@ -63,13 +57,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);

return 0;
Expand All @@ -80,10 +67,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);
}
Expand All @@ -93,14 +78,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;
}

Expand All @@ -117,17 +99,19 @@ int cc_pm_init(struct cc_drvdata *drvdata)
/* must be before the enabling to avoid redundant 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);
}

/* enable the PM module*/
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;
}
50 changes: 0 additions & 50 deletions drivers/crypto/ccree/cc_request_mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ struct cc_req_mgr_handle {
#else
struct tasklet_struct comptask;
#endif
bool is_runtime_suspended;
};

struct cc_bl_item {
Expand Down Expand Up @@ -664,52 +663,3 @@ static void comp_handler(unsigned long devarg)
cc_proc_backlog(drvdata);
dev_dbg(dev, "Comp. handler done.\n");
}

/*
* 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
8 changes: 0 additions & 8 deletions drivers/crypto/ccree/cc_request_mgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,4 @@ void complete_request(struct cc_drvdata *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__*/

0 comments on commit 15fd256

Please sign in to comment.