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

Commit 284df960 authored by Jeff Hugo's avatar Jeff Hugo Committed by Karthikeyan Ramasubramanian
Browse files

soc: qcom: glink: Implement RX intent reuse



Add the infrastructure to enable the G-Link clients to re-use an RX intent.
Update the G-Link loopback server and IPC Router to re-use an RX intent
appropriately.

Change-Id: I51793ed012f0da12d70ddf4295122d08c184de3d
Signed-off-by: default avatarJeffrey Hugo <jhugo@codeaurora.org>
Signed-off-by: default avatarKarthikeyan Ramasubramanian <kramasub@codeaurora.org>
parent 982147c1
Loading
Loading
Loading
Loading
+69 −20
Original line number Diff line number Diff line
@@ -245,7 +245,7 @@ static void ch_push_remote_rx_intent(struct channel_ctx *ctx, size_t size,
							uint32_t riid);

static int ch_pop_remote_rx_intent(struct channel_ctx *ctx, size_t size,
							uint32_t *riid_ptr);
				uint32_t *riid_ptr, size_t *intent_size);

static struct glink_core_rx_intent *ch_push_local_rx_intent(
		struct channel_ctx *ctx, const void *pkt_priv, size_t size);
@@ -262,7 +262,7 @@ static struct glink_core_rx_intent *ch_get_local_rx_intent_notified(
		struct channel_ctx *ctx, const void *ptr);

static void ch_remove_local_rx_intent_notified(struct channel_ctx *ctx,
					struct glink_core_rx_intent *liid_ptr);
			struct glink_core_rx_intent *liid_ptr, bool reuse);

static struct glink_core_rx_intent *ch_get_free_local_rx_intent(
		struct channel_ctx *ctx);
@@ -569,7 +569,7 @@ bool ch_check_duplicate_riid(struct channel_ctx *ctx, int riid)
 * This functions searches for an RX intent that is >= to the requested size.
 */
