Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 479682d4 authored by Raju P.L.S.S.S.N's avatar Raju P.L.S.S.S.N Committed by Gerrit - the friendly Code Review server
Browse files

drivers: qcom: rpmh: Avoid race when setting solver mode



Ensure that the solver mode is set only when there are no active
requests being processed by the RPMH drivers. Also, since we are no
longer locking in the interrupt handlers, remove the _irqsave variants
of spinlocks.

Change-Id: I61b118c1946488cc95a8f4da3dae975d7361bf46
Signed-off-by: default avatarRaju P.L.S.S.S.N <rplsssn@codeaurora.org>
Signed-off-by: default avatarLina Iyer <ilina@codeaurora.org>
parent df485206
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ struct rpmh_ctrlr {
 * @base:       start address of the RSC's DRV registers
 * @tcs_base:   start address of the TCS registers in this controller
 * @id:         instance id in the controller (Direct Resource Voter)
 * @in_solver_mode: Controller is in solver mode
 * @num_tcs:    number of TCSes in this DRV
 * @tcs:        TCS groups
 * @tcs_in_use: s/w state of the TCS
@@ -100,6 +101,7 @@ struct rsc_drv {
	void __iomem *base;
	void __iomem *tcs_base;
	int id;
	bool in_solver_mode;
	int num_tcs;
	struct tcs_group tcs[TCS_TYPE_NR];
	DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
@@ -116,6 +118,7 @@ int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
int rpmh_rsc_invalidate(struct rsc_drv *drv);
bool rpmh_rsc_ctrlr_is_idle(struct rsc_drv *drv);
int rpmh_rsc_write_pdc_data(struct rsc_drv *drv, const struct tcs_request *msg);
void rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable);

void rpmh_tx_done(const struct tcs_request *msg, int r);

+29 −0
Original line number Diff line number Diff line
@@ -388,6 +388,10 @@ static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg)
		return PTR_ERR(tcs);

	spin_lock(&drv->lock);
	if (msg->state == RPMH_ACTIVE_ONLY_STATE && drv->in_solver_mode) {
		ret = -EINVAL;
		goto done_write;
	}
	/*
	 * The h/w does not like if we send a request to the same address,
	 * when one is already in-flight or being processed.
@@ -526,6 +530,30 @@ static int tcs_ctrl_write(struct rsc_drv *drv, const struct tcs_request *msg)
	return ret;
}

/**
 *  rpmh_rsc_mode_solver_set: Enable/disable solver mode
 *
 *  @drv: The controller
 *
 *  enable: boolean state to be set - true/false
 */
void rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable)
{
	int m;
	struct tcs_group *tcs = get_tcs_of_type(drv, ACTIVE_TCS);

again:
	spin_lock(&drv->lock);
	for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) {
		if (!tcs_is_free(drv, m)) {
			spin_unlock(&drv->lock);
			goto again;
		}
	}
	drv->in_solver_mode = enable;
	spin_unlock(&drv->lock);
}

/**
 *  rpmh_rsc_ctrlr_is_idle: Check if any of the AMCs are busy.
 *
@@ -818,6 +846,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
		return ret;

	spin_lock_init(&drv->lock);
	drv->in_solver_mode = false;
	bitmap_zero(drv->tcs_in_use, MAX_TCS_NR);

	irq = platform_get_irq(pdev, drv->id);
+6 −14
Original line number Diff line number Diff line
@@ -78,14 +78,13 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)

static int check_ctrlr_state(struct rpmh_ctrlr *ctrlr, enum rpmh_state state)
{
	unsigned long flags;
	int ret = 0;

	/* Do not allow setting active votes when in solver mode */
	spin_lock_irqsave(&ctrlr->cache_lock, flags);
	spin_lock(&ctrlr->cache_lock);
	if (ctrlr->in_solver_mode && state == RPMH_ACTIVE_ONLY_STATE)
		ret = -EBUSY;
	spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
	spin_unlock(&ctrlr->cache_lock);

	return ret;
}
@@ -103,18 +102,11 @@ static int check_ctrlr_state(struct rpmh_ctrlr *ctrlr, enum rpmh_state state)
int rpmh_mode_solver_set(const struct device *dev, bool enable)
{
	struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
	unsigned long flags;

	for (;;) {
		spin_lock_irqsave(&ctrlr->cache_lock, flags);
		if (rpmh_rsc_ctrlr_is_idle(ctrlr_to_drv(ctrlr))) {
	spin_lock(&ctrlr->cache_lock);
	rpmh_rsc_mode_solver_set(ctrlr_to_drv(ctrlr), enable);
	ctrlr->in_solver_mode = enable;
			spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
			break;
		}
		spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
		udelay(10);
	}
	spin_unlock(&ctrlr->cache_lock);

	return 0;
}