summaryrefslogtreecommitdiffstats
path: root/drivers/soc/qcom/rpmh-rsc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/qcom/rpmh-rsc.c')
-rw-r--r--drivers/soc/qcom/rpmh-rsc.c55
1 files changed, 25 insertions, 30 deletions
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index a5659a7306e4..fb142dfbb237 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -192,11 +192,7 @@ static void write_tcs_reg_sync(const struct rsc_drv *drv, int reg, int tcs_id,
*
* Returns true if nobody has claimed this TCS (by setting tcs_in_use).
*
- * Context: Must be called with the drv->lock held or the tcs_lock for the TCS
- * being tested. If only the tcs_lock is held then it is possible that
- * this function will return that a tcs is still busy when it has been
- * recently been freed but it will never return free when a TCS is
- * actually in use.
+ * Context: Must be called with the drv->lock held.
*
* Return: true if the given TCS is free.
*/
@@ -255,8 +251,6 @@ void rpmh_rsc_invalidate(struct rsc_drv *drv)
* This is normally pretty straightforward except if we are trying to send
* an ACTIVE_ONLY message but don't have any active_only TCSes.
*
- * Called without drv->lock held and with no tcs_lock locks held.
- *
* Return: A pointer to a tcs_group or an ERR_PTR.
*/
static struct tcs_group *get_tcs_for_msg(struct rsc_drv *drv,
@@ -594,24 +588,19 @@ static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg)
if (IS_ERR(tcs))
return PTR_ERR(tcs);
- spin_lock_irqsave(&tcs->lock, flags);
- spin_lock(&drv->lock);
+ spin_lock_irqsave(&drv->lock, flags);
/*
* The h/w does not like if we send a request to the same address,
* when one is already in-flight or being processed.
*/
ret = check_for_req_inflight(drv, tcs, msg);
- if (ret) {
- spin_unlock(&drv->lock);
- goto done_write;
- }
+ if (ret)
+ goto unlock;
- tcs_id = find_free_tcs(tcs);
- if (tcs_id < 0) {
- ret = tcs_id;
- spin_unlock(&drv->lock);
- goto done_write;
- }
+ ret = find_free_tcs(tcs);
+ if (ret < 0)
+ goto unlock;
+ tcs_id = ret;
tcs->req[tcs_id - tcs->offset] = msg;
set_bit(tcs_id, drv->tcs_in_use);
@@ -625,13 +614,22 @@ static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg)
write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0);
enable_tcs_irq(drv, tcs_id, true);
}
- spin_unlock(&drv->lock);
+ spin_unlock_irqrestore(&drv->lock, flags);
+ /*
+ * These two can be done after the lock is released because:
+ * - We marked "tcs_in_use" under lock.
+ * - Once "tcs_in_use" has been marked nobody else could be writing
+ * to these registers until the interrupt goes off.
+ * - The interrupt can't go off until we trigger w/ the last line
+ * of __tcs_set_trigger() below.
+ */
__tcs_buffer_write(drv, tcs_id, 0, msg);
__tcs_set_trigger(drv, tcs_id, true);
-done_write:
- spin_unlock_irqrestore(&tcs->lock, flags);
+ return 0;
+unlock:
+ spin_unlock_irqrestore(&drv->lock, flags);
return ret;
}
@@ -686,8 +684,6 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
* Only for use on sleep/wake TCSes since those are the only ones we maintain
* tcs->slots for.
*
- * Must be called with the tcs_lock for the group held.
- *
* Return: -ENOMEM if there was no room, else 0.
*/
static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
@@ -722,25 +718,25 @@ static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
* This should only be called for for sleep/wake state, never active-only
* state.
*
+ * The caller must ensure that no other RPMH actions are happening and the
+ * controller is idle when this function is called since it runs lockless.
+ *
* Return: 0 if no error; else -error.
*/
int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg)
{
struct tcs_group *tcs;
int tcs_id = 0, cmd_id = 0;
- unsigned long flags;
int ret;
tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);
- spin_lock_irqsave(&tcs->lock, flags);
/* find the TCS id and the command in the TCS to write to */
ret = find_slots(tcs, msg, &tcs_id, &cmd_id);
if (!ret)
__tcs_buffer_write(drv, tcs_id, cmd_id, msg);
- spin_unlock_irqrestore(&tcs->lock, flags);
return ret;
}
@@ -769,8 +765,8 @@ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv)
* should be checked for not busy, because we used wake TCSes for
* active requests in this case.
*
- * Since this is called from the last cpu, need not take drv or tcs
- * lock before checking tcs_is_free().
+ * Since this is called from the last cpu, need not take drv->lock
+ * before checking tcs_is_free().
*/
if (!tcs->num_tcs)
tcs = &drv->tcs[WAKE_TCS];
@@ -899,7 +895,6 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev,
tcs->type = tcs_cfg[i].type;
tcs->num_tcs = tcs_cfg[i].n;
tcs->ncpt = ncpt;
- spin_lock_init(&tcs->lock);
if (!tcs->num_tcs || tcs->type == CONTROL_TCS)
continue;