int ch_pop_remote_rx_intent(struct channel_ctx *ctx, size_t size,
		uint32_t *riid_ptr)
		uint32_t *riid_ptr, size_t *intent_size)
{
	struct glink_core_rx_intent *intent;
	struct glink_core_rx_intent *intent_tmp;
@@ -596,15 +596,16 @@ int ch_pop_remote_rx_intent(struct channel_ctx *ctx, size_t size,
			list) {
		if (intent->intent_size >= size) {
			list_del(&intent->list);
			*riid_ptr = intent->id;
			kfree(intent);
			spin_unlock_irqrestore(
				&ctx->rmt_rx_intent_lst_lock_lhc2, flags);
			GLINK_DBG_CH(ctx,
					"%s: R[%u]:%zu Removed remote intent\n",
					__func__,
					intent->id,
					intent->intent_size);
			*riid_ptr = intent->id;
			*intent_size = intent->intent_size;
			kfree(intent);
			spin_unlock_irqrestore(
				&ctx->rmt_rx_intent_lst_lock_lhc2, flags);
			return 0;
		}
	}
@@ -705,7 +706,8 @@ struct glink_core_rx_intent *ch_push_local_rx_intent(struct channel_ctx *ctx,
	}

	/* transport is responsible for allocating/reserving for the intent */
	ret = ctx->transport_ptr->ops->allocate_rx_intent(size, intent);
	ret = ctx->transport_ptr->ops->allocate_rx_intent(
					ctx->transport_ptr->ops, size, intent);
	if (ret < 0) {
		/* intent data allocation failure */
		GLINK_ERR_CH(ctx, "%s: unable to allocate intent sz[%zu] %d",
@@ -947,13 +949,14 @@ struct glink_core_rx_intent *ch_get_local_rx_intent_notified(
 *					notified list
 * @ctx:	Local channel context
 * @ptr:	Pointer to the rx intent
 * @reuse:	Reuse the rx intent
 *
 * This functions parses the local intent notify list for a specific channel
 * and checks for the intent. If found, the function deletes the intent
 * from local_rx_intent_notified list and adds it to local_rx_intent_free list.
 */
void ch_remove_local_rx_intent_notified(struct channel_ctx *ctx,
	struct glink_core_rx_intent *liid_ptr)
	struct glink_core_rx_intent *liid_ptr, bool reuse)
{
	struct glink_core_rx_intent *ptr_intent, *tmp_intent;
	unsigned long flags;
@@ -970,6 +973,12 @@ void ch_remove_local_rx_intent_notified(struct channel_ctx *ctx,
				ptr_intent->intent_size);
			kfree(ptr_intent->bounce_buf);
			ptr_intent->bounce_buf = NULL;
			ptr_intent->write_offset = 0;
			ptr_intent->pkt_size = 0;
			if (reuse)
				list_add_tail(&ptr_intent->list,
					&ctx->local_rx_intent_list);
			else
				list_add_tail(&ptr_intent->list,
					&ctx->local_rx_intent_free_list);
			spin_unlock_irqrestore(
@@ -1424,6 +1433,20 @@ static int dummy_poll(struct glink_transport_if *if_ptr, uint32_t lcid)
	return -EOPNOTSUPP;
}

/**
 * dummy_reuse_rx_intent() - a dummy reuse_rx_intent() for transports that
 *			     don't define one
 * @if_ptr:	The transport interface handle for this transport.
 * @intent:	The intent to reuse.
 *
 * Return: Success.
 */
static int dummy_reuse_rx_intent(struct glink_transport_if *if_ptr,
				 struct glink_core_rx_intent *intent)
{
	return 0;
}

/**
 * dummy_mask_rx_irq() - a dummy mask_rx_irq() for transports that don't define
 *			 one
@@ -1760,6 +1783,7 @@ static int glink_tx_common(void *handle, void *pkt_priv,
	uint32_t riid;
	int ret = 0;
	struct glink_core_tx_pkt *tx_info;
	size_t intent_size;

	if (!ctx)
		return -EINVAL;
@@ -1774,7 +1798,7 @@ static int glink_tx_common(void *handle, void *pkt_priv,
		return -EINVAL;

	/* find matching rx intent (first-fit algorithm for now) */
	if (ch_pop_remote_rx_intent(ctx, size, &riid)) {
	if (ch_pop_remote_rx_intent(ctx, size, &riid, &intent_size)) {
		if (!(tx_flags & GLINK_TX_REQ_INTENT)) {
			/* no rx intent available */
			GLINK_ERR_CH(ctx,
@@ -1804,13 +1828,15 @@ static int glink_tx_common(void *handle, void *pkt_priv,
			do {
				wait_for_completion(&ctx->int_req_complete);
				reinit_completion(&ctx->int_req_complete);
			} while (ch_pop_remote_rx_intent(ctx, size, &riid));
			} while (ch_pop_remote_rx_intent(ctx, size, &riid,
								&intent_size));
		}
	}

	tx_info = kzalloc(sizeof(struct glink_core_tx_pkt), GFP_KERNEL);
	if (!tx_info) {
		GLINK_ERR_CH(ctx, "%s: No memory for allocation\n", __func__);
		ch_push_remote_rx_intent(ctx, intent_size, riid);
		return -ENOMEM;
	}
	tx_info->pkt_priv = pkt_priv;
@@ -1821,6 +1847,8 @@ static int glink_tx_common(void *handle, void *pkt_priv,
	tx_info->iovec = iovec ? iovec : (void *)tx_info;
	tx_info->vprovider = vbuf_provider;
	tx_info->pprovider = pbuf_provider;
	tx_info->intent_size = intent_size;

	GLINK_INFO_CH(ctx, "%s: data[%p], size[%u]. Thread: %u\n", __func__,
			tx_info->data ? tx_info->data : tx_info->iovec,
			tx_info->size, current->pid);
@@ -1913,10 +1941,12 @@ EXPORT_SYMBOL(glink_queue_rx_intent);
 *
 * Return: 0 for success; standard Linux error code for failure case
 */
int glink_rx_done(void *handle, const void *ptr)
int glink_rx_done(void *handle, const void *ptr, bool reuse)
{
	struct channel_ctx *ctx = (struct channel_ctx *)handle;
	struct glink_core_rx_intent *liid_ptr;
	uint32_t id;
	int ret = 0;

	liid_ptr = ch_get_local_rx_intent_notified(ctx, ptr);

@@ -1926,13 +1956,26 @@ int glink_rx_done(void *handle, const void *ptr)
		return -EINVAL;
	}

	id = liid_ptr->id;
	if (reuse) {
		ret = ctx->transport_ptr->ops->reuse_rx_intent(
					ctx->transport_ptr->ops, liid_ptr);
		if (ret) {
			ret = -ENOBUFS;
			reuse = false;
			ctx->transport_ptr->ops->deallocate_rx_intent(
					ctx->transport_ptr->ops, liid_ptr);
		}
	} else {
		ctx->transport_ptr->ops->deallocate_rx_intent(
					ctx->transport_ptr->ops, liid_ptr);
	}
	ch_remove_local_rx_intent_notified(ctx, liid_ptr, reuse);
	/* send rx done */
	ctx->transport_ptr->ops->tx_cmd_local_rx_done(ctx->transport_ptr->ops,
			ctx->lcid, liid_ptr->id);
	ctx->transport_ptr->ops->deallocate_rx_intent(liid_ptr);
	ch_remove_local_rx_intent_notified(ctx, liid_ptr);
			ctx->lcid, id, reuse);

	return 0;
	return ret;
}
EXPORT_SYMBOL(glink_rx_done);

@@ -2245,6 +2288,8 @@ int glink_core_register_transport(struct glink_transport_if *if_ptr,
		if_ptr->poll = dummy_poll;
	if (!if_ptr->mask_rx_irq)
		if_ptr->mask_rx_irq = dummy_mask_rx_irq;
	if (!if_ptr->reuse_rx_intent)
		if_ptr->reuse_rx_intent = dummy_reuse_rx_intent;
	xprt_ptr->capabilities = 0;
	xprt_ptr->ops = if_ptr;
	spin_lock_init(&xprt_ptr->xprt_ctx_lock_lhb1);
@@ -2995,9 +3040,10 @@ void glink_core_rx_put_pkt_ctx(struct glink_transport_if *if_ptr,
 * @xprt_ptr:	Transport to send packet on.
 * @rcid:	Remote channel ID
 * @riid:	Remote intent ID
 * @reuse:	Reuse the consumed intent
 */
void glink_core_rx_cmd_tx_done(struct glink_transport_if *if_ptr, uint32_t
		rcid, uint32_t riid)
void glink_core_rx_cmd_tx_done(struct glink_transport_if *if_ptr,
			       uint32_t rcid, uint32_t riid, bool reuse)
{
	struct channel_ctx *ctx;
	struct glink_core_tx_pkt *tx_pkt;
@@ -3030,6 +3076,9 @@ void glink_core_rx_cmd_tx_done(struct glink_transport_if *if_ptr, uint32_t
	/* notify client */
	ctx->notify_tx_done(ctx, ctx->user_priv, tx_pkt->pkt_priv,
			    tx_pkt->data ? tx_pkt->data : tx_pkt->iovec);
	if (reuse)
		ch_push_remote_rx_intent(ctx, tx_pkt->intent_size,
								tx_pkt->riid);
	ch_remove_tx_pending_remote_done(ctx, tx_pkt);
	mutex_unlock(&ctx->tx_lists_mutex_lhc3);
}
+1 −1
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ struct glink_core_if {
	void (*rx_cmd_remote_rx_intent_put)(struct glink_transport_if *if_ptr,
			uint32_t rcid, uint32_t riid, size_t size);
	void (*rx_cmd_tx_done)(struct glink_transport_if *if_ptr, uint32_t rcid,
			uint32_t riid);
			uint32_t riid, bool reuse);
	void (*rx_cmd_remote_rx_intent_req)(struct glink_transport_if *if_ptr,
			uint32_t rcid, size_t size);
	void (*rx_cmd_rx_intent_req_ack)(struct glink_transport_if *if_ptr,
+3 −3
Original line number Diff line number Diff line
@@ -729,7 +729,7 @@ static int glink_lbsrv_handle_data(struct rx_work_info *tmp_rx_work_info)
			   msecs_to_jiffies(delay_ms));
	return 0;
out_handle_data:
	glink_rx_done(rx_ch_info->handle, tmp_rx_work_info->ptr);
	glink_rx_done(rx_ch_info->handle, tmp_rx_work_info->ptr, false);
	return ret;
}

@@ -921,7 +921,7 @@ static void glink_lbsrv_rx_worker(struct work_struct *work)

	if (rx_ch_info->type == CTL) {
		request_pkt = *((struct req *)tmp_rx_work_info->ptr);
		glink_rx_done(rx_ch_info->handle, tmp_rx_work_info->ptr);
		glink_rx_done(rx_ch_info->handle, tmp_rx_work_info->ptr, false);
		ret = glink_queue_rx_intent(rx_ch_info->handle, rx_ch_info,
					    sizeof(struct req));
		LBSRV_INFO("%s:%s:%s %s: QUEUE RX INTENT size[%zu] ret[%d]\n",
@@ -1096,7 +1096,7 @@ static void glink_lbsrv_rx_done_worker(struct work_struct *work)

	mutex_lock(&tmp_ch_info->ch_info_lock);
	if (!IS_ERR_OR_NULL(tmp_ch_info->handle))
		glink_rx_done(tmp_ch_info->handle, tmp_work_info->ptr);
		glink_rx_done(tmp_ch_info->handle, tmp_work_info->ptr, false);
	mutex_unlock(&tmp_ch_info->ch_info_lock);
	kfree(tmp_work_info);
}
+51 −8
Original line number Diff line number Diff line
@@ -67,7 +67,8 @@ struct edge_info {
 * @edge:		Handle to the edge_info this channel is associated with.
 * @smd_ch:		Handle to the underlying smd channel.
 * @intents:		List of active intents on this channel.
 * @intents_lock:	Lock to protect @intents.
 * @used_intents:	List of consumed intents on this channel.
 * @intents_lock:	Lock to protect @intents and @used_intents.
 * @next_intent_id:	The next id to use for generated intents.
 * @wq:			Handle for running tasks.
 * @work:		Task to process received data.
@@ -84,6 +85,7 @@ struct channel {
	struct edge_info *edge;
	smd_channel_t *smd_ch;
	struct list_head intents;
	struct list_head used_intents;
	struct mutex intents_lock;
	uint32_t next_intent_id;
	struct workqueue_struct *wq;
@@ -182,7 +184,8 @@ static void process_tx_done(struct work_struct *work)
	kfree(ch_work);
	einfo->xprt_if.glink_core_if_ptr->rx_cmd_tx_done(&einfo->xprt_if,
								ch->lcid,
								riid);
								riid,
								false);
}

/**
@@ -334,7 +337,9 @@ static void process_data_event(struct work_struct *work)
		intent->write_offset += read_avail;
		intent->pkt_size += read_avail;
		if (read_avail == pkt_size && !einfo->intentless) {
			kfree(ch->cur_intent);
			mutex_lock(&ch->intents_lock);
			list_add_tail(&ch->cur_intent->node, &ch->used_intents);
			mutex_unlock(&ch->intents_lock);
			ch->cur_intent = NULL;
		}
		einfo->xprt_if.glink_core_if_ptr->rx_put_pkt_ctx(
@@ -528,6 +533,7 @@ static int tx_cmd_ch_open(struct glink_transport_if *if_ptr, uint32_t lcid,
		ch->pdrv.probe = channel_probe;
		ch->edge = einfo;
		INIT_LIST_HEAD(&ch->intents);
		INIT_LIST_HEAD(&ch->used_intents);
		mutex_init(&ch->intents_lock);
		INIT_WORK(&ch->work, process_data_event);
		ch->wq = create_singlethread_workqueue(ch->name);
@@ -588,6 +594,12 @@ static int tx_cmd_ch_close(struct glink_transport_if *if_ptr, uint32_t lcid)
		list_del(&intent->node);
		kfree(intent);
	}
	while (!list_empty(&ch->used_intents)) {
		intent = list_first_entry(&ch->used_intents, struct intent_info,
									node);
		list_del(&intent->node);
		kfree(intent);
	}
	mutex_unlock(&ch->intents_lock);
	ch->is_closing = false;

@@ -657,6 +669,13 @@ static int ssr(struct glink_transport_if *if_ptr)
			list_del(&intent->node);
			kfree(intent);
		}
		while (!list_empty(&ch->used_intents)) {
			intent = list_first_entry(&ch->used_intents,
							struct intent_info,
							node);
			list_del(&intent->node);
			kfree(intent);
		}
		mutex_unlock(&ch->intents_lock);
		ch->is_closing = false;
	}
@@ -667,6 +686,7 @@ static int ssr(struct glink_transport_if *if_ptr)

/**
 * allocate_rx_intent() - allocate/reserve space for RX Intent
 * @if_ptr:	The transport the intent is associated with.
 * @size:	size of intent.
 * @intent:	Pointer to the intent structure.
 *
@@ -678,7 +698,8 @@ static int ssr(struct glink_transport_if *if_ptr)
 *
 * Return: 0 on success or standard Linux error code.
 */
static int allocate_rx_intent(size_t size, struct glink_core_rx_intent *intent)
static int allocate_rx_intent(struct glink_transport_if *if_ptr, size_t size,
			      struct glink_core_rx_intent *intent)
{
	void *t;

@@ -695,11 +716,13 @@ static int allocate_rx_intent(size_t size, struct glink_core_rx_intent *intent)

/**
 * deallocate_rx_intent() - Deallocate space created for RX Intent
 * @if_ptr:	The transport the intent is associated with.
 * @intent:	Pointer to the intent structure.
 *
 * Return: 0 on success or standard Linux error code.
 */
static int deallocate_rx_intent(struct glink_core_rx_intent *intent)
static int deallocate_rx_intent(struct glink_transport_if *if_ptr,
				struct glink_core_rx_intent *intent)
{
	if (!intent || !intent->data)
		return -EINVAL;
@@ -769,12 +792,32 @@ static int tx_cmd_local_rx_intent(struct glink_transport_if *if_ptr,
 * @if_ptr:	The transport to transmit on.
 * @lcid:	The local channel id to encode.
 * @liid:	The local intent id to encode.
 *
 * The remote side doesn't speak G-Link, so ignore rx_done.
 * @reuse:	Reuse the consumed intent.
 */
static void tx_cmd_local_rx_done(struct glink_transport_if *if_ptr,
				 uint32_t lcid, uint32_t liid)
				 uint32_t lcid, uint32_t liid, bool reuse)
{
	struct edge_info *einfo;
	struct channel *ch;
	struct intent_info *i;

	einfo = container_of(if_ptr, struct edge_info, xprt_if);
	list_for_each_entry(ch, &einfo->channels, node) {
		if (lcid == ch->lcid)
			break;
	}
	mutex_lock(&ch->intents_lock);
	list_for_each_entry(i, &ch->used_intents, node) {
		if (i->liid == liid) {
			list_del(&i->node);
			if (reuse)
				list_add_tail(&i->node, &ch->intents);
			else
				kfree(i);
			break;
		}
	}
	mutex_unlock(&ch->intents_lock);
}

/**
+18 −5
Original line number Diff line number Diff line
@@ -798,7 +798,8 @@ static void rx_worker(struct kthread_work *work)
			einfo->xprt_if.glink_core_if_ptr->rx_cmd_tx_done(
								&einfo->xprt_if,
								cmd.param1,
								cmd.param2);
								cmd.param2,
								false);
			break;
		case RX_INTENT_REQ_CMD:
			einfo->xprt_if.glink_core_if_ptr->
@@ -835,6 +836,13 @@ static void rx_worker(struct kthread_work *work)
								cmd.param1,
								cmd.param2);
			break;
		case RX_DONE_W_REUSE_CMD:
			einfo->xprt_if.glink_core_if_ptr->rx_cmd_tx_done(
								&einfo->xprt_if,
								cmd.param1,
								cmd.param2,
								true);
			break;
		default:
			pr_err("Unrecognized command: %d\n", cmd.id);
			break;
@@ -1140,6 +1148,7 @@ static int ssr(struct glink_transport_if *if_ptr)

/**
 * allocate_rx_intent() - allocate/reserve space for RX Intent
 * @if_ptr:	The transport the intent is associated with.
 * @size:	size of intent.
 * @intent:	Pointer to the intent structure.
 *
@@ -1151,7 +1160,8 @@ static int ssr(struct glink_transport_if *if_ptr)
 *
 * Return: 0 on success or standard Linux error code.
 */
static int allocate_rx_intent(size_t size, struct glink_core_rx_intent *intent)
static int allocate_rx_intent(struct glink_transport_if *if_ptr, size_t size,
			      struct glink_core_rx_intent *intent)
{
	void *t;

@@ -1168,11 +1178,13 @@ static int allocate_rx_intent(size_t size, struct glink_core_rx_intent *intent)

/**
 * deallocate_rx_intent() - Deallocate space created for RX Intent
 * @if_ptr:	The transport the intent is associated with.
 * @intent:	Pointer to the intent structure.
 *
 * Return: 0 on success or standard Linux error code.
 */
static int deallocate_rx_intent(struct glink_core_rx_intent *intent)
static int deallocate_rx_intent(struct glink_transport_if *if_ptr,
				struct glink_core_rx_intent *intent)
{
	if (!intent || !intent->data)
		return -EINVAL;
@@ -1241,9 +1253,10 @@ static int tx_cmd_local_rx_intent(struct glink_transport_if *if_ptr,
 * @if_ptr:	The transport to transmit on.
 * @lcid:	The local channel id to encode.
 * @liid:	The local intent id to encode.
 * @reuse:	Reuse the consumed intent.
 */
static void tx_cmd_local_rx_done(struct glink_transport_if *if_ptr,
				 uint32_t lcid, uint32_t liid)
				 uint32_t lcid, uint32_t liid, bool reuse)
{
	struct command {
		uint16_t id;
@@ -1265,7 +1278,7 @@ static void tx_cmd_local_rx_done(struct glink_transport_if *if_ptr,
		return;
	}

	cmd.id = RX_DONE_CMD;
	cmd.id = reuse ? RX_DONE_W_REUSE_CMD : RX_DONE_CMD;
	cmd.lcid = lcid;
	cmd.liid = liid;

Loading