soc: qcom: rpmh: Optimize locking around flushing cache

In OS-Initiated mode of PSCI, a serialization is established in Linux
between the last CPU powering down the cluster / domain and the CPU
powering up back. The serialization is established by the genpd
framework and therefore it doesn't help to lock around the cache.

Refactor out the core of the flush functionality from the locking
wrappers. Calling the core functionality avoids a spin trylock, which
the RCU framework might consider suspicious under the circumstances.

Change-Id: I242fb4827b71152bda36ea5870393054b8703309
Signed-off-by: Lina Iyer <ilina@codeaurora.org>
Signed-off-by: Maulik Shah <quic_mkshah@quicinc.com>
This commit is contained in:
Lina Iyer 2020-09-03 13:53:28 -06:00 committed by Maulik Shah
parent 7466fd9c13
commit 0d2c70be39
3 changed files with 44 additions and 37 deletions

View File

@ -151,5 +151,6 @@ int rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable);
void rpmh_tx_done(const struct tcs_request *msg, int r);
int rpmh_flush(struct rpmh_ctrlr *ctrlr);
int _rpmh_flush(struct rpmh_ctrlr *ctrlr);
#endif /* __RPM_INTERNAL_H__ */

View File

@ -1064,7 +1064,7 @@ static int rpmh_rsc_pd_cb(struct notifier_block *nb,
/* We don't need to lock as domin on/off are serialized */
if ((action == GENPD_NOTIFY_PRE_OFF) &&
(rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client)))
(rpmh_rsc_ctrlr_is_busy(drv) || _rpmh_flush(&drv->client)))
return NOTIFY_BAD;
return NOTIFY_OK;

View File

@ -470,6 +470,45 @@ static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state,
return rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), &rpm_msg.msg);
}
int _rpmh_flush(struct rpmh_ctrlr *ctrlr)
{
struct cache_req *p;
int ret = 0;
if (!ctrlr->dirty) {
pr_debug("Skipping flush, TCS has latest data.\n");
return ret;
}
/* Invalidate the TCSes first to avoid stale data */
rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr));
/* First flush the cached batch requests */
ret = flush_batch(ctrlr);
if (ret)
return ret;
list_for_each_entry(p, &ctrlr->cache, list) {
if (!is_req_valid(p)) {
pr_debug("%s: skipping RPMH req: a:%#x s:%#x w:%#x\n",
__func__, p->addr, p->sleep_val, p->wake_val);
continue;
}
ret = send_single(ctrlr, RPMH_SLEEP_STATE, p->addr,
p->sleep_val);
if (ret)
return ret;
ret = send_single(ctrlr, RPMH_WAKE_ONLY_STATE, p->addr,
p->wake_val);
if (ret)
return ret;
}
ctrlr->dirty = false;
return ret;
}
/**
* rpmh_flush() - Flushes the buffered sleep and wake sets to TCSes
*
@ -481,8 +520,7 @@ static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state,
*/
int rpmh_flush(struct rpmh_ctrlr *ctrlr)
{
struct cache_req *p;
int ret = 0;
int ret;
if (rpmh_standalone)
return 0;
@ -498,7 +536,6 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
* Conditionally check for irqs_disabled only when solver mode
* is not available.
*/
if (!(ctrlr->flags & SOLVER_PRESENT))
lockdep_assert_irqs_disabled();
@ -508,40 +545,9 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
*/
if (!spin_trylock(&ctrlr->cache_lock))
return -EBUSY;
if (!ctrlr->dirty) {
pr_debug("Skipping flush, TCS has latest data.\n");
goto exit;
}
/* Invalidate the TCSes first to avoid stale data */
rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr));
/* First flush the cached batch requests */
ret = flush_batch(ctrlr);
if (ret)
goto exit;
list_for_each_entry(p, &ctrlr->cache, list) {
if (!is_req_valid(p)) {
pr_debug("%s: skipping RPMH req: a:%#x s:%#x w:%#x",
__func__, p->addr, p->sleep_val, p->wake_val);
continue;
}
ret = send_single(ctrlr, RPMH_SLEEP_STATE, p->addr,
p->sleep_val);
if (ret)
goto exit;
ret = send_single(ctrlr, RPMH_WAKE_ONLY_STATE, p->addr,
p->wake_val);
if (ret)
goto exit;
}
ctrlr->dirty = false;
exit:
ret = _rpmh_flush(ctrlr);
spin_unlock(&ctrlr->cache_lock);
return ret;
}