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

Commit e5135ccb authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers: mailbox: qti_tcs: re-organize code"

parents 499351e9 14424654
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ static void msg_submit(struct mbox_chan *chan)
	void *data;
	int err = -EBUSY;

again:
	spin_lock_irqsave(&chan->lock, flags);

	if (!chan->msg_count || chan->active_req)
@@ -85,6 +86,16 @@ static void msg_submit(struct mbox_chan *chan)
exit:
	spin_unlock_irqrestore(&chan->lock, flags);

	/*
	 * If the controller returns -EAGAIN, then it means, our spinlock
	 * here is preventing the controller from receiving its interrupt,
	 * that would help clear the controller channels that are currently
	 * blocked waiting on the interrupt response.
	 * Unlock and retry again.
	 */
	if (err == -EAGAIN)
		goto again;

	if (!err && (chan->txdone_method & TXDONE_BY_POLL))
		/* kick start the timer immediately to avoid delays */
		hrtimer_start(&chan->mbox->poll_hrt, ktime_set(0, 0),
+107 −42
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>

#include <asm-generic/io.h>

@@ -95,10 +94,10 @@ struct tcs_response {
	struct mbox_chan *chan;
	struct tcs_mbox_msg *msg;
	u32 m; /* m-th TCS */
	struct tasklet_struct tasklet;
	int err;
	int idx;
	bool in_use;
	struct list_head list;
};

struct tcs_response_pool {
@@ -122,16 +121,18 @@ struct tcs_mbox {

/* One per MBOX controller */
struct tcs_drv {
	struct mbox_controller mbox;
	const char *name;
	void *base; /* start address of the RSC's registers */
	void *reg_base; /* start address for DRV specific register */
	void __iomem *base; /* start address of the RSC's registers */
	void __iomem *reg_base; /* start address for DRV specific register */
	int drv_id;
	struct platform_device *pdev;
	struct mbox_controller mbox;
	struct tcs_mbox tcs[TCS_TYPE_NR];
	int num_assigned;
	int num_tcs;
	struct workqueue_struct *wq;
	struct tasklet_struct tasklet;
	struct list_head response_pending;
	spinlock_t drv_lock;
	struct tcs_response_pool *resp_pool;
	atomic_t tcs_in_use[MAX_POOL_SIZE];
	/* Debug info */
@@ -141,8 +142,6 @@ struct tcs_drv {
	atomic_t tcs_irq_count[MAX_POOL_SIZE];
};

static void tcs_notify_tx_done(unsigned long data);

static int tcs_response_pool_init(struct tcs_drv *drv)
{
	struct tcs_response_pool *pool;
@@ -153,11 +152,10 @@ static int tcs_response_pool_init(struct tcs_drv *drv)
		return -ENOMEM;

	for (i = 0; i < MAX_POOL_SIZE; i++) {
		tasklet_init(&pool->resp[i].tasklet, tcs_notify_tx_done,
						(unsigned long) &pool->resp[i]);
		pool->resp[i].drv = drv;
		pool->resp[i].idx = i;
		pool->resp[i].m = TCS_M_INIT;
		INIT_LIST_HEAD(&pool->resp[i].list);
	}

	spin_lock_init(&pool->lock);
@@ -188,6 +186,9 @@ static struct tcs_response *setup_response(struct tcs_drv *drv,
	}
	spin_unlock_irqrestore(&pool->lock, flags);

	if (pos == MAX_POOL_SIZE)
		pr_err("response pool is full\n");

	return resp;
}

@@ -240,11 +241,11 @@ static void print_response(struct tcs_drv *drv, int m)
		return;

	msg = resp->msg;
	pr_info("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
	pr_debug("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);
	pr_debug("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",
		pr_debug("addr=0x%x data=0x%x complete=0x%x\n",
				msg->payload[i].addr,
				msg->payload[i].data,
				msg->payload[i].complete);
@@ -364,7 +365,15 @@ static inline struct tcs_mbox *get_tcs_for_msg(struct tcs_drv *drv,

static inline void send_tcs_response(struct tcs_response *resp)
{
	tasklet_schedule(&resp->tasklet);
	struct tcs_drv *drv = resp->drv;
	unsigned long flags;

	spin_lock_irqsave(&drv->drv_lock, flags);
	INIT_LIST_HEAD(&resp->list);
	list_add_tail(&resp->list, &drv->response_pending);
	spin_unlock_irqrestore(&drv->drv_lock, flags);

	tasklet_schedule(&drv->tasklet);
}

static inline void enable_tcs_irq(struct tcs_drv *drv, int m, bool enable)
@@ -455,12 +464,12 @@ static irqreturn_t tcs_irq_handler(int irq, void *p)
		/* Clear the TCS IRQ status */
		write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, BIT(m));

		/* Notify the client that this request is completed. */
		atomic_set(&drv->tcs_in_use[m], 0);

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

		/* Notify the client that this request is completed. */
		atomic_set(&drv->tcs_in_use[m], 0);
	}

	return IRQ_HANDLED;
@@ -475,19 +484,38 @@ static inline void mbox_notify_tx_done(struct mbox_chan *chan,
	mbox_chan_txdone(chan, err);
}

/**
 * tcs_notify_tx_done: TX Done for requests that do not trigger TCS
 */
static void tcs_notify_tx_done(unsigned long data)
static void respond_tx_done(struct tcs_response *resp)
{
	struct tcs_response *resp = (struct tcs_response *) data;
	struct mbox_chan *chan = resp->chan;
	struct tcs_mbox_msg *msg = resp->msg;
	int err = resp->err;
	int m = resp->m;

	mbox_notify_tx_done(chan, msg, m, err);
	free_response(resp);
	mbox_notify_tx_done(chan, msg, m, err);
}

/**
 * tcs_notify_tx_done: TX Done for requests that do not trigger TCS
 */
static void tcs_notify_tx_done(unsigned long data)
{
	struct tcs_drv *drv = (struct tcs_drv *)data;
	struct tcs_response *resp;
	unsigned long flags;

	do {
		spin_lock_irqsave(&drv->drv_lock, flags);
		if (list_empty(&drv->response_pending)) {
			spin_unlock_irqrestore(&drv->drv_lock, flags);
			break;
		}
		resp = list_first_entry(&drv->response_pending,
					struct tcs_response, list);
		list_del(&resp->list);
		spin_unlock_irqrestore(&drv->drv_lock, flags);
		respond_tx_done(resp);
	} while (1);
}

static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n,
@@ -673,8 +701,11 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg,
	if (IS_ERR(tcs))
		return PTR_ERR(tcs);

	if (trigger)
	if (trigger) {
		resp = setup_response(drv, msg, chan, TCS_M_INIT, 0);
		if (IS_ERR_OR_NULL(resp))
			return -EBUSY;
	}

	/* Identify the sequential slots that we can write to */
	spin_lock_irqsave(&tcs->tcs_lock, flags);
@@ -686,28 +717,21 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg,
		return slot;
	}

	/* Figure out the TCS-m and CMD-n to write to */
	offset = slot / tcs->ncpt;
	m = offset + tcs->tcs_offset;
	n = slot % tcs->ncpt;

	if (trigger) {
		/* Block, if we have an address from the msg in flight */
		ret = check_for_req_inflight(drv, tcs, msg);
		if (ret) {
			spin_unlock_irqrestore(&tcs->tcs_lock, flags);
			if (resp)
				free_response(resp);
			return ret;
		}
	}

	/* Mark the slots as in-use, before we unlock */
	if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS)
		bitmap_set(tcs->slots, slot, msg->num_payload);

	/* Copy the addresses of the resources over to the slots */
	for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++)
		tcs->cmd_addr[slot + i] = msg->payload[i].addr;

	offset = slot / tcs->ncpt;
	m = offset + tcs->tcs_offset;
	n = slot % tcs->ncpt;

	/* Block, if we have an address from the msg in flight */
	if (trigger) {
		resp->m = m;
		/* Mark the TCS as busy */
		atomic_set(&drv->tcs_in_use[m], 1);
@@ -716,6 +740,14 @@ static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg,
		if (tcs->type != ACTIVE_TCS)
			enable_tcs_irq(drv, m, true);
		drv->tcs_last_sent_ts[m] = arch_counter_get_cntvct();
	} else {
		/* Mark the slots as in-use, before we unlock */
		if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS)
			bitmap_set(tcs->slots, slot, msg->num_payload);

		/* Copy the addresses of the resources over to the slots */
		for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++)
			tcs->cmd_addr[slot + i] = msg->payload[i].addr;
	}

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

static void print_tcs_regs(struct tcs_drv *drv, int m)
{
	int n;
	struct tcs_mbox *tcs = get_tcs_from_index(drv, m);
	void __iomem *base = drv->reg_base;
	u32 enable, addr, data, msgid;

	if (!tcs || tcs_is_free(drv, m))
		return;

	enable = read_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0);
	if (!enable)
		return;

	pr_debug("TCS-%d contents:\n", m);
	for (n = 0; n < tcs->ncpt; n++) {
		if (!(enable & BIT(n)))
			continue;
		addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n);
		data = read_tcs_reg(base, TCS_DRV_CMD_DATA, m, n);
		msgid = read_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n);
		pr_debug("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n",
						n, addr, data, msgid);
	}
}

