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

Commit 7ec1605a authored by Chris Lew's avatar Chris Lew
Browse files

rpmsg: glink: spi: Try to send rx done immediately



Some remote processors and usecases such as audio playback are
sensitive to the response time of rx done. Try to send the rx done cmd
from rx context. If trysend fails, defer the rx done work like before.

Change-Id: I299cc30920d1a6adfe597001d84a052f886141d0
Signed-off-by: default avatarChris Lew <clew@codeaurora.org>
parent 0f798a65
Loading
Loading
Loading
Loading
+61 −41
Original line number Diff line number Diff line
@@ -1360,30 +1360,38 @@ static void glink_spi_handle_rx_done(struct glink_spi *glink,
	spin_unlock_irqrestore(&channel->intent_lock, flags);
}

static void glink_spi_rx_done(struct glink_spi *glink,
static int __glink_spi_rx_done(struct glink_spi *glink,
				struct glink_channel *channel,
			       struct glink_core_rx_intent *intent)
				struct glink_core_rx_intent *intent,
				bool wait)
{
	/* We don't send RX_DONE to intentless systems */
	if (glink->intentless) {
	struct {
		u16 id;
		u16 lcid;
		u32 liid;
		u64 reserved;
	} __packed cmd;
	unsigned int cid = channel->lcid;
	unsigned int iid = intent->id;
	bool reuse = intent->reuse;
	int ret;

	cmd.id = reuse ? SPI_CMD_RX_DONE_W_REUSE : SPI_CMD_RX_DONE;
	cmd.lcid = cid;
	cmd.liid = iid;

	ret = glink_spi_tx(glink, &cmd, sizeof(cmd), NULL, 0, wait);
	if (ret)
		return ret;

	intent->offset = 0;
	if (!reuse) {
		kfree(intent->data);
		kfree(intent);
		return;
	}

	/* Take it off the tree of receive intents */
	if (!intent->reuse) {
		spin_lock(&channel->intent_lock);
		idr_remove(&channel->liids, intent->id);
		spin_unlock(&channel->intent_lock);
	}

	/* Schedule the sending of a rx_done indication */
	spin_lock(&channel->intent_lock);
	list_add_tail(&intent->node, &channel->done_intents);
	spin_unlock(&channel->intent_lock);

	schedule_work(&channel->intent_work);
	CH_INFO(channel, "reuse:%d liid:%d", reuse, iid);
	return 0;
}

static void glink_spi_rx_done_work(struct work_struct *work)
@@ -1392,40 +1400,52 @@ static void glink_spi_rx_done_work(struct work_struct *work)
						     intent_work);
	struct glink_spi *glink = channel->glink;
	struct glink_core_rx_intent *intent, *tmp;
	struct {
		u16 id;
		u16 lcid;
		u32 liid;
		u64 reserved;
	} __packed cmd;

	unsigned int lcid = channel->lcid;
	unsigned int iid;
	bool reuse;
	unsigned long flags;

	spin_lock_irqsave(&channel->intent_lock, flags);
	list_for_each_entry_safe(intent, tmp, &channel->done_intents, node) {
		list_del(&intent->node);
		spin_unlock_irqrestore(&channel->intent_lock, flags);
		iid = intent->id;
		reuse = intent->reuse;

		cmd.id = reuse ? SPI_CMD_RX_DONE_W_REUSE : SPI_CMD_RX_DONE;
		cmd.lcid = lcid;
		cmd.liid = iid;
		__glink_spi_rx_done(glink, channel, intent, true);

		CH_INFO(channel, "reuse:%d liid:%d", reuse, iid);
		glink_spi_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
		intent->offset = 0;
		if (!reuse) {
		spin_lock_irqsave(&channel->intent_lock, flags);
	}
	spin_unlock_irqrestore(&channel->intent_lock, flags);
}

static void glink_spi_rx_done(struct glink_spi *glink,
			       struct glink_channel *channel,
			       struct glink_core_rx_intent *intent)
{
	unsigned long flags;
	int ret = -EAGAIN;

	/* We don't send RX_DONE to intentless systems */
	if (glink->intentless) {
		kfree(intent->data);
		kfree(intent);
		return;
	}

	/* Take it off the tree of receive intents */
	if (!intent->reuse) {
		spin_lock_irqsave(&channel->intent_lock, flags);
		idr_remove(&channel->liids, intent->id);
		spin_unlock_irqrestore(&channel->intent_lock, flags);
	}

	/* Schedule the sending of a rx_done indication */
	if (list_empty(&channel->done_intents))
		ret = __glink_spi_rx_done(glink, channel, intent, false);

	if (ret) {
		spin_lock_irqsave(&channel->intent_lock, flags);
		list_add_tail(&intent->node, &channel->done_intents);
		schedule_work(&channel->intent_work);
		spin_unlock_irqrestore(&channel->intent_lock, flags);
	}
}

/* Locally initiated rpmsg_create_ept */
static struct glink_channel *glink_spi_create_local(struct glink_spi *glink,