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

Commit 955160f0 authored by Raju P.L.S.S.S.N's avatar Raju P.L.S.S.S.N Committed by Lina Iyer
Browse files

drivers: qcom: rpmh-rsc: output debug information from RSC



Output the TCS state when the debug api is invoked. The state of the
TCS, the contents and the IRQ status is presented. Additionally, crash
the system if any TCS is busy to help with the debug.

Change-Id: I7ef5480cc6da7208d5f82351d863561fcc1abf68
Signed-off-by: default avatarRaju P.L.S.S.S.N <rplsssn@codeaurora.org>
parent 1e2d7df6
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ struct rpmh_ctrlr {
 * @tcs_in_use: s/w state of the TCS
 * @lock:       synchronize state of the controller
 * @client:     handle to the DRV's client.
 * @irq:        IRQ at gic
 */
struct rsc_drv {
	const char *name;
@@ -106,6 +107,7 @@ struct rsc_drv {
	DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
	spinlock_t lock;
	struct rpmh_ctrlr client;
	int irq;
};

int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
@@ -117,4 +119,5 @@ int rpmh_rsc_write_pdc_data(struct rsc_drv *drv, const struct tcs_request *msg);

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

void rpmh_rsc_debug(struct rsc_drv *drv);
#endif /* __RPM_INTERNAL_H__ */
+104 −2
Original line number Diff line number Diff line
@@ -446,8 +446,8 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
	do {
		ret = tcs_write(drv, msg);
		if (ret == -EBUSY) {
			pr_info_ratelimited("TCS Busy, retrying RPMH message send: addr=%#x\n",
					    msg->cmds[0].addr);
			pr_info_ratelimited("DRV:%s TCS Busy, retrying RPMH message send: addr=%#x\n",
					    drv->name, msg->cmds[0].addr);
			udelay(10);
		}
	} while (ret == -EBUSY);
@@ -596,6 +596,106 @@ int rpmh_rsc_write_pdc_data(struct rsc_drv *drv, const struct tcs_request *msg)
	return 0;
}

static struct tcs_group *get_tcs_from_index(struct rsc_drv *drv, int tcs_id)
{
	unsigned int i;

	for (i = 0; i < TCS_TYPE_NR; i++) {
		if (drv->tcs[i].mask & BIT(tcs_id))
			return &drv->tcs[i];
	}

	return NULL;
}

static void print_tcs_info(struct rsc_drv *drv, int tcs_id)
{
	struct tcs_group *tcs_grp = get_tcs_from_index(drv, tcs_id);
	const struct tcs_request *req = get_req_from_tcs(drv, tcs_id);
	struct tcs_cmd *cmd;
	unsigned long cmds_enabled;
	u32 addr, data, msgid, sts, irq_sts;
	bool in_use = test_bit(tcs_id, drv->tcs_in_use);
	int i;

	if (!tcs_grp || !req)
		return;

	sts = read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id, 0);
	cmds_enabled = read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
	if (!cmds_enabled)
		return;

	data = read_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, 0);
	irq_sts = read_tcs_reg(drv, RSC_DRV_IRQ_STATUS, 0, 0);
	pr_warn("Request: tcs-in-use:%s active_tcs=%s(%d) state=%d wait_for_compl=%u]\n",
		(in_use ? "YES" : "NO"),
		((tcs_grp->type == ACTIVE_TCS) ? "YES" : "NO"),
		tcs_grp->type, req->state, req->wait_for_compl);
	pr_warn("TCS=%d [ctrlr-sts:%s amc-mode:0x%x irq-sts:%s]\n",
		tcs_id, sts ? "IDLE" : "BUSY", data,
		(irq_sts & BIT(tcs_id)) ? "COMPLETED" : "PENDING");

	for (i = 0; i < req->num_cmds; i++) {
		cmd = &req->cmds[i];
		pr_warn("\tREQ=%d [addr=0x%x data=0x%x wait=0x%x]\n",
			i, cmd->addr, cmd->data, cmd->wait);

		if (i < MAX_CMDS_PER_TCS) {
			addr = read_tcs_reg(drv, RSC_DRV_CMD_ADDR, tcs_id, i);
			data = read_tcs_reg(drv, RSC_DRV_CMD_DATA, tcs_id, i);
			msgid = read_tcs_reg(drv, RSC_DRV_CMD_MSGID, tcs_id, i);
			sts = read_tcs_reg(drv, RSC_DRV_CMD_STATUS, tcs_id, i);
			pr_warn("\tCMD=%d [addr=0x%x data=0x%x hdr=0x%x sts=0x%x enabled=%ld]\n",
				i, addr, data, msgid, sts,
				(cmds_enabled & BIT(i)));
		}
	}

	for_each_set_bit_from(i, &cmds_enabled, MAX_CMDS_PER_TCS) {
		addr = read_tcs_reg(drv, RSC_DRV_CMD_ADDR, tcs_id, i);
		data = read_tcs_reg(drv, RSC_DRV_CMD_DATA, tcs_id, i);
		msgid = read_tcs_reg(drv, RSC_DRV_CMD_MSGID, tcs_id, i);
		sts = read_tcs_reg(drv, RSC_DRV_CMD_STATUS, tcs_id, i);
		pr_warn("\tCMD=%d [addr=0x%x data=0x%x hdr=0x%x sts=0x%x enabled=1]\n",
			i, addr, data, msgid, sts);
	}
}

void rpmh_rsc_debug(struct rsc_drv *drv)
{
	struct irq_data *rsc_irq_data = irq_get_irq_data(drv->irq);
	bool irq_sts;
	int i;
	int busy = 0;

	pr_warn("RSC:%s\n", drv->name);

	for (i = 0; i < drv->num_tcs; i++) {
		if (!test_bit(i, drv->tcs_in_use))
			continue;
		busy++;
		print_tcs_info(drv, i);
	}

	if (!rsc_irq_data) {
		pr_err("No IRQ data for RSC:%s\n", drv->name);
		return;
	}

	irq_get_irqchip_state(drv->irq, IRQCHIP_STATE_PENDING, &irq_sts);
	pr_warn("HW IRQ %lu is %s at GIC\n", rsc_irq_data->hwirq,
		irq_sts ? "PENDING" : "NOT PENDING");

	/*
	 * The TCS(s) are busy waiting, we have no way to recover from this.
	 * If this debug function is called, we assume it's because timeout
	 * has happened.
	 * Crash and report.
	 */
	BUG_ON(busy);
}

static int rpmh_probe_tcs_config(struct platform_device *pdev,
				 struct rsc_drv *drv)
{
@@ -731,6 +831,8 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
	if (irq < 0)
		return irq;

	drv->irq = irq;

	ret = devm_request_irq(&pdev->dev, irq, tcs_tx_done,
			       IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
			       drv->name, drv);
+7 −3
Original line number Diff line number Diff line
@@ -331,8 +331,12 @@ int rpmh_write(const struct device *dev, enum rpmh_state state,
		return ret;

	ret = wait_for_completion_timeout(&compl, RPMH_TIMEOUT_MS);
	WARN_ON(!ret);
	return (ret > 0) ? 0 : -ETIMEDOUT;
	if (!ret) {
		rpmh_rsc_debug(ctrlr_to_drv(ctrlr));
		return -ETIMEDOUT;
	}

	return 0;
}
EXPORT_SYMBOL(rpmh_write);

@@ -459,7 +463,7 @@ int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
			 * the completion on our stack and that's bad once
			 * we've returned from the function.
			 */
			WARN_ON(1);
			rpmh_rsc_debug(ctrlr_to_drv(ctrlr));
			ret = -ETIMEDOUT;
			goto exit;
		}