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

Commit 8ff1a590 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 38ad1712 955160f0
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;
		}