static void dump_tcs_stats(struct tcs_drv *drv)
{
	int i;
@@ -766,12 +824,13 @@ static void dump_tcs_stats(struct tcs_drv *drv)
	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",
		pr_debug("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_tcs_regs(drv, i);
		print_response(drv, i);
	}
}
@@ -840,7 +899,7 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data)
		if (ret != -EBUSY)
			break;
		udelay(100);
	} while (++count < 10);
	} while (++count < 100);

tx_fail:
	/* If there was an error in the request, schedule a response */
@@ -849,6 +908,7 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data)
				drv, msg, chan, TCS_M_INIT, ret);

		dev_err(dev, "Error sending RPMH message %d\n", ret);
		if (resp)
			send_tcs_response(resp);
		ret = 0;
	}
@@ -857,6 +917,7 @@ static int chan_tcs_write(struct mbox_chan *chan, void *data)
	if (ret == -EBUSY) {
		dev_err(dev, "TCS Busy, retrying RPMH message send\n");
		dump_tcs_stats(drv);
		ret = -EAGAIN;
	}

	return ret;
@@ -967,6 +1028,7 @@ static struct mbox_chan *of_tcs_mbox_xlate(struct mbox_controller *mbox,
	}

	chan = &mbox->chans[drv->num_assigned++];
	chan->con_priv = drv;

	return chan;
}
@@ -1108,6 +1170,9 @@ static int tcs_drv_probe(struct platform_device *pdev)
	drv->mbox.is_idle = tcs_drv_is_idle;
	drv->num_tcs = st;
	drv->pdev = pdev;
	INIT_LIST_HEAD(&drv->response_pending);
	spin_lock_init(&drv->drv_lock);
	tasklet_init(&drv->tasklet, tcs_notify_tx_done, (unsigned long)drv);

	drv->name = of_get_property(pdev->dev.of_node, "label", NULL);
	if (!drv->name)
+51 −42
Original line number Diff line number Diff line
@@ -35,13 +35,17 @@

#define DEFINE_RPMH_MSG_ONSTACK(rc, s, q, c, name)	\
	struct rpmh_msg name = {			\
		.msg = { 0 },			\
		.msg.state = s,			\
		.msg.is_complete = true,	\
		.msg.payload = name.cmd,	\
		.msg.num_payload = 0,		\
		.msg = {				\
			.state = s,			\
			.payload = name.cmd,		\
			.num_payload = 0,		\
			.is_read = false,		\
			.is_control = false,		\
			.is_complete = true,		\
			.invalidate = false,		\
		},					\
		.cmd = { { 0 } },			\
		.waitq = q,			\
		.completion = q,			\
		.wait_count = c,			\
		.rc = rc,				\
		.bit = -1,				\
@@ -57,7 +61,7 @@ struct rpmh_req {
struct rpmh_msg {
	struct tcs_mbox_msg msg;
	struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
	wait_queue_head_t *waitq;
	struct completion *completion;
	atomic_t *wait_count;
	struct rpmh_client *rc;
	int bit;
@@ -106,21 +110,31 @@ static struct rpmh_msg *get_msg_from_pool(struct rpmh_client *rc)
	return msg;
}

static void free_msg_to_pool(struct rpmh_msg *rpm_msg)
{
	struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
	unsigned long flags;

	/* If we allocated the pool, set it as available */
	if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
		spin_lock_irqsave(&rpm->lock, flags);
		bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
		spin_unlock_irqrestore(&rpm->lock, flags);
	}
}

static void rpmh_rx_cb(struct mbox_client *cl, void *msg)
{
	struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg);

	atomic_dec(rpm_msg->wait_count);
	wake_up(rpm_msg->waitq);
}

static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r)
{
	struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg);
	struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
	atomic_t *wc = rpm_msg->wait_count;
	wait_queue_head_t *waitq = rpm_msg->waitq;
	unsigned long flags;
	struct completion *compl = rpm_msg->completion;

	rpm_msg->err = r;

@@ -144,18 +158,12 @@ static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r)
	 * into an issue that the stack allocated parent object may be
	 * invalid before we can check the ->bit value.
	 */

	/* If we allocated the pool, set it as available */
	if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
		spin_lock_irqsave(&rpm->lock, flags);
		bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
		spin_unlock_irqrestore(&rpm->lock, flags);
	}
	free_msg_to_pool(rpm_msg);

	/* Signal the blocking thread we are done */
	if (wc && atomic_dec_and_test(wc))
		if (waitq)
			wake_up(waitq);
		if (compl)
			complete(compl);
}

static struct rpmh_req *__find_req(struct rpmh_client *rc, u32 addr)
@@ -312,9 +320,9 @@ EXPORT_SYMBOL(rpmh_write_single_async);
int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state,
			u32 addr, u32 data)
{
	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
	DECLARE_COMPLETION_ONSTACK(compl);
	atomic_t wait_count = ATOMIC_INIT(1);
	DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg);
	DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg);
	int ret;

	if (IS_ERR_OR_NULL(rc))
@@ -333,7 +341,7 @@ int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state,
	if (ret < 0)
		return ret;

	wait_event(waitq, atomic_read(&wait_count) == 0);
	wait_for_completion(&compl);

	return rpm_msg.err;
}
@@ -408,9 +416,9 @@ EXPORT_SYMBOL(rpmh_write_async);
int rpmh_write(struct rpmh_client *rc, enum rpmh_state state,
			struct tcs_cmd *cmd, int n)
{
	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
	DECLARE_COMPLETION_ONSTACK(compl);
	atomic_t wait_count = ATOMIC_INIT(1);
	DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg);
	DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg);
	int ret;

	if (IS_ERR_OR_NULL(rc) || !cmd || n <= 0 || n > MAX_RPMH_PAYLOAD)
@@ -428,7 +436,7 @@ int rpmh_write(struct rpmh_client *rc, enum rpmh_state state,
	if (ret)
		return ret;

	wait_event(waitq, atomic_read(&wait_count) == 0);
	wait_for_completion(&compl);

	return rpm_msg.err;
}
@@ -454,7 +462,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
			struct tcs_cmd *cmd, int *n)
{
	struct rpmh_msg *rpm_msg[RPMH_MAX_REQ_IN_BATCH];
	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
	DECLARE_COMPLETION_ONSTACK(compl);
	atomic_t wait_count = ATOMIC_INIT(0); /* overwritten */
	int count = 0;
	int ret, i, j, k;
@@ -507,9 +515,8 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
	for (i = 0; i < count; i++) {
		rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i]);
		if (IS_ERR_OR_NULL(rpm_msg[i])) {
			/* Clean up our call by spoofing tx_done */
			for (j = 0 ; j < i; j++)
				rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, 0);
				free_msg_to_pool(rpm_msg[j]);
			return PTR_ERR(rpm_msg[i]);
		}
		cmd += n[i];
@@ -520,7 +527,7 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
		might_sleep();
		atomic_set(&wait_count, count);
		for (i = 0; i < count; i++) {
			rpm_msg[i]->waitq = &waitq;
			rpm_msg[i]->completion = &compl;
			rpm_msg[i]->wait_count = &wait_count;
			/* Bypass caching and write to mailbox directly */
			ret = mbox_send_message(rc->chan, &rpm_msg[i]->msg);
@@ -530,15 +537,17 @@ int rpmh_write_passthru(struct rpmh_client *rc, enum rpmh_state state,
				break;
			}
		}
		wait_event(waitq, atomic_read(&wait_count) == (count - i));
		/* For those unsent requests, spoof tx_done */
		for (j = i; j < count; j++)
			rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, ret);
		wait_for_completion(&compl);
	} else {
		/* Send Sleep requests to the controller, expect no response */
		for (i = 0; i < count; i++) {
			rpm_msg[i]->waitq = NULL;
			rpm_msg[i]->completion = NULL;
			ret = mbox_send_controller_data(rc->chan,
						&rpm_msg[i]->msg);
			/* Clean up our call by spoofing tx_done */
			rpmh_tx_done(&rc->client, &rpm_msg[i]->msg, ret);
			free_msg_to_pool(rpm_msg[i]);
		}
		return 0;
	}
@@ -660,10 +669,10 @@ EXPORT_SYMBOL(rpmh_invalidate);
int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp)
{
	int ret;
	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
	DECLARE_COMPLETION_ONSTACK(compl);
	atomic_t wait_count = ATOMIC_INIT(2); /* wait for rx_cb and tx_done */
	DEFINE_RPMH_MSG_ONSTACK(rc, RPMH_ACTIVE_ONLY_STATE,
				&waitq, &wait_count, rpm_msg);
				&compl, &wait_count, rpm_msg);

	if (IS_ERR_OR_NULL(rc) || !resp)
		return -EINVAL;
@@ -684,7 +693,7 @@ int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp)
		return ret;

	/* Wait until the response is received from RPMH */
	wait_event(waitq, atomic_read(&wait_count) == 0);
	wait_for_completion(&compl);

	/* Read the data back from the tcs_mbox_msg structrure */
	*resp = rpm_msg.cmd[0].data;