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

Commit 51bc14d7 authored by Lina Iyer's avatar Lina Iyer
Browse files

drivers: mailbox: qti-tcs: Update error logging



Provide more statistics when we are unable to send a RPMH message. Log
the time stamp when sending a request and receiving a response for each
TCS and print them, when we cannot find a free TCS to write to.

If the TCSes are busy to handle the request, return -EBUSY back to
mailbox framework which would then retry when the interrupt handler
finally gets a chance to run and schedules a tasklet. The tasklet calls
tx_done on the mailbox and retries the message.

Change-Id: I4452343e3ebcaabe3b3fc820489be722263135d8
Signed-off-by: default avatarLina Iyer <ilina@codeaurora.org>
parent ec57adc3
Loading
Loading
Loading
Loading
+92 −31
Original line number Diff line number Diff line
@@ -134,6 +134,9 @@ struct tcs_drv {
	struct workqueue_struct *wq;
	struct tcs_response_pool *resp_pool;
	atomic_t tcs_in_use[MAX_POOL_SIZE];
	/* Debug info */
	u64 tcs_last_sent_ts[MAX_POOL_SIZE];
	u64 tcs_last_recv_ts[MAX_POOL_SIZE];
	atomic_t tcs_send_count[MAX_POOL_SIZE];
	atomic_t tcs_irq_count[MAX_POOL_SIZE];
};
@@ -170,8 +173,9 @@ static struct tcs_response *setup_response(struct tcs_drv *drv,
	struct tcs_response_pool *pool = drv->resp_pool;
	struct tcs_response *resp = ERR_PTR(-ENOMEM);
	int pos;
	unsigned long flags;

	spin_lock(&pool->lock);
	spin_lock_irqsave(&pool->lock, flags);
	pos = find_first_zero_bit(pool->avail, MAX_POOL_SIZE);
	if (pos != MAX_POOL_SIZE) {
		bitmap_set(pool->avail, pos, 1);
@@ -182,7 +186,7 @@ static struct tcs_response *setup_response(struct tcs_drv *drv,
		resp->err = err;
		resp->in_use = false;
	}
	spin_unlock(&pool->lock);
	spin_unlock_irqrestore(&pool->lock, flags);

	return resp;
}
@@ -190,34 +194,62 @@ static struct tcs_response *setup_response(struct tcs_drv *drv,
static void free_response(struct tcs_response *resp)
{
	struct tcs_response_pool *pool = resp->drv->resp_pool;
	unsigned long flags;

	spin_lock(&pool->lock);
	spin_lock_irqsave(&pool->lock, flags);
	resp->err = -EINVAL;
	bitmap_clear(pool->avail, resp->idx, 1);
	spin_unlock(&pool->lock);
	spin_unlock_irqrestore(&pool->lock, flags);
}

static inline struct tcs_response *get_response(struct tcs_drv *drv, u32 m)
static inline struct tcs_response *get_response(struct tcs_drv *drv, u32 m,
					bool for_use)
{
	struct tcs_response_pool *pool = drv->resp_pool;
	struct tcs_response *resp = NULL;
	int pos = 0;
	unsigned long flags;

	spin_lock_irqsave(&pool->lock, flags);
	do {
		pos = find_next_bit(pool->avail, MAX_POOL_SIZE, pos);
		if (pos == MAX_POOL_SIZE)
			break;

		resp = &pool->resp[pos];
		if (resp->m == m && !resp->in_use) {
			resp->in_use = true;
			resp->in_use = for_use;
			break;
		}
		pos++;
		udelay(1);
	} while (1);
	spin_unlock_irqrestore(&pool->lock, flags);

	return resp;
}

static void print_response(struct tcs_drv *drv, int m)
{
	struct tcs_response *resp;
	struct tcs_mbox_msg *msg;
	int i;

	resp = get_response(drv, m, false);
	if (!resp)
		return;

	msg = resp->msg;
	pr_info("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
			resp->idx, resp->m, resp->in_use);
	pr_info("Msg: state=%d\n", msg->state);
	for (i = 0; i < msg->num_payload; i++)
		pr_info("addr=0x%x data=0x%x complete=0x%x\n",
				msg->payload[i].addr,
				msg->payload[i].data,
				msg->payload[i].complete);
}

static inline u32 read_drv_config(void __iomem *base)
{
	return le32_to_cpu(readl_relaxed(base + DRV_PRNT_CHLD_CONFIG));
@@ -257,17 +289,19 @@ static inline bool tcs_is_free(struct tcs_drv *drv, int m)

static inline struct tcs_mbox *get_tcs_from_index(struct tcs_drv *drv, int m)
{
	struct tcs_mbox *tcs;
	struct tcs_mbox *tcs = NULL;
	int i;

	for (i = 0; i < TCS_TYPE_NR; i++) {
	for (i = 0; i < drv->num_tcs; i++) {
		tcs = &drv->tcs[i];
		if (tcs->tcs_mask & BIT(m))
		if (tcs->tcs_mask & (u32)BIT(m))
			break;
	}

	if (i == TCS_TYPE_NR)
	if (i == drv->num_tcs) {
		WARN(1, "Incorrect TCS index %d", m);
		tcs = NULL;
	}

	return tcs;
}
@@ -369,16 +403,10 @@ static irqreturn_t tcs_irq_handler(int irq, void *p)
			continue;
		atomic_inc(&drv->tcs_irq_count[m]);

		resp = get_response(drv, m);
		resp = get_response(drv, m, true);
		if (!resp) {
			pr_err("No resp request for TCS-%d\n", m);
			continue;
		}

		tcs = get_tcs_from_index(drv, m);
		if (!tcs) {
			pr_err("TCS-%d doesn't exist in DRV\n", m);
			continue;
			goto no_resp;
		}

		/* Check if all commands were completed */
@@ -404,7 +432,8 @@ static irqreturn_t tcs_irq_handler(int irq, void *p)
						resp->err);

		/* Clear the AMC mode for non-ACTIVE TCSes */
		if (tcs->type != ACTIVE_TCS) {
		tcs = get_tcs_from_index(drv, m);
		if (tcs && tcs->type != ACTIVE_TCS) {
			data = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
			data &= ~TCS_AMC_MODE_ENABLE;
			write_tcs_reg(base, TCS_DRV_CONTROL, m, 0, data);
@@ -419,10 +448,15 @@ static irqreturn_t tcs_irq_handler(int irq, void *p)
			write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
		}

no_resp:
		/* Record the recvd time stamp */
		drv->tcs_last_recv_ts[m] = arch_counter_get_cntvct();

		/* Clear the TCS IRQ status */
		write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, BIT(m));

		/* Clean up response object and notify mbox in tasklet */
		if (resp)
			send_tcs_response(resp);

		/* Notify the client that this request is completed. */
@@ -628,7 +662,6 @@ static int find_slots(struct tcs_mbox *tcs, struct tcs_mbox_msg *msg)
static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg,
				bool trigger)
{
	const struct device *dev = chan->cl->dev;
	struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
	int d = drv->drv_id;
	struct tcs_mbox *tcs;
@@ -647,7 +680,6 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg,
	spin_lock_irqsave(&tcs->tcs_lock, flags);
	slot = find_slots(tcs, msg);
	if (slot < 0) {
		dev_err(dev, "No TCS slot found.\n");
		spin_unlock_irqrestore(&tcs->tcs_lock, flags);
		if (resp)
			free_response(resp);
@@ -683,6 +715,7 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg,
		/* Enable interrupt for active votes through wake TCS */
		if (tcs->type != ACTIVE_TCS)
			enable_tcs_irq(drv, m, true);
		drv->tcs_last_sent_ts[m] = arch_counter_get_cntvct();
	}

	/* Write to the TCS or AMC */
@@ -725,6 +758,24 @@ static int tcs_mbox_invalidate(struct mbox_chan *chan)
	return 0;
}

static void dump_tcs_stats(struct tcs_drv *drv)
{
	int i;
	unsigned long long curr = arch_counter_get_cntvct();

	for (i = 0; i < drv->num_tcs; i++) {
		if (!atomic_read(&drv->tcs_in_use[i]))
			continue;
		pr_info("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n",
				curr, i,
				atomic_read(&drv->tcs_send_count[i]),
				drv->tcs_last_sent_ts[i],
				atomic_read(&drv->tcs_irq_count[i]),
				drv->tcs_last_recv_ts[i]);
		print_response(drv, i);
	}
}

/**
 * chan_tcs_write: Validate the incoming message and write to the
 * appropriate TCS block.
@@ -738,35 +789,41 @@ static int tcs_mbox_invalidate(struct mbox_chan *chan)
 */
static int chan_tcs_write(struct mbox_chan *chan, void *data)
{
	struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
	struct tcs_mbox_msg *msg = data;
	const struct device *dev = chan->cl->dev;
	int ret = -EINVAL;
	int ret = 0;
	int count = 0;

	if (!msg) {
		dev_err(dev, "Payload error.\n");
		ret = -EINVAL;
		goto tx_fail;
	}

	if (!msg->payload || msg->num_payload > MAX_RPMH_PAYLOAD) {
		dev_err(dev, "Payload error.\n");
		ret = -EINVAL;
		goto tx_fail;
	}

	if (msg->invalidate || msg->is_control) {
		dev_err(dev, "Incorrect API.\n");
		ret = -EINVAL;
		goto tx_fail;
	}

	if (msg->state != RPMH_ACTIVE_ONLY_STATE &&
			msg->state != RPMH_AWAKE_STATE) {
		dev_err(dev, "Incorrect API.\n");
		ret = -EINVAL;
		goto tx_fail;
	}

	/* Read requests should always be single */
	if (msg->is_read && msg->num_payload > 1) {
		dev_err(dev, "Incorrect read request.\n");
		ret = -EINVAL;
		goto tx_fail;
	}

@@ -780,25 +837,29 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data)
	/* Post the message to the TCS and trigger */
	do {
		ret = tcs_mbox_write(chan, msg, true);
		if (ret == -EBUSY) {
			ret = -EIO;
			udelay(10);
		} else
		if (ret != -EBUSY)
			break;
		udelay(100);
	} while (++count < 10);

tx_fail:
	if (ret) {
		struct tcs_drv *drv = container_of(chan->mbox,
					struct tcs_drv, mbox);
	/* If there was an error in the request, schedule a response */
	if (ret < 0 && ret != -EBUSY) {
		struct tcs_response *resp = setup_response(
				drv, msg, chan, TCS_M_INIT, ret);

		dev_err(dev, "Error sending RPMH message %d\n", ret);
		send_tcs_response(resp);
		ret = 0;
	}

	return 0;
	/* If we were just busy waiting for TCS, dump the state and return */
	if (ret == -EBUSY) {
		dev_err(dev, "TCS Busy, retrying RPMH message send\n");
		dump_tcs_stats(drv);
	}

	return ret;
}

static void __tcs_write_hidden(struct tcs_drv *drv, int d,