All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/18] rpmsg: glink: Add glink smem based transport
@ 2017-08-16 17:18 ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

The glink protocol works uses a shared-memory(transport) for
communication between the local and remote processors. The
existing glink-rpm driver implements the basic features
of the protocol and uses msgram as the transport.

The same is extended to support smem based transport as well.
The first few patches consolidates the code, so that the
core protocol code is made common for both the types of
transport.

The next set of patches add the additional features of the
protocol required by clients using smem based transport,
particularly support for intents.

 * What is intents ?
	Intents are nothing but pre-allocated buffers that
	both the local and the remote clients allocate and
	share the details (about the buffer size and an id)
	before intending to receive data. The transmitter then
	searches for an suitable 'intent-id' based on size from
	the list that it was notified previously and sends the data
	targeting that intent buffer, which is then copied by the
	receiver in to the same intent-buffer. So this avoids memory
	allocation stalls on copy based transports.

Bjorn Andersson (7):
  rpmsg: glink: Rename glink_rpm_xx functions to qcom_glink_xx
  rpmsg: glink: Associate indirections for pipe fifo accessor's
  rpmsg: glink: Split rpm_probe to reuse the common code
  rpmsg: glink: Move the common glink protocol implementation to
    glink_native.c
  rpmsg: glink: Allow unaligned data access
  rpmsg: glink: Introduce glink smem based transport
  rpmsg: glink: Make RX FIFO peak accessor to take an offset

Sricharan R (11):
  rpmsg: glink: Fix default case while handling received commands
  rpmsg: glink: Add support for transport version negotiation
  rpmsg: glink: Fix idr_lock from mutex to spinlock
  rpmsg: glink: Add support for TX intents
  rpmsg: glink: Use the local intents when receiving data
  rpmsg: glink: Add rx done command
  rpmsg: glink: Add announce_create ops and preallocate intents
  rpmsg: glink: Receive and store the remote intent buffers
  rpmsg: glink: Use the intents passed by remote
  rpmsg: glink: Request for intents when unavailable
  rpmsg: glink: Handle remote rx done command

 drivers/rpmsg/Kconfig             |   16 +-
 drivers/rpmsg/Makefile            |    2 +
 drivers/rpmsg/qcom_glink_native.c | 1593 +++++++++++++++++++++++++++++++++++++
 drivers/rpmsg/qcom_glink_native.h |   44 +
 drivers/rpmsg/qcom_glink_rpm.c    | 1026 ++----------------------
 drivers/rpmsg/qcom_glink_smem.c   |  309 +++++++
 include/linux/rpmsg/qcom_glink.h  |   27 +
 7 files changed, 2066 insertions(+), 951 deletions(-)
 create mode 100644 drivers/rpmsg/qcom_glink_native.c
 create mode 100644 drivers/rpmsg/qcom_glink_native.h
 create mode 100644 drivers/rpmsg/qcom_glink_smem.c
 create mode 100644 include/linux/rpmsg/qcom_glink.h

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 00/18] rpmsg: glink: Add glink smem based transport
@ 2017-08-16 17:18 ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

The glink protocol works uses a shared-memory(transport) for
communication between the local and remote processors. The
existing glink-rpm driver implements the basic features
of the protocol and uses msgram as the transport.

The same is extended to support smem based transport as well.
The first few patches consolidates the code, so that the
core protocol code is made common for both the types of
transport.

The next set of patches add the additional features of the
protocol required by clients using smem based transport,
particularly support for intents.

 * What is intents ?
	Intents are nothing but pre-allocated buffers that
	both the local and the remote clients allocate and
	share the details (about the buffer size and an id)
	before intending to receive data. The transmitter then
	searches for an suitable 'intent-id' based on size from
	the list that it was notified previously and sends the data
	targeting that intent buffer, which is then copied by the
	receiver in to the same intent-buffer. So this avoids memory
	allocation stalls on copy based transports.

Bjorn Andersson (7):
  rpmsg: glink: Rename glink_rpm_xx functions to qcom_glink_xx
  rpmsg: glink: Associate indirections for pipe fifo accessor's
  rpmsg: glink: Split rpm_probe to reuse the common code
  rpmsg: glink: Move the common glink protocol implementation to
    glink_native.c
  rpmsg: glink: Allow unaligned data access
  rpmsg: glink: Introduce glink smem based transport
  rpmsg: glink: Make RX FIFO peak accessor to take an offset

Sricharan R (11):
  rpmsg: glink: Fix default case while handling received commands
  rpmsg: glink: Add support for transport version negotiation
  rpmsg: glink: Fix idr_lock from mutex to spinlock
  rpmsg: glink: Add support for TX intents
  rpmsg: glink: Use the local intents when receiving data
  rpmsg: glink: Add rx done command
  rpmsg: glink: Add announce_create ops and preallocate intents
  rpmsg: glink: Receive and store the remote intent buffers
  rpmsg: glink: Use the intents passed by remote
  rpmsg: glink: Request for intents when unavailable
  rpmsg: glink: Handle remote rx done command

 drivers/rpmsg/Kconfig             |   16 +-
 drivers/rpmsg/Makefile            |    2 +
 drivers/rpmsg/qcom_glink_native.c | 1593 +++++++++++++++++++++++++++++++++++++
 drivers/rpmsg/qcom_glink_native.h |   44 +
 drivers/rpmsg/qcom_glink_rpm.c    | 1026 ++----------------------
 drivers/rpmsg/qcom_glink_smem.c   |  309 +++++++
 include/linux/rpmsg/qcom_glink.h  |   27 +
 7 files changed, 2066 insertions(+), 951 deletions(-)
 create mode 100644 drivers/rpmsg/qcom_glink_native.c
 create mode 100644 drivers/rpmsg/qcom_glink_native.h
 create mode 100644 drivers/rpmsg/qcom_glink_smem.c
 create mode 100644 include/linux/rpmsg/qcom_glink.h

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 01/18] rpmsg: glink: Rename glink_rpm_xx functions to qcom_glink_xx
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:18   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

From: Bjorn Andersson <bjorn.andersson@linaro.org>

Renaming the glink_rpm_xx functions and structs to qcom_glink_xx
equivalents helps to reuse the core glink protocol while adding
support for smem based glink transport in the later patches.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_rpm.c | 248 +++++++++++++++++++++--------------------
 1 file changed, 128 insertions(+), 120 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 3559a3e..56a0a66 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -101,7 +101,7 @@ struct glink_defer_cmd {
  * @lcids:	idr of all channels with a known local channel id
  * @rcids:	idr of all channels with a known remote channel id
  */
-struct glink_rpm {
+struct qcom_glink {
 	struct device *dev;
 
 	struct mbox_client mbox_client;
@@ -134,7 +134,7 @@ enum {
  * struct glink_channel - internal representation of a channel
  * @rpdev:	rpdev reference, only used for primary endpoints
  * @ept:	rpmsg endpoint this channel is associated with
- * @glink:	glink_rpm context handle
+ * @glink:	qcom_glink context handle
  * @refcount:	refcount for the channel object
  * @recv_lock:	guard for @ept.cb
  * @name:	unique channel name/identifier
@@ -150,7 +150,7 @@ struct glink_channel {
 	struct rpmsg_endpoint ept;
 
 	struct rpmsg_device *rpdev;
-	struct glink_rpm *glink;
+	struct qcom_glink *glink;
 
 	struct kref refcount;
 
@@ -184,8 +184,8 @@ struct glink_channel {
 
 #define GLINK_FEATURE_INTENTLESS	BIT(1)
 
-static struct glink_channel *glink_rpm_alloc_channel(struct glink_rpm *glink,
-						     const char *name)
+static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
+						      const char *name)
 {
 	struct glink_channel *channel;
 
@@ -206,7 +206,7 @@ static struct glink_channel *glink_rpm_alloc_channel(struct glink_rpm *glink,
 	return channel;
 }
 
-static void glink_rpm_channel_release(struct kref *ref)
+static void qcom_glink_channel_release(struct kref *ref)
 {
 	struct glink_channel *channel = container_of(ref, struct glink_channel,
 						     refcount);
@@ -215,7 +215,7 @@ static void glink_rpm_channel_release(struct kref *ref)
 	kfree(channel);
 }
 
-static size_t glink_rpm_rx_avail(struct glink_rpm *glink)
+static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
 {
 	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
 	unsigned int head;
@@ -230,8 +230,8 @@ static size_t glink_rpm_rx_avail(struct glink_rpm *glink)
 		return head - tail;
 }
 
-static void glink_rpm_rx_peak(struct glink_rpm *glink,
-			      void *data, size_t count)
+static void qcom_glink_rx_peak(struct qcom_glink *glink,
+			       void *data, size_t count)
 {
 	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
 	unsigned int tail;
@@ -251,8 +251,8 @@ static void glink_rpm_rx_peak(struct glink_rpm *glink,
 	}
 }
 
-static void glink_rpm_rx_advance(struct glink_rpm *glink,
-				 size_t count)
+static void qcom_glink_rx_advance(struct qcom_glink *glink,
+				  size_t count)
 {
 	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
 	unsigned int tail;
@@ -266,7 +266,7 @@ static void glink_rpm_rx_advance(struct glink_rpm *glink,
 	writel(tail, pipe->tail);
 }
 
-static size_t glink_rpm_tx_avail(struct glink_rpm *glink)
+static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
 {
 	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
 	unsigned int head;
@@ -281,9 +281,9 @@ static size_t glink_rpm_tx_avail(struct glink_rpm *glink)
 		return tail - head;
 }
 
-static unsigned int glink_rpm_tx_write(struct glink_rpm *glink,
-				       unsigned int head,
-				       const void *data, size_t count)
+static unsigned int qcom_glink_tx_write(struct qcom_glink *glink,
+					unsigned int head,
+					const void *data, size_t count)
 {
 	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
 	size_t len;
@@ -306,8 +306,8 @@ static unsigned int glink_rpm_tx_write(struct glink_rpm *glink,
 	return head;
 }
 
-static int glink_rpm_tx(struct glink_rpm *glink,
-			const void *hdr, size_t hlen,
+static int qcom_glink_tx(struct qcom_glink *glink,
+			 const void *hdr, size_t hlen,
 			const void *data, size_t dlen, bool wait)
 {
 	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
@@ -326,7 +326,7 @@ static int glink_rpm_tx(struct glink_rpm *glink,
 	if (ret)
 		return ret;
 
-	while (glink_rpm_tx_avail(glink) < tlen) {
+	while (qcom_glink_tx_avail(glink) < tlen) {
 		if (!wait) {
 			ret = -ENOMEM;
 			goto out;
@@ -336,8 +336,8 @@ static int glink_rpm_tx(struct glink_rpm *glink,
 	}
 
 	head = readl(pipe->head);
-	head = glink_rpm_tx_write(glink, head, hdr, hlen);
-	head = glink_rpm_tx_write(glink, head, data, dlen);
+	head = qcom_glink_tx_write(glink, head, hdr, hlen);
+	head = qcom_glink_tx_write(glink, head, data, dlen);
 	writel(head, pipe->head);
 
 	mbox_send_message(glink->mbox_chan, NULL);
@@ -349,7 +349,7 @@ static int glink_rpm_tx(struct glink_rpm *glink,
 	return ret;
 }
 
-static int glink_rpm_send_version(struct glink_rpm *glink)
+static int qcom_glink_send_version(struct qcom_glink *glink)
 {
 	struct glink_msg msg;
 
@@ -357,10 +357,10 @@ static int glink_rpm_send_version(struct glink_rpm *glink)
 	msg.param1 = cpu_to_le16(1);
 	msg.param2 = cpu_to_le32(GLINK_FEATURE_INTENTLESS);
 
-	return glink_rpm_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
 
-static void glink_rpm_send_version_ack(struct glink_rpm *glink)
+static void qcom_glink_send_version_ack(struct qcom_glink *glink)
 {
 	struct glink_msg msg;
 
@@ -368,11 +368,11 @@ static void glink_rpm_send_version_ack(struct glink_rpm *glink)
 	msg.param1 = cpu_to_le16(1);
 	msg.param2 = cpu_to_le32(0);
 
-	glink_rpm_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
 
-static void glink_rpm_send_open_ack(struct glink_rpm *glink,
-					 struct glink_channel *channel)
+static void qcom_glink_send_open_ack(struct qcom_glink *glink,
+				     struct glink_channel *channel)
 {
 	struct glink_msg msg;
 
@@ -380,11 +380,11 @@ static void glink_rpm_send_open_ack(struct glink_rpm *glink,
 	msg.param1 = cpu_to_le16(channel->rcid);
 	msg.param2 = cpu_to_le32(0);
 
-	glink_rpm_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
 
 /**
- * glink_rpm_send_open_req() - send a RPM_CMD_OPEN request to the remote
+ * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
  * @glink:
  * @channel:
  *
@@ -393,8 +393,8 @@ static void glink_rpm_send_open_ack(struct glink_rpm *glink,
  *
  * Returns 0 on success, negative errno otherwise.
  */
-static int glink_rpm_send_open_req(struct glink_rpm *glink,
-					 struct glink_channel *channel)
+static int qcom_glink_send_open_req(struct qcom_glink *glink,
+				    struct glink_channel *channel)
 {
 	struct {
 		struct glink_msg msg;
@@ -420,7 +420,7 @@ static int glink_rpm_send_open_req(struct glink_rpm *glink,
 	req.msg.param2 = cpu_to_le32(name_len);
 	strcpy(req.name, channel->name);
 
-	ret = glink_rpm_tx(glink, &req, req_len, NULL, 0, true);
+	ret = qcom_glink_tx(glink, &req, req_len, NULL, 0, true);
 	if (ret)
 		goto remove_idr;
 
@@ -435,8 +435,8 @@ static int glink_rpm_send_open_req(struct glink_rpm *glink,
 	return ret;
 }
 
-static void glink_rpm_send_close_req(struct glink_rpm *glink,
-					  struct glink_channel *channel)
+static void qcom_glink_send_close_req(struct qcom_glink *glink,
+				      struct glink_channel *channel)
 {
 	struct glink_msg req;
 
@@ -444,10 +444,11 @@ static void glink_rpm_send_close_req(struct glink_rpm *glink,
 	req.param1 = cpu_to_le16(channel->lcid);
 	req.param2 = 0;
 
-	glink_rpm_tx(glink, &req, sizeof(req), NULL, 0, true);
+	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
 }
 
-static void glink_rpm_send_close_ack(struct glink_rpm *glink, unsigned int rcid)
+static void qcom_glink_send_close_ack(struct qcom_glink *glink,
+				      unsigned int rcid)
 {
 	struct glink_msg req;
 
@@ -455,16 +456,16 @@ static void glink_rpm_send_close_ack(struct glink_rpm *glink, unsigned int rcid)
 	req.param1 = cpu_to_le16(rcid);
 	req.param2 = 0;
 
-	glink_rpm_tx(glink, &req, sizeof(req), NULL, 0, true);
+	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
 }
 
-static int glink_rpm_rx_defer(struct glink_rpm *glink, size_t extra)
+static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 {
 	struct glink_defer_cmd *dcmd;
 
 	extra = ALIGN(extra, 8);
 
-	if (glink_rpm_rx_avail(glink) < sizeof(struct glink_msg) + extra) {
+	if (qcom_glink_rx_avail(glink) < sizeof(struct glink_msg) + extra) {
 		dev_dbg(glink->dev, "Insufficient data in rx fifo");
 		return -ENXIO;
 	}
@@ -475,19 +476,19 @@ static int glink_rpm_rx_defer(struct glink_rpm *glink, size_t extra)
 
 	INIT_LIST_HEAD(&dcmd->node);
 
-	glink_rpm_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
+	qcom_glink_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
 
 	spin_lock(&glink->rx_lock);
 	list_add_tail(&dcmd->node, &glink->rx_queue);
 	spin_unlock(&glink->rx_lock);
 
 	schedule_work(&glink->rx_work);
-	glink_rpm_rx_advance(glink, sizeof(dcmd->msg) + extra);
+	qcom_glink_rx_advance(glink, sizeof(dcmd->msg) + extra);
 
 	return 0;
 }
 
-static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
+static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 {
 	struct glink_channel *channel;
 	struct {
@@ -504,7 +505,7 @@ static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
 		return -EAGAIN;
 	}
 
-	glink_rpm_rx_peak(glink, &hdr, sizeof(hdr));
+	qcom_glink_rx_peak(glink, &hdr, sizeof(hdr));
 	chunk_size = le32_to_cpu(hdr.chunk_size);
 	left_size = le32_to_cpu(hdr.left_size);
 
@@ -522,7 +523,8 @@ static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
 		dev_dbg(glink->dev, "Data on non-existing channel\n");
 
 		/* Drop the message */
-		glink_rpm_rx_advance(glink, ALIGN(sizeof(hdr) + chunk_size, 8));
+		qcom_glink_rx_advance(glink,
+				      ALIGN(sizeof(hdr) + chunk_size, 8));
 		return 0;
 	}
 
@@ -536,17 +538,18 @@ static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
 		channel->buf_offset = 0;
 	}
 
-	glink_rpm_rx_advance(glink, sizeof(hdr));
+	qcom_glink_rx_advance(glink, sizeof(hdr));
 
 	if (channel->buf_size - channel->buf_offset < chunk_size) {
 		dev_err(glink->dev, "Insufficient space in input buffer\n");
 
 		/* The packet header lied, drop payload */
-		glink_rpm_rx_advance(glink, chunk_size);
+		qcom_glink_rx_advance(glink, chunk_size);
 		return -ENOMEM;
 	}
 
-	glink_rpm_rx_peak(glink, channel->buf + channel->buf_offset, chunk_size);
+	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
+			   chunk_size);
 	channel->buf_offset += chunk_size;
 
 	/* Handle message when no fragments remain to be received */
@@ -567,12 +570,12 @@ static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
 	}
 
 	/* Each message starts at 8 byte aligned address */
-	glink_rpm_rx_advance(glink, ALIGN(chunk_size, 8));
+	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
 
 	return 0;
 }
 
-static int glink_rpm_rx_open_ack(struct glink_rpm *glink, unsigned int lcid)
+static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
 
@@ -587,9 +590,9 @@ static int glink_rpm_rx_open_ack(struct glink_rpm *glink, unsigned int lcid)
 	return 0;
 }
 
-static irqreturn_t glink_rpm_intr(int irq, void *data)
+static irqreturn_t qcom_glink_intr(int irq, void *data)
 {
-	struct glink_rpm *glink = data;
+	struct qcom_glink *glink = data;
 	struct glink_msg msg;
 	unsigned int param1;
 	unsigned int param2;
@@ -598,11 +601,11 @@ static irqreturn_t glink_rpm_intr(int irq, void *data)
 	int ret;
 
 	for (;;) {
-		avail = glink_rpm_rx_avail(glink);
+		avail = qcom_glink_rx_avail(glink);
 		if (avail < sizeof(msg))
 			break;
 
-		glink_rpm_rx_peak(glink, &msg, sizeof(msg));
+		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
 
 		cmd = le16_to_cpu(msg.cmd);
 		param1 = le16_to_cpu(msg.param1);
@@ -613,21 +616,21 @@ static irqreturn_t glink_rpm_intr(int irq, void *data)
 		case RPM_CMD_VERSION_ACK:
 		case RPM_CMD_CLOSE:
 		case RPM_CMD_CLOSE_ACK:
-			ret = glink_rpm_rx_defer(glink, 0);
+			ret = qcom_glink_rx_defer(glink, 0);
 			break;
 		case RPM_CMD_OPEN_ACK:
-			ret = glink_rpm_rx_open_ack(glink, param1);
-			glink_rpm_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			ret = qcom_glink_rx_open_ack(glink, param1);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 			break;
 		case RPM_CMD_OPEN:
-			ret = glink_rpm_rx_defer(glink, param2);
+			ret = qcom_glink_rx_defer(glink, param2);
 			break;
 		case RPM_CMD_TX_DATA:
 		case RPM_CMD_TX_DATA_CONT:
-			ret = glink_rpm_rx_data(glink, avail);
+			ret = qcom_glink_rx_data(glink, avail);
 			break;
 		case RPM_CMD_READ_NOTIF:
-			glink_rpm_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 
 			mbox_send_message(glink->mbox_chan, NULL);
 			mbox_client_txdone(glink->mbox_chan, 0);
@@ -648,17 +651,17 @@ static irqreturn_t glink_rpm_intr(int irq, void *data)
 }
 
 /* Locally initiated rpmsg_create_ept */
-static struct glink_channel *glink_rpm_create_local(struct glink_rpm *glink,
-						    const char *name)
+static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
+						     const char *name)
 {
 	struct glink_channel *channel;
 	int ret;
 
-	channel = glink_rpm_alloc_channel(glink, name);
+	channel = qcom_glink_alloc_channel(glink, name);
 	if (IS_ERR(channel))
 		return ERR_CAST(channel);
 
-	ret = glink_rpm_send_open_req(glink, channel);
+	ret = qcom_glink_send_open_req(glink, channel);
 	if (ret)
 		goto release_channel;
 
@@ -670,34 +673,34 @@ static struct glink_channel *glink_rpm_create_local(struct glink_rpm *glink,
 	if (!ret)
 		goto err_timeout;
 
-	glink_rpm_send_open_ack(glink, channel);
+	qcom_glink_send_open_ack(glink, channel);
 
 	return channel;
 
 err_timeout:
-	/* glink_rpm_send_open_req() did register the channel in lcids*/
+	/* qcom_glink_send_open_req() did register the channel in lcids*/
 	mutex_lock(&glink->idr_lock);
 	idr_remove(&glink->lcids, channel->lcid);
 	mutex_unlock(&glink->idr_lock);
 
 release_channel:
-	/* Release glink_rpm_send_open_req() reference */
-	kref_put(&channel->refcount, glink_rpm_channel_release);
-	/* Release glink_rpm_alloc_channel() reference */
-	kref_put(&channel->refcount, glink_rpm_channel_release);
+	/* Release qcom_glink_send_open_req() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+	/* Release qcom_glink_alloc_channel() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	return ERR_PTR(-ETIMEDOUT);
 }
 
 /* Remote initiated rpmsg_create_ept */
-static int glink_rpm_create_remote(struct glink_rpm *glink,
-				   struct glink_channel *channel)
+static int qcom_glink_create_remote(struct qcom_glink *glink,
+				    struct glink_channel *channel)
 {
 	int ret;
 
-	glink_rpm_send_open_ack(glink, channel);
+	qcom_glink_send_open_ack(glink, channel);
 
-	ret = glink_rpm_send_open_req(glink, channel);
+	ret = qcom_glink_send_open_req(glink, channel);
 	if (ret)
 		goto close_link;
 
@@ -714,21 +717,23 @@ static int glink_rpm_create_remote(struct glink_rpm *glink,
 	 * Send a close request to "undo" our open-ack. The close-ack will
 	 * release the last reference.
 	 */
-	glink_rpm_send_close_req(glink, channel);
+	qcom_glink_send_close_req(glink, channel);
 
-	/* Release glink_rpm_send_open_req() reference */
-	kref_put(&channel->refcount, glink_rpm_channel_release);
+	/* Release qcom_glink_send_open_req() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	return ret;
 }
 
-static struct rpmsg_endpoint *glink_rpm_create_ept(struct rpmsg_device *rpdev,
-						  rpmsg_rx_cb_t cb, void *priv,
-						  struct rpmsg_channel_info chinfo)
+static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
+						    rpmsg_rx_cb_t cb,
+						    void *priv,
+						    struct rpmsg_channel_info
+						    chinfo)
 {
 	struct glink_channel *parent = to_glink_channel(rpdev->ept);
 	struct glink_channel *channel;
-	struct glink_rpm *glink = parent->glink;
+	struct qcom_glink *glink = parent->glink;
 	struct rpmsg_endpoint *ept;
 	const char *name = chinfo.name;
 	int cid;
@@ -740,11 +745,11 @@ static struct rpmsg_endpoint *glink_rpm_create_ept(struct rpmsg_device *rpdev,
 	}
 
 	if (!channel) {
-		channel = glink_rpm_create_local(glink, name);
+		channel = qcom_glink_create_local(glink, name);
 		if (IS_ERR(channel))
 			return NULL;
 	} else {
-		ret = glink_rpm_create_remote(glink, channel);
+		ret = qcom_glink_create_remote(glink, channel);
 		if (ret)
 			return NULL;
 	}
@@ -758,10 +763,10 @@ static struct rpmsg_endpoint *glink_rpm_create_ept(struct rpmsg_device *rpdev,
 	return ept;
 }
 
-static void glink_rpm_destroy_ept(struct rpmsg_endpoint *ept)
+static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
 {
 	struct glink_channel *channel = to_glink_channel(ept);
-	struct glink_rpm *glink = channel->glink;
+	struct qcom_glink *glink = channel->glink;
 	unsigned long flags;
 
 	spin_lock_irqsave(&channel->recv_lock, flags);
@@ -771,13 +776,13 @@ static void glink_rpm_destroy_ept(struct rpmsg_endpoint *ept)
 	/* Decouple the potential rpdev from the channel */
 	channel->rpdev = NULL;
 
-	glink_rpm_send_close_req(glink, channel);
+	qcom_glink_send_close_req(glink, channel);
 }
 
-static int __glink_rpm_send(struct glink_channel *channel,
+static int __qcom_glink_send(struct glink_channel *channel,
 			     void *data, int len, bool wait)
 {
-	struct glink_rpm *glink = channel->glink;
+	struct qcom_glink *glink = channel->glink;
 	struct {
 		struct glink_msg msg;
 		__le32 chunk_size;
@@ -793,27 +798,27 @@ static int __glink_rpm_send(struct glink_channel *channel,
 	req.chunk_size = cpu_to_le32(len);
 	req.left_size = cpu_to_le32(0);
 
-	return glink_rpm_tx(glink, &req, sizeof(req), data, len, wait);
+	return qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
 }
 
-static int glink_rpm_send(struct rpmsg_endpoint *ept, void *data, int len)
+static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len)
 {
 	struct glink_channel *channel = to_glink_channel(ept);
 
-	return __glink_rpm_send(channel, data, len, true);
+	return __qcom_glink_send(channel, data, len, true);
 }
 
-static int glink_rpm_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+static int qcom_glink_trysend(struct rpmsg_endpoint *ept, void *data, int len)
 {
 	struct glink_channel *channel = to_glink_channel(ept);
 
-	return __glink_rpm_send(channel, data, len, false);
+	return __qcom_glink_send(channel, data, len, false);
 }
 
 /*
  * Finds the device_node for the glink child interested in this channel.
  */
-static struct device_node *glink_rpm_match_channel(struct device_node *node,
+static struct device_node *qcom_glink_match_channel(struct device_node *node,
 						    const char *channel)
 {
 	struct device_node *child;
@@ -835,16 +840,16 @@ static struct device_node *glink_rpm_match_channel(struct device_node *node,
 }
 
 static const struct rpmsg_device_ops glink_device_ops = {
-	.create_ept = glink_rpm_create_ept,
+	.create_ept = qcom_glink_create_ept,
 };
 
 static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
-	.destroy_ept = glink_rpm_destroy_ept,
-	.send = glink_rpm_send,
-	.trysend = glink_rpm_trysend,
+	.destroy_ept = qcom_glink_destroy_ept,
+	.send = qcom_glink_send,
+	.trysend = qcom_glink_trysend,
 };
 
-static void glink_rpm_rpdev_release(struct device *dev)
+static void qcom_glink_rpdev_release(struct device *dev)
 {
 	struct rpmsg_device *rpdev = to_rpmsg_device(dev);
 	struct glink_channel *channel = to_glink_channel(rpdev->ept);
@@ -853,14 +858,15 @@ static void glink_rpm_rpdev_release(struct device *dev)
 	kfree(rpdev);
 }
 
-static int glink_rpm_rx_open(struct glink_rpm *glink, unsigned int rcid,
-			     char *name)
+static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
+			      char *name)
 {
 	struct glink_channel *channel;
 	struct rpmsg_device *rpdev;
 	bool create_device = false;
 	int lcid;
 	int ret;
+	struct device_node *node;
 
 	idr_for_each_entry(&glink->lcids, channel, lcid) {
 		if (!strcmp(channel->name, name))
@@ -868,7 +874,7 @@ static int glink_rpm_rx_open(struct glink_rpm *glink, unsigned int rcid,
 	}
 
 	if (!channel) {
-		channel = glink_rpm_alloc_channel(glink, name);
+		channel = qcom_glink_alloc_channel(glink, name);
 		if (IS_ERR(channel))
 			return PTR_ERR(channel);
 
@@ -901,9 +907,10 @@ static int glink_rpm_rx_open(struct glink_rpm *glink, unsigned int rcid,
 		rpdev->dst = RPMSG_ADDR_ANY;
 		rpdev->ops = &glink_device_ops;
 
-		rpdev->dev.of_node = glink_rpm_match_channel(glink->dev->of_node, name);
+		node = qcom_glink_match_channel(glink->dev->of_node, name);
+		rpdev->dev.of_node = node;
 		rpdev->dev.parent = glink->dev;
-		rpdev->dev.release = glink_rpm_rpdev_release;
+		rpdev->dev.release = qcom_glink_rpdev_release;
 
 		ret = rpmsg_register_device(rpdev);
 		if (ret)
@@ -924,12 +931,12 @@ static int glink_rpm_rx_open(struct glink_rpm *glink, unsigned int rcid,
 free_channel:
 	/* Release the reference, iff we took it */
 	if (create_device)
-		kref_put(&channel->refcount, glink_rpm_channel_release);
+		kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	return ret;
 }
 
-static void glink_rpm_rx_close(struct glink_rpm *glink, unsigned int rcid)
+static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 {
 	struct rpmsg_channel_info chinfo;
 	struct glink_channel *channel;
@@ -946,17 +953,17 @@ static void glink_rpm_rx_close(struct glink_rpm *glink, unsigned int rcid)
 		rpmsg_unregister_device(glink->dev, &chinfo);
 	}
 
-	glink_rpm_send_close_ack(glink, channel->rcid);
+	qcom_glink_send_close_ack(glink, channel->rcid);
 
 	mutex_lock(&glink->idr_lock);
 	idr_remove(&glink->rcids, channel->rcid);
 	channel->rcid = 0;
 	mutex_unlock(&glink->idr_lock);
 
-	kref_put(&channel->refcount, glink_rpm_channel_release);
+	kref_put(&channel->refcount, qcom_glink_channel_release);
 }
 
-static void glink_rpm_rx_close_ack(struct glink_rpm *glink, unsigned int lcid)
+static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
 
@@ -969,12 +976,13 @@ static void glink_rpm_rx_close_ack(struct glink_rpm *glink, unsigned int lcid)
 	channel->lcid = 0;
 	mutex_unlock(&glink->idr_lock);
 
-	kref_put(&channel->refcount, glink_rpm_channel_release);
+	kref_put(&channel->refcount, qcom_glink_channel_release);
 }
 
-static void glink_rpm_work(struct work_struct *work)
+static void qcom_glink_work(struct work_struct *work)
 {
-	struct glink_rpm *glink = container_of(work, struct glink_rpm, rx_work);
+	struct qcom_glink *glink = container_of(work, struct qcom_glink,
+						rx_work);
 	struct glink_defer_cmd *dcmd;
 	struct glink_msg *msg;
 	unsigned long flags;
@@ -999,18 +1007,18 @@ static void glink_rpm_work(struct work_struct *work)
 
 		switch (cmd) {
 		case RPM_CMD_VERSION:
-			glink_rpm_send_version_ack(glink);
+			qcom_glink_send_version_ack(glink);
 			break;
 		case RPM_CMD_VERSION_ACK:
 			break;
 		case RPM_CMD_OPEN:
-			glink_rpm_rx_open(glink, param1, msg->data);
+			qcom_glink_rx_open(glink, param1, msg->data);
 			break;
 		case RPM_CMD_CLOSE:
-			glink_rpm_rx_close(glink, param1);
+			qcom_glink_rx_close(glink, param1);
 			break;
 		case RPM_CMD_CLOSE_ACK:
-			glink_rpm_rx_close_ack(glink, param1);
+			qcom_glink_rx_close_ack(glink, param1);
 			break;
 		default:
 			WARN(1, "Unknown defer object %d\n", cmd);
@@ -1098,7 +1106,7 @@ static int glink_rpm_parse_toc(struct device *dev,
 
 static int glink_rpm_probe(struct platform_device *pdev)
 {
-	struct glink_rpm *glink;
+	struct qcom_glink *glink;
 	struct device_node *np;
 	void __iomem *msg_ram;
 	size_t msg_ram_size;
@@ -1116,7 +1124,7 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
 	INIT_LIST_HEAD(&glink->rx_queue);
-	INIT_WORK(&glink->rx_work, glink_rpm_work);
+	INIT_WORK(&glink->rx_work, qcom_glink_work);
 
 	mutex_init(&glink->idr_lock);
 	idr_init(&glink->lcids);
@@ -1151,7 +1159,7 @@ static int glink_rpm_probe(struct platform_device *pdev)
 
 	irq = platform_get_irq(pdev, 0);
 	ret = devm_request_irq(dev, irq,
-			       glink_rpm_intr,
+			       qcom_glink_intr,
 			       IRQF_NO_SUSPEND | IRQF_SHARED,
 			       "glink-rpm", glink);
 	if (ret) {
@@ -1161,7 +1169,7 @@ static int glink_rpm_probe(struct platform_device *pdev)
 
 	glink->irq = irq;
 
-	ret = glink_rpm_send_version(glink);
+	ret = qcom_glink_send_version(glink);
 	if (ret)
 		return ret;
 
@@ -1179,7 +1187,7 @@ static int glink_rpm_remove_device(struct device *dev, void *data)
 
 static int glink_rpm_remove(struct platform_device *pdev)
 {
-	struct glink_rpm *glink = platform_get_drvdata(pdev);
+	struct qcom_glink *glink = platform_get_drvdata(pdev);
 	struct glink_channel *channel;
 	int cid;
 	int ret;
@@ -1193,7 +1201,7 @@ static int glink_rpm_remove(struct platform_device *pdev)
 
 	/* Release any defunct local channels, waiting for close-ack */
 	idr_for_each_entry(&glink->lcids, channel, cid)
-		kref_put(&channel->refcount, glink_rpm_channel_release);
+		kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	idr_destroy(&glink->lcids);
 	idr_destroy(&glink->rcids);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 01/18] rpmsg: glink: Rename glink_rpm_xx functions to qcom_glink_xx
@ 2017-08-16 17:18   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: Bjorn Andersson <bjorn.andersson@linaro.org>

Renaming the glink_rpm_xx functions and structs to qcom_glink_xx
equivalents helps to reuse the core glink protocol while adding
support for smem based glink transport in the later patches.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_rpm.c | 248 +++++++++++++++++++++--------------------
 1 file changed, 128 insertions(+), 120 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 3559a3e..56a0a66 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -101,7 +101,7 @@ struct glink_defer_cmd {
  * @lcids:	idr of all channels with a known local channel id
  * @rcids:	idr of all channels with a known remote channel id
  */
-struct glink_rpm {
+struct qcom_glink {
 	struct device *dev;
 
 	struct mbox_client mbox_client;
@@ -134,7 +134,7 @@ enum {
  * struct glink_channel - internal representation of a channel
  * @rpdev:	rpdev reference, only used for primary endpoints
  * @ept:	rpmsg endpoint this channel is associated with
- * @glink:	glink_rpm context handle
+ * @glink:	qcom_glink context handle
  * @refcount:	refcount for the channel object
  * @recv_lock:	guard for @ept.cb
  * @name:	unique channel name/identifier
@@ -150,7 +150,7 @@ struct glink_channel {
 	struct rpmsg_endpoint ept;
 
 	struct rpmsg_device *rpdev;
-	struct glink_rpm *glink;
+	struct qcom_glink *glink;
 
 	struct kref refcount;
 
@@ -184,8 +184,8 @@ struct glink_channel {
 
 #define GLINK_FEATURE_INTENTLESS	BIT(1)
 
-static struct glink_channel *glink_rpm_alloc_channel(struct glink_rpm *glink,
-						     const char *name)
+static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
+						      const char *name)
 {
 	struct glink_channel *channel;
 
@@ -206,7 +206,7 @@ static struct glink_channel *glink_rpm_alloc_channel(struct glink_rpm *glink,
 	return channel;
 }
 
-static void glink_rpm_channel_release(struct kref *ref)
+static void qcom_glink_channel_release(struct kref *ref)
 {
 	struct glink_channel *channel = container_of(ref, struct glink_channel,
 						     refcount);
@@ -215,7 +215,7 @@ static void glink_rpm_channel_release(struct kref *ref)
 	kfree(channel);
 }
 
-static size_t glink_rpm_rx_avail(struct glink_rpm *glink)
+static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
 {
 	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
 	unsigned int head;
@@ -230,8 +230,8 @@ static size_t glink_rpm_rx_avail(struct glink_rpm *glink)
 		return head - tail;
 }
 
-static void glink_rpm_rx_peak(struct glink_rpm *glink,
-			      void *data, size_t count)
+static void qcom_glink_rx_peak(struct qcom_glink *glink,
+			       void *data, size_t count)
 {
 	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
 	unsigned int tail;
@@ -251,8 +251,8 @@ static void glink_rpm_rx_peak(struct glink_rpm *glink,
 	}
 }
 
-static void glink_rpm_rx_advance(struct glink_rpm *glink,
-				 size_t count)
+static void qcom_glink_rx_advance(struct qcom_glink *glink,
+				  size_t count)
 {
 	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
 	unsigned int tail;
@@ -266,7 +266,7 @@ static void glink_rpm_rx_advance(struct glink_rpm *glink,
 	writel(tail, pipe->tail);
 }
 
-static size_t glink_rpm_tx_avail(struct glink_rpm *glink)
+static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
 {
 	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
 	unsigned int head;
@@ -281,9 +281,9 @@ static size_t glink_rpm_tx_avail(struct glink_rpm *glink)
 		return tail - head;
 }
 
-static unsigned int glink_rpm_tx_write(struct glink_rpm *glink,
-				       unsigned int head,
-				       const void *data, size_t count)
+static unsigned int qcom_glink_tx_write(struct qcom_glink *glink,
+					unsigned int head,
+					const void *data, size_t count)
 {
 	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
 	size_t len;
@@ -306,8 +306,8 @@ static unsigned int glink_rpm_tx_write(struct glink_rpm *glink,
 	return head;
 }
 
-static int glink_rpm_tx(struct glink_rpm *glink,
-			const void *hdr, size_t hlen,
+static int qcom_glink_tx(struct qcom_glink *glink,
+			 const void *hdr, size_t hlen,
 			const void *data, size_t dlen, bool wait)
 {
 	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
@@ -326,7 +326,7 @@ static int glink_rpm_tx(struct glink_rpm *glink,
 	if (ret)
 		return ret;
 
-	while (glink_rpm_tx_avail(glink) < tlen) {
+	while (qcom_glink_tx_avail(glink) < tlen) {
 		if (!wait) {
 			ret = -ENOMEM;
 			goto out;
@@ -336,8 +336,8 @@ static int glink_rpm_tx(struct glink_rpm *glink,
 	}
 
 	head = readl(pipe->head);
-	head = glink_rpm_tx_write(glink, head, hdr, hlen);
-	head = glink_rpm_tx_write(glink, head, data, dlen);
+	head = qcom_glink_tx_write(glink, head, hdr, hlen);
+	head = qcom_glink_tx_write(glink, head, data, dlen);
 	writel(head, pipe->head);
 
 	mbox_send_message(glink->mbox_chan, NULL);
@@ -349,7 +349,7 @@ static int glink_rpm_tx(struct glink_rpm *glink,
 	return ret;
 }
 
-static int glink_rpm_send_version(struct glink_rpm *glink)
+static int qcom_glink_send_version(struct qcom_glink *glink)
 {
 	struct glink_msg msg;
 
@@ -357,10 +357,10 @@ static int glink_rpm_send_version(struct glink_rpm *glink)
 	msg.param1 = cpu_to_le16(1);
 	msg.param2 = cpu_to_le32(GLINK_FEATURE_INTENTLESS);
 
-	return glink_rpm_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
 
-static void glink_rpm_send_version_ack(struct glink_rpm *glink)
+static void qcom_glink_send_version_ack(struct qcom_glink *glink)
 {
 	struct glink_msg msg;
 
@@ -368,11 +368,11 @@ static void glink_rpm_send_version_ack(struct glink_rpm *glink)
 	msg.param1 = cpu_to_le16(1);
 	msg.param2 = cpu_to_le32(0);
 
-	glink_rpm_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
 
-static void glink_rpm_send_open_ack(struct glink_rpm *glink,
-					 struct glink_channel *channel)
+static void qcom_glink_send_open_ack(struct qcom_glink *glink,
+				     struct glink_channel *channel)
 {
 	struct glink_msg msg;
 
@@ -380,11 +380,11 @@ static void glink_rpm_send_open_ack(struct glink_rpm *glink,
 	msg.param1 = cpu_to_le16(channel->rcid);
 	msg.param2 = cpu_to_le32(0);
 
-	glink_rpm_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
 
 /**
- * glink_rpm_send_open_req() - send a RPM_CMD_OPEN request to the remote
+ * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
  * @glink:
  * @channel:
  *
@@ -393,8 +393,8 @@ static void glink_rpm_send_open_ack(struct glink_rpm *glink,
  *
  * Returns 0 on success, negative errno otherwise.
  */
-static int glink_rpm_send_open_req(struct glink_rpm *glink,
-					 struct glink_channel *channel)
+static int qcom_glink_send_open_req(struct qcom_glink *glink,
+				    struct glink_channel *channel)
 {
 	struct {
 		struct glink_msg msg;
@@ -420,7 +420,7 @@ static int glink_rpm_send_open_req(struct glink_rpm *glink,
 	req.msg.param2 = cpu_to_le32(name_len);
 	strcpy(req.name, channel->name);
 
-	ret = glink_rpm_tx(glink, &req, req_len, NULL, 0, true);
+	ret = qcom_glink_tx(glink, &req, req_len, NULL, 0, true);
 	if (ret)
 		goto remove_idr;
 
@@ -435,8 +435,8 @@ static int glink_rpm_send_open_req(struct glink_rpm *glink,
 	return ret;
 }
 
-static void glink_rpm_send_close_req(struct glink_rpm *glink,
-					  struct glink_channel *channel)
+static void qcom_glink_send_close_req(struct qcom_glink *glink,
+				      struct glink_channel *channel)
 {
 	struct glink_msg req;
 
@@ -444,10 +444,11 @@ static void glink_rpm_send_close_req(struct glink_rpm *glink,
 	req.param1 = cpu_to_le16(channel->lcid);
 	req.param2 = 0;
 
-	glink_rpm_tx(glink, &req, sizeof(req), NULL, 0, true);
+	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
 }
 
-static void glink_rpm_send_close_ack(struct glink_rpm *glink, unsigned int rcid)
+static void qcom_glink_send_close_ack(struct qcom_glink *glink,
+				      unsigned int rcid)
 {
 	struct glink_msg req;
 
@@ -455,16 +456,16 @@ static void glink_rpm_send_close_ack(struct glink_rpm *glink, unsigned int rcid)
 	req.param1 = cpu_to_le16(rcid);
 	req.param2 = 0;
 
-	glink_rpm_tx(glink, &req, sizeof(req), NULL, 0, true);
+	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
 }
 
-static int glink_rpm_rx_defer(struct glink_rpm *glink, size_t extra)
+static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 {
 	struct glink_defer_cmd *dcmd;
 
 	extra = ALIGN(extra, 8);
 
-	if (glink_rpm_rx_avail(glink) < sizeof(struct glink_msg) + extra) {
+	if (qcom_glink_rx_avail(glink) < sizeof(struct glink_msg) + extra) {
 		dev_dbg(glink->dev, "Insufficient data in rx fifo");
 		return -ENXIO;
 	}
@@ -475,19 +476,19 @@ static int glink_rpm_rx_defer(struct glink_rpm *glink, size_t extra)
 
 	INIT_LIST_HEAD(&dcmd->node);
 
-	glink_rpm_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
+	qcom_glink_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
 
 	spin_lock(&glink->rx_lock);
 	list_add_tail(&dcmd->node, &glink->rx_queue);
 	spin_unlock(&glink->rx_lock);
 
 	schedule_work(&glink->rx_work);
-	glink_rpm_rx_advance(glink, sizeof(dcmd->msg) + extra);
+	qcom_glink_rx_advance(glink, sizeof(dcmd->msg) + extra);
 
 	return 0;
 }
 
-static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
+static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 {
 	struct glink_channel *channel;
 	struct {
@@ -504,7 +505,7 @@ static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
 		return -EAGAIN;
 	}
 
-	glink_rpm_rx_peak(glink, &hdr, sizeof(hdr));
+	qcom_glink_rx_peak(glink, &hdr, sizeof(hdr));
 	chunk_size = le32_to_cpu(hdr.chunk_size);
 	left_size = le32_to_cpu(hdr.left_size);
 
@@ -522,7 +523,8 @@ static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
 		dev_dbg(glink->dev, "Data on non-existing channel\n");
 
 		/* Drop the message */
-		glink_rpm_rx_advance(glink, ALIGN(sizeof(hdr) + chunk_size, 8));
+		qcom_glink_rx_advance(glink,
+				      ALIGN(sizeof(hdr) + chunk_size, 8));
 		return 0;
 	}
 
@@ -536,17 +538,18 @@ static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
 		channel->buf_offset = 0;
 	}
 
-	glink_rpm_rx_advance(glink, sizeof(hdr));
+	qcom_glink_rx_advance(glink, sizeof(hdr));
 
 	if (channel->buf_size - channel->buf_offset < chunk_size) {
 		dev_err(glink->dev, "Insufficient space in input buffer\n");
 
 		/* The packet header lied, drop payload */
-		glink_rpm_rx_advance(glink, chunk_size);
+		qcom_glink_rx_advance(glink, chunk_size);
 		return -ENOMEM;
 	}
 
-	glink_rpm_rx_peak(glink, channel->buf + channel->buf_offset, chunk_size);
+	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
+			   chunk_size);
 	channel->buf_offset += chunk_size;
 
 	/* Handle message when no fragments remain to be received */
@@ -567,12 +570,12 @@ static int glink_rpm_rx_data(struct glink_rpm *glink, size_t avail)
 	}
 
 	/* Each message starts at 8 byte aligned address */
-	glink_rpm_rx_advance(glink, ALIGN(chunk_size, 8));
+	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
 
 	return 0;
 }
 
-static int glink_rpm_rx_open_ack(struct glink_rpm *glink, unsigned int lcid)
+static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
 
@@ -587,9 +590,9 @@ static int glink_rpm_rx_open_ack(struct glink_rpm *glink, unsigned int lcid)
 	return 0;
 }
 
-static irqreturn_t glink_rpm_intr(int irq, void *data)
+static irqreturn_t qcom_glink_intr(int irq, void *data)
 {
-	struct glink_rpm *glink = data;
+	struct qcom_glink *glink = data;
 	struct glink_msg msg;
 	unsigned int param1;
 	unsigned int param2;
@@ -598,11 +601,11 @@ static irqreturn_t glink_rpm_intr(int irq, void *data)
 	int ret;
 
 	for (;;) {
-		avail = glink_rpm_rx_avail(glink);
+		avail = qcom_glink_rx_avail(glink);
 		if (avail < sizeof(msg))
 			break;
 
-		glink_rpm_rx_peak(glink, &msg, sizeof(msg));
+		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
 
 		cmd = le16_to_cpu(msg.cmd);
 		param1 = le16_to_cpu(msg.param1);
@@ -613,21 +616,21 @@ static irqreturn_t glink_rpm_intr(int irq, void *data)
 		case RPM_CMD_VERSION_ACK:
 		case RPM_CMD_CLOSE:
 		case RPM_CMD_CLOSE_ACK:
-			ret = glink_rpm_rx_defer(glink, 0);
+			ret = qcom_glink_rx_defer(glink, 0);
 			break;
 		case RPM_CMD_OPEN_ACK:
-			ret = glink_rpm_rx_open_ack(glink, param1);
-			glink_rpm_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			ret = qcom_glink_rx_open_ack(glink, param1);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 			break;
 		case RPM_CMD_OPEN:
-			ret = glink_rpm_rx_defer(glink, param2);
+			ret = qcom_glink_rx_defer(glink, param2);
 			break;
 		case RPM_CMD_TX_DATA:
 		case RPM_CMD_TX_DATA_CONT:
-			ret = glink_rpm_rx_data(glink, avail);
+			ret = qcom_glink_rx_data(glink, avail);
 			break;
 		case RPM_CMD_READ_NOTIF:
-			glink_rpm_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 
 			mbox_send_message(glink->mbox_chan, NULL);
 			mbox_client_txdone(glink->mbox_chan, 0);
@@ -648,17 +651,17 @@ static irqreturn_t glink_rpm_intr(int irq, void *data)
 }
 
 /* Locally initiated rpmsg_create_ept */
-static struct glink_channel *glink_rpm_create_local(struct glink_rpm *glink,
-						    const char *name)
+static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
+						     const char *name)
 {
 	struct glink_channel *channel;
 	int ret;
 
-	channel = glink_rpm_alloc_channel(glink, name);
+	channel = qcom_glink_alloc_channel(glink, name);
 	if (IS_ERR(channel))
 		return ERR_CAST(channel);
 
-	ret = glink_rpm_send_open_req(glink, channel);
+	ret = qcom_glink_send_open_req(glink, channel);
 	if (ret)
 		goto release_channel;
 
@@ -670,34 +673,34 @@ static struct glink_channel *glink_rpm_create_local(struct glink_rpm *glink,
 	if (!ret)
 		goto err_timeout;
 
-	glink_rpm_send_open_ack(glink, channel);
+	qcom_glink_send_open_ack(glink, channel);
 
 	return channel;
 
 err_timeout:
-	/* glink_rpm_send_open_req() did register the channel in lcids*/
+	/* qcom_glink_send_open_req() did register the channel in lcids*/
 	mutex_lock(&glink->idr_lock);
 	idr_remove(&glink->lcids, channel->lcid);
 	mutex_unlock(&glink->idr_lock);
 
 release_channel:
-	/* Release glink_rpm_send_open_req() reference */
-	kref_put(&channel->refcount, glink_rpm_channel_release);
-	/* Release glink_rpm_alloc_channel() reference */
-	kref_put(&channel->refcount, glink_rpm_channel_release);
+	/* Release qcom_glink_send_open_req() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+	/* Release qcom_glink_alloc_channel() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	return ERR_PTR(-ETIMEDOUT);
 }
 
 /* Remote initiated rpmsg_create_ept */
-static int glink_rpm_create_remote(struct glink_rpm *glink,
-				   struct glink_channel *channel)
+static int qcom_glink_create_remote(struct qcom_glink *glink,
+				    struct glink_channel *channel)
 {
 	int ret;
 
-	glink_rpm_send_open_ack(glink, channel);
+	qcom_glink_send_open_ack(glink, channel);
 
-	ret = glink_rpm_send_open_req(glink, channel);
+	ret = qcom_glink_send_open_req(glink, channel);
 	if (ret)
 		goto close_link;
 
@@ -714,21 +717,23 @@ static int glink_rpm_create_remote(struct glink_rpm *glink,
 	 * Send a close request to "undo" our open-ack. The close-ack will
 	 * release the last reference.
 	 */
-	glink_rpm_send_close_req(glink, channel);
+	qcom_glink_send_close_req(glink, channel);
 
-	/* Release glink_rpm_send_open_req() reference */
-	kref_put(&channel->refcount, glink_rpm_channel_release);
+	/* Release qcom_glink_send_open_req() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	return ret;
 }
 
-static struct rpmsg_endpoint *glink_rpm_create_ept(struct rpmsg_device *rpdev,
-						  rpmsg_rx_cb_t cb, void *priv,
-						  struct rpmsg_channel_info chinfo)
+static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
+						    rpmsg_rx_cb_t cb,
+						    void *priv,
+						    struct rpmsg_channel_info
+						    chinfo)
 {
 	struct glink_channel *parent = to_glink_channel(rpdev->ept);
 	struct glink_channel *channel;
-	struct glink_rpm *glink = parent->glink;
+	struct qcom_glink *glink = parent->glink;
 	struct rpmsg_endpoint *ept;
 	const char *name = chinfo.name;
 	int cid;
@@ -740,11 +745,11 @@ static struct rpmsg_endpoint *glink_rpm_create_ept(struct rpmsg_device *rpdev,
 	}
 
 	if (!channel) {
-		channel = glink_rpm_create_local(glink, name);
+		channel = qcom_glink_create_local(glink, name);
 		if (IS_ERR(channel))
 			return NULL;
 	} else {
-		ret = glink_rpm_create_remote(glink, channel);
+		ret = qcom_glink_create_remote(glink, channel);
 		if (ret)
 			return NULL;
 	}
@@ -758,10 +763,10 @@ static struct rpmsg_endpoint *glink_rpm_create_ept(struct rpmsg_device *rpdev,
 	return ept;
 }
 
-static void glink_rpm_destroy_ept(struct rpmsg_endpoint *ept)
+static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
 {
 	struct glink_channel *channel = to_glink_channel(ept);
-	struct glink_rpm *glink = channel->glink;
+	struct qcom_glink *glink = channel->glink;
 	unsigned long flags;
 
 	spin_lock_irqsave(&channel->recv_lock, flags);
@@ -771,13 +776,13 @@ static void glink_rpm_destroy_ept(struct rpmsg_endpoint *ept)
 	/* Decouple the potential rpdev from the channel */
 	channel->rpdev = NULL;
 
-	glink_rpm_send_close_req(glink, channel);
+	qcom_glink_send_close_req(glink, channel);
 }
 
-static int __glink_rpm_send(struct glink_channel *channel,
+static int __qcom_glink_send(struct glink_channel *channel,
 			     void *data, int len, bool wait)
 {
-	struct glink_rpm *glink = channel->glink;
+	struct qcom_glink *glink = channel->glink;
 	struct {
 		struct glink_msg msg;
 		__le32 chunk_size;
@@ -793,27 +798,27 @@ static int __glink_rpm_send(struct glink_channel *channel,
 	req.chunk_size = cpu_to_le32(len);
 	req.left_size = cpu_to_le32(0);
 
-	return glink_rpm_tx(glink, &req, sizeof(req), data, len, wait);
+	return qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
 }
 
-static int glink_rpm_send(struct rpmsg_endpoint *ept, void *data, int len)
+static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len)
 {
 	struct glink_channel *channel = to_glink_channel(ept);
 
-	return __glink_rpm_send(channel, data, len, true);
+	return __qcom_glink_send(channel, data, len, true);
 }
 
-static int glink_rpm_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+static int qcom_glink_trysend(struct rpmsg_endpoint *ept, void *data, int len)
 {
 	struct glink_channel *channel = to_glink_channel(ept);
 
-	return __glink_rpm_send(channel, data, len, false);
+	return __qcom_glink_send(channel, data, len, false);
 }
 
 /*
  * Finds the device_node for the glink child interested in this channel.
  */
-static struct device_node *glink_rpm_match_channel(struct device_node *node,
+static struct device_node *qcom_glink_match_channel(struct device_node *node,
 						    const char *channel)
 {
 	struct device_node *child;
@@ -835,16 +840,16 @@ static struct device_node *glink_rpm_match_channel(struct device_node *node,
 }
 
 static const struct rpmsg_device_ops glink_device_ops = {
-	.create_ept = glink_rpm_create_ept,
+	.create_ept = qcom_glink_create_ept,
 };
 
 static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
-	.destroy_ept = glink_rpm_destroy_ept,
-	.send = glink_rpm_send,
-	.trysend = glink_rpm_trysend,
+	.destroy_ept = qcom_glink_destroy_ept,
+	.send = qcom_glink_send,
+	.trysend = qcom_glink_trysend,
 };
 
-static void glink_rpm_rpdev_release(struct device *dev)
+static void qcom_glink_rpdev_release(struct device *dev)
 {
 	struct rpmsg_device *rpdev = to_rpmsg_device(dev);
 	struct glink_channel *channel = to_glink_channel(rpdev->ept);
@@ -853,14 +858,15 @@ static void glink_rpm_rpdev_release(struct device *dev)
 	kfree(rpdev);
 }
 
-static int glink_rpm_rx_open(struct glink_rpm *glink, unsigned int rcid,
-			     char *name)
+static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
+			      char *name)
 {
 	struct glink_channel *channel;
 	struct rpmsg_device *rpdev;
 	bool create_device = false;
 	int lcid;
 	int ret;
+	struct device_node *node;
 
 	idr_for_each_entry(&glink->lcids, channel, lcid) {
 		if (!strcmp(channel->name, name))
@@ -868,7 +874,7 @@ static int glink_rpm_rx_open(struct glink_rpm *glink, unsigned int rcid,
 	}
 
 	if (!channel) {
-		channel = glink_rpm_alloc_channel(glink, name);
+		channel = qcom_glink_alloc_channel(glink, name);
 		if (IS_ERR(channel))
 			return PTR_ERR(channel);
 
@@ -901,9 +907,10 @@ static int glink_rpm_rx_open(struct glink_rpm *glink, unsigned int rcid,
 		rpdev->dst = RPMSG_ADDR_ANY;
 		rpdev->ops = &glink_device_ops;
 
-		rpdev->dev.of_node = glink_rpm_match_channel(glink->dev->of_node, name);
+		node = qcom_glink_match_channel(glink->dev->of_node, name);
+		rpdev->dev.of_node = node;
 		rpdev->dev.parent = glink->dev;
-		rpdev->dev.release = glink_rpm_rpdev_release;
+		rpdev->dev.release = qcom_glink_rpdev_release;
 
 		ret = rpmsg_register_device(rpdev);
 		if (ret)
@@ -924,12 +931,12 @@ static int glink_rpm_rx_open(struct glink_rpm *glink, unsigned int rcid,
 free_channel:
 	/* Release the reference, iff we took it */
 	if (create_device)
-		kref_put(&channel->refcount, glink_rpm_channel_release);
+		kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	return ret;
 }
 
-static void glink_rpm_rx_close(struct glink_rpm *glink, unsigned int rcid)
+static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 {
 	struct rpmsg_channel_info chinfo;
 	struct glink_channel *channel;
@@ -946,17 +953,17 @@ static void glink_rpm_rx_close(struct glink_rpm *glink, unsigned int rcid)
 		rpmsg_unregister_device(glink->dev, &chinfo);
 	}
 
-	glink_rpm_send_close_ack(glink, channel->rcid);
+	qcom_glink_send_close_ack(glink, channel->rcid);
 
 	mutex_lock(&glink->idr_lock);
 	idr_remove(&glink->rcids, channel->rcid);
 	channel->rcid = 0;
 	mutex_unlock(&glink->idr_lock);
 
-	kref_put(&channel->refcount, glink_rpm_channel_release);
+	kref_put(&channel->refcount, qcom_glink_channel_release);
 }
 
-static void glink_rpm_rx_close_ack(struct glink_rpm *glink, unsigned int lcid)
+static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
 
@@ -969,12 +976,13 @@ static void glink_rpm_rx_close_ack(struct glink_rpm *glink, unsigned int lcid)
 	channel->lcid = 0;
 	mutex_unlock(&glink->idr_lock);
 
-	kref_put(&channel->refcount, glink_rpm_channel_release);
+	kref_put(&channel->refcount, qcom_glink_channel_release);
 }
 
-static void glink_rpm_work(struct work_struct *work)
+static void qcom_glink_work(struct work_struct *work)
 {
-	struct glink_rpm *glink = container_of(work, struct glink_rpm, rx_work);
+	struct qcom_glink *glink = container_of(work, struct qcom_glink,
+						rx_work);
 	struct glink_defer_cmd *dcmd;
 	struct glink_msg *msg;
 	unsigned long flags;
@@ -999,18 +1007,18 @@ static void glink_rpm_work(struct work_struct *work)
 
 		switch (cmd) {
 		case RPM_CMD_VERSION:
-			glink_rpm_send_version_ack(glink);
+			qcom_glink_send_version_ack(glink);
 			break;
 		case RPM_CMD_VERSION_ACK:
 			break;
 		case RPM_CMD_OPEN:
-			glink_rpm_rx_open(glink, param1, msg->data);
+			qcom_glink_rx_open(glink, param1, msg->data);
 			break;
 		case RPM_CMD_CLOSE:
-			glink_rpm_rx_close(glink, param1);
+			qcom_glink_rx_close(glink, param1);
 			break;
 		case RPM_CMD_CLOSE_ACK:
-			glink_rpm_rx_close_ack(glink, param1);
+			qcom_glink_rx_close_ack(glink, param1);
 			break;
 		default:
 			WARN(1, "Unknown defer object %d\n", cmd);
@@ -1098,7 +1106,7 @@ static int glink_rpm_parse_toc(struct device *dev,
 
 static int glink_rpm_probe(struct platform_device *pdev)
 {
-	struct glink_rpm *glink;
+	struct qcom_glink *glink;
 	struct device_node *np;
 	void __iomem *msg_ram;
 	size_t msg_ram_size;
@@ -1116,7 +1124,7 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
 	INIT_LIST_HEAD(&glink->rx_queue);
-	INIT_WORK(&glink->rx_work, glink_rpm_work);
+	INIT_WORK(&glink->rx_work, qcom_glink_work);
 
 	mutex_init(&glink->idr_lock);
 	idr_init(&glink->lcids);
@@ -1151,7 +1159,7 @@ static int glink_rpm_probe(struct platform_device *pdev)
 
 	irq = platform_get_irq(pdev, 0);
 	ret = devm_request_irq(dev, irq,
-			       glink_rpm_intr,
+			       qcom_glink_intr,
 			       IRQF_NO_SUSPEND | IRQF_SHARED,
 			       "glink-rpm", glink);
 	if (ret) {
@@ -1161,7 +1169,7 @@ static int glink_rpm_probe(struct platform_device *pdev)
 
 	glink->irq = irq;
 
-	ret = glink_rpm_send_version(glink);
+	ret = qcom_glink_send_version(glink);
 	if (ret)
 		return ret;
 
@@ -1179,7 +1187,7 @@ static int glink_rpm_remove_device(struct device *dev, void *data)
 
 static int glink_rpm_remove(struct platform_device *pdev)
 {
-	struct glink_rpm *glink = platform_get_drvdata(pdev);
+	struct qcom_glink *glink = platform_get_drvdata(pdev);
 	struct glink_channel *channel;
 	int cid;
 	int ret;
@@ -1193,7 +1201,7 @@ static int glink_rpm_remove(struct platform_device *pdev)
 
 	/* Release any defunct local channels, waiting for close-ack */
 	idr_for_each_entry(&glink->lcids, channel, cid)
-		kref_put(&channel->refcount, glink_rpm_channel_release);
+		kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	idr_destroy(&glink->lcids);
 	idr_destroy(&glink->rcids);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 02/18] rpmsg: glink: Associate indirections for pipe fifo accessor's
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:18   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

From: Bjorn Andersson <bjorn.andersson@linaro.org>

With the intention of reusing the glink core protocol commands
and code across both rpm and smem based transports, the only thing
different is way of accessing the shared-memory of the transport
(FIFO). So put the fifo accessor's of the transport's pipe (rx/tx)
behind indirections, so that the rest of the code can be shared.

For this, have a qcom_glink_pipe that can be used in the common code
containing the indirections and wrap it with glink_rpm_pipe that contains
the transport specific members.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_rpm.c | 144 ++++++++++++++++++++++++++++++-----------
 1 file changed, 106 insertions(+), 38 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 56a0a66..870ce32 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -41,12 +41,28 @@
 #define RPM_GLINK_CID_MIN	1
 #define RPM_GLINK_CID_MAX	65536
 
+#define to_rpm_pipe(p)	container_of(p, struct glink_rpm_pipe, native)
+
 struct rpm_toc_entry {
 	__le32 id;
 	__le32 offset;
 	__le32 size;
 } __packed;
 
+struct qcom_glink;
+
+struct qcom_glink_pipe {
+	size_t length;
+
+	size_t (*avail)(struct qcom_glink_pipe *glink_pipe);
+	void (*peak)(struct qcom_glink_pipe *glink_pipe, void *data,
+		     size_t count);
+	void (*advance)(struct qcom_glink_pipe *glink_pipe, size_t count);
+	void (*write)(struct qcom_glink_pipe *glink_pipe,
+		      const void *hdr, size_t hlen,
+		      const void *data, size_t dlen);
+};
+
 struct rpm_toc {
 	__le32 magic;
 	__le32 count;
@@ -62,12 +78,12 @@ struct glink_msg {
 } __packed;
 
 struct glink_rpm_pipe {
+	struct qcom_glink_pipe native;
+
 	void __iomem *tail;
 	void __iomem *head;
 
 	void __iomem *fifo;
-
-	size_t length;
 };
 
 /**
@@ -107,8 +123,8 @@ struct qcom_glink {
 	struct mbox_client mbox_client;
 	struct mbox_chan *mbox_chan;
 
-	struct glink_rpm_pipe rx_pipe;
-	struct glink_rpm_pipe tx_pipe;
+	struct qcom_glink_pipe *rx_pipe;
+	struct qcom_glink_pipe *tx_pipe;
 
 	int irq;
 
@@ -215,9 +231,9 @@ static void qcom_glink_channel_release(struct kref *ref)
 	kfree(channel);
 }
 
-static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
+static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
 {
-	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int head;
 	unsigned int tail;
 
@@ -225,21 +241,26 @@ static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
 	tail = readl(pipe->tail);
 
 	if (head < tail)
-		return pipe->length - tail + head;
+		return pipe->native.length - tail + head;
 	else
 		return head - tail;
 }
 
-static void qcom_glink_rx_peak(struct qcom_glink *glink,
-			       void *data, size_t count)
+static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
+{
+	return glink->rx_pipe->avail(glink->rx_pipe);
+}
+
+static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
+			      void *data, size_t count)
 {
-	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int tail;
 	size_t len;
 
 	tail = readl(pipe->tail);
 
-	len = min_t(size_t, count, pipe->length - tail);
+	len = min_t(size_t, count, pipe->native.length - tail);
 	if (len) {
 		__ioread32_copy(data, pipe->fifo + tail,
 				len / sizeof(u32));
@@ -251,24 +272,35 @@ static void qcom_glink_rx_peak(struct qcom_glink *glink,
 	}
 }
 
-static void qcom_glink_rx_advance(struct qcom_glink *glink,
-				  size_t count)
+static void qcom_glink_rx_peak(struct qcom_glink *glink,
+			       void *data, size_t count)
 {
-	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
+	glink->rx_pipe->peak(glink->rx_pipe, data, count);
+}
+
+static void glink_rpm_rx_advance(struct qcom_glink_pipe *glink_pipe,
+				 size_t count)
+{
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int tail;
 
 	tail = readl(pipe->tail);
 
 	tail += count;
-	if (tail >= pipe->length)
-		tail -= pipe->length;
+	if (tail >= pipe->native.length)
+		tail -= pipe->native.length;
 
 	writel(tail, pipe->tail);
 }
 
-static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
+static void qcom_glink_rx_advance(struct qcom_glink *glink, size_t count)
+{
+	glink->rx_pipe->advance(glink->rx_pipe, count);
+}
+
+static size_t glink_rpm_tx_avail(struct qcom_glink_pipe *glink_pipe)
 {
-	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int head;
 	unsigned int tail;
 
@@ -276,19 +308,23 @@ static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
 	tail = readl(pipe->tail);
 
 	if (tail <= head)
-		return pipe->length - head + tail;
+		return pipe->native.length - head + tail;
 	else
 		return tail - head;
 }
 
-static unsigned int qcom_glink_tx_write(struct qcom_glink *glink,
-					unsigned int head,
-					const void *data, size_t count)
+static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
+{
+	return glink->tx_pipe->avail(glink->tx_pipe);
+}
+
+static unsigned int glink_rpm_tx_write_one(struct glink_rpm_pipe *pipe,
+					   unsigned int head,
+					   const void *data, size_t count)
 {
-	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
 	size_t len;
 
-	len = min_t(size_t, count, pipe->length - head);
+	len = min_t(size_t, count, pipe->native.length - head);
 	if (len) {
 		__iowrite32_copy(pipe->fifo + head, data,
 				 len / sizeof(u32));
@@ -300,23 +336,41 @@ static unsigned int qcom_glink_tx_write(struct qcom_glink *glink,
 	}
 
 	head += count;
-	if (head >= pipe->length)
-		head -= pipe->length;
+	if (head >= pipe->native.length)
+		head -= pipe->native.length;
 
 	return head;
 }
 
+static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
+			       const void *hdr, size_t hlen,
+			       const void *data, size_t dlen)
+{
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
+	unsigned int head;
+
+	head = readl(pipe->head);
+	head = glink_rpm_tx_write_one(pipe, head, hdr, hlen);
+	head = glink_rpm_tx_write_one(pipe, head, data, dlen);
+	writel(head, pipe->head);
+}
+
+static void qcom_glink_tx_write(struct qcom_glink *glink,
+				const void *hdr, size_t hlen,
+				const void *data, size_t dlen)
+{
+	glink->tx_pipe->write(glink->tx_pipe, hdr, hlen, data, dlen);
+}
+
 static int qcom_glink_tx(struct qcom_glink *glink,
 			 const void *hdr, size_t hlen,
 			const void *data, size_t dlen, bool wait)
 {
-	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
-	unsigned int head;
 	unsigned int tlen = hlen + dlen;
 	int ret;
 
 	/* Reject packets that are too big */
-	if (tlen >= glink->tx_pipe.length)
+	if (tlen >= glink->tx_pipe->length)
 		return -EINVAL;
 
 	if (WARN(tlen % 8, "Unaligned TX request"))
@@ -335,10 +389,7 @@ static int qcom_glink_tx(struct qcom_glink *glink,
 		msleep(10);
 	}
 
-	head = readl(pipe->head);
-	head = qcom_glink_tx_write(glink, head, hdr, hlen);
-	head = qcom_glink_tx_write(glink, head, data, dlen);
-	writel(head, pipe->head);
+	qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
 
 	mbox_send_message(glink->mbox_chan, NULL);
 	mbox_client_txdone(glink->mbox_chan, 0);
@@ -1075,14 +1126,14 @@ static int glink_rpm_parse_toc(struct device *dev,
 
 		switch (id) {
 		case RPM_RX_FIFO_ID:
-			rx->length = size;
+			rx->native.length = size;
 
 			rx->tail = msg_ram + offset;
 			rx->head = msg_ram + offset + sizeof(u32);
 			rx->fifo = msg_ram + offset + 2 * sizeof(u32);
 			break;
 		case RPM_TX_FIFO_ID:
-			tx->length = size;
+			tx->native.length = size;
 
 			tx->tail = msg_ram + offset;
 			tx->head = msg_ram + offset + sizeof(u32);
@@ -1107,6 +1158,8 @@ static int glink_rpm_parse_toc(struct device *dev,
 static int glink_rpm_probe(struct platform_device *pdev)
 {
 	struct qcom_glink *glink;
+	struct glink_rpm_pipe *rx_pipe;
+	struct glink_rpm_pipe *tx_pipe;
 	struct device_node *np;
 	void __iomem *msg_ram;
 	size_t msg_ram_size;
@@ -1121,6 +1174,11 @@ static int glink_rpm_probe(struct platform_device *pdev)
 
 	glink->dev = dev;
 
+	rx_pipe = devm_kzalloc(&pdev->dev, sizeof(*rx_pipe), GFP_KERNEL);
+	tx_pipe = devm_kzalloc(&pdev->dev, sizeof(*tx_pipe), GFP_KERNEL);
+	if (!rx_pipe || !tx_pipe)
+		return -ENOMEM;
+
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
 	INIT_LIST_HEAD(&glink->rx_queue);
@@ -1150,12 +1208,22 @@ static int glink_rpm_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	ret = glink_rpm_parse_toc(dev, msg_ram, msg_ram_size,
-				  &glink->rx_pipe, &glink->tx_pipe);
+				  rx_pipe, tx_pipe);
 	if (ret)
 		return ret;
 
-	writel(0, glink->tx_pipe.head);
-	writel(0, glink->rx_pipe.tail);
+	/* Pipe specific accessors */
+	rx_pipe->native.avail = glink_rpm_rx_avail;
+	rx_pipe->native.peak = glink_rpm_rx_peak;
+	rx_pipe->native.advance = glink_rpm_rx_advance;
+	tx_pipe->native.avail = glink_rpm_tx_avail;
+	tx_pipe->native.write = glink_rpm_tx_write;
+
+	glink->tx_pipe = &tx_pipe->native;
+	glink->rx_pipe = &rx_pipe->native;
+
+	writel(0, tx_pipe->head);
+	writel(0, rx_pipe->tail);
 
 	irq = platform_get_irq(pdev, 0);
 	ret = devm_request_irq(dev, irq,
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 02/18] rpmsg: glink: Associate indirections for pipe fifo accessor's
@ 2017-08-16 17:18   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: Bjorn Andersson <bjorn.andersson@linaro.org>

With the intention of reusing the glink core protocol commands
and code across both rpm and smem based transports, the only thing
different is way of accessing the shared-memory of the transport
(FIFO). So put the fifo accessor's of the transport's pipe (rx/tx)
behind indirections, so that the rest of the code can be shared.

For this, have a qcom_glink_pipe that can be used in the common code
containing the indirections and wrap it with glink_rpm_pipe that contains
the transport specific members.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_rpm.c | 144 ++++++++++++++++++++++++++++++-----------
 1 file changed, 106 insertions(+), 38 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 56a0a66..870ce32 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -41,12 +41,28 @@
 #define RPM_GLINK_CID_MIN	1
 #define RPM_GLINK_CID_MAX	65536
 
+#define to_rpm_pipe(p)	container_of(p, struct glink_rpm_pipe, native)
+
 struct rpm_toc_entry {
 	__le32 id;
 	__le32 offset;
 	__le32 size;
 } __packed;
 
+struct qcom_glink;
+
+struct qcom_glink_pipe {
+	size_t length;
+
+	size_t (*avail)(struct qcom_glink_pipe *glink_pipe);
+	void (*peak)(struct qcom_glink_pipe *glink_pipe, void *data,
+		     size_t count);
+	void (*advance)(struct qcom_glink_pipe *glink_pipe, size_t count);
+	void (*write)(struct qcom_glink_pipe *glink_pipe,
+		      const void *hdr, size_t hlen,
+		      const void *data, size_t dlen);
+};
+
 struct rpm_toc {
 	__le32 magic;
 	__le32 count;
@@ -62,12 +78,12 @@ struct glink_msg {
 } __packed;
 
 struct glink_rpm_pipe {
+	struct qcom_glink_pipe native;
+
 	void __iomem *tail;
 	void __iomem *head;
 
 	void __iomem *fifo;
-
-	size_t length;
 };
 
 /**
@@ -107,8 +123,8 @@ struct qcom_glink {
 	struct mbox_client mbox_client;
 	struct mbox_chan *mbox_chan;
 
-	struct glink_rpm_pipe rx_pipe;
-	struct glink_rpm_pipe tx_pipe;
+	struct qcom_glink_pipe *rx_pipe;
+	struct qcom_glink_pipe *tx_pipe;
 
 	int irq;
 
@@ -215,9 +231,9 @@ static void qcom_glink_channel_release(struct kref *ref)
 	kfree(channel);
 }
 
-static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
+static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
 {
-	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int head;
 	unsigned int tail;
 
@@ -225,21 +241,26 @@ static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
 	tail = readl(pipe->tail);
 
 	if (head < tail)
-		return pipe->length - tail + head;
+		return pipe->native.length - tail + head;
 	else
 		return head - tail;
 }
 
-static void qcom_glink_rx_peak(struct qcom_glink *glink,
-			       void *data, size_t count)
+static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
+{
+	return glink->rx_pipe->avail(glink->rx_pipe);
+}
+
+static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
+			      void *data, size_t count)
 {
-	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int tail;
 	size_t len;
 
 	tail = readl(pipe->tail);
 
-	len = min_t(size_t, count, pipe->length - tail);
+	len = min_t(size_t, count, pipe->native.length - tail);
 	if (len) {
 		__ioread32_copy(data, pipe->fifo + tail,
 				len / sizeof(u32));
@@ -251,24 +272,35 @@ static void qcom_glink_rx_peak(struct qcom_glink *glink,
 	}
 }
 
-static void qcom_glink_rx_advance(struct qcom_glink *glink,
-				  size_t count)
+static void qcom_glink_rx_peak(struct qcom_glink *glink,
+			       void *data, size_t count)
 {
-	struct glink_rpm_pipe *pipe = &glink->rx_pipe;
+	glink->rx_pipe->peak(glink->rx_pipe, data, count);
+}
+
+static void glink_rpm_rx_advance(struct qcom_glink_pipe *glink_pipe,
+				 size_t count)
+{
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int tail;
 
 	tail = readl(pipe->tail);
 
 	tail += count;
-	if (tail >= pipe->length)
-		tail -= pipe->length;
+	if (tail >= pipe->native.length)
+		tail -= pipe->native.length;
 
 	writel(tail, pipe->tail);
 }
 
-static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
+static void qcom_glink_rx_advance(struct qcom_glink *glink, size_t count)
+{
+	glink->rx_pipe->advance(glink->rx_pipe, count);
+}
+
+static size_t glink_rpm_tx_avail(struct qcom_glink_pipe *glink_pipe)
 {
-	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int head;
 	unsigned int tail;
 
@@ -276,19 +308,23 @@ static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
 	tail = readl(pipe->tail);
 
 	if (tail <= head)
-		return pipe->length - head + tail;
+		return pipe->native.length - head + tail;
 	else
 		return tail - head;
 }
 
-static unsigned int qcom_glink_tx_write(struct qcom_glink *glink,
-					unsigned int head,
-					const void *data, size_t count)
+static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
+{
+	return glink->tx_pipe->avail(glink->tx_pipe);
+}
+
+static unsigned int glink_rpm_tx_write_one(struct glink_rpm_pipe *pipe,
+					   unsigned int head,
+					   const void *data, size_t count)
 {
-	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
 	size_t len;
 
-	len = min_t(size_t, count, pipe->length - head);
+	len = min_t(size_t, count, pipe->native.length - head);
 	if (len) {
 		__iowrite32_copy(pipe->fifo + head, data,
 				 len / sizeof(u32));
@@ -300,23 +336,41 @@ static unsigned int qcom_glink_tx_write(struct qcom_glink *glink,
 	}
 
 	head += count;
-	if (head >= pipe->length)
-		head -= pipe->length;
+	if (head >= pipe->native.length)
+		head -= pipe->native.length;
 
 	return head;
 }
 
+static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
+			       const void *hdr, size_t hlen,
+			       const void *data, size_t dlen)
+{
+	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
+	unsigned int head;
+
+	head = readl(pipe->head);
+	head = glink_rpm_tx_write_one(pipe, head, hdr, hlen);
+	head = glink_rpm_tx_write_one(pipe, head, data, dlen);
+	writel(head, pipe->head);
+}
+
+static void qcom_glink_tx_write(struct qcom_glink *glink,
+				const void *hdr, size_t hlen,
+				const void *data, size_t dlen)
+{
+	glink->tx_pipe->write(glink->tx_pipe, hdr, hlen, data, dlen);
+}
+
 static int qcom_glink_tx(struct qcom_glink *glink,
 			 const void *hdr, size_t hlen,
 			const void *data, size_t dlen, bool wait)
 {
-	struct glink_rpm_pipe *pipe = &glink->tx_pipe;
-	unsigned int head;
 	unsigned int tlen = hlen + dlen;
 	int ret;
 
 	/* Reject packets that are too big */
-	if (tlen >= glink->tx_pipe.length)
+	if (tlen >= glink->tx_pipe->length)
 		return -EINVAL;
 
 	if (WARN(tlen % 8, "Unaligned TX request"))
@@ -335,10 +389,7 @@ static int qcom_glink_tx(struct qcom_glink *glink,
 		msleep(10);
 	}
 
-	head = readl(pipe->head);
-	head = qcom_glink_tx_write(glink, head, hdr, hlen);
-	head = qcom_glink_tx_write(glink, head, data, dlen);
-	writel(head, pipe->head);
+	qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
 
 	mbox_send_message(glink->mbox_chan, NULL);
 	mbox_client_txdone(glink->mbox_chan, 0);
@@ -1075,14 +1126,14 @@ static int glink_rpm_parse_toc(struct device *dev,
 
 		switch (id) {
 		case RPM_RX_FIFO_ID:
-			rx->length = size;
+			rx->native.length = size;
 
 			rx->tail = msg_ram + offset;
 			rx->head = msg_ram + offset + sizeof(u32);
 			rx->fifo = msg_ram + offset + 2 * sizeof(u32);
 			break;
 		case RPM_TX_FIFO_ID:
-			tx->length = size;
+			tx->native.length = size;
 
 			tx->tail = msg_ram + offset;
 			tx->head = msg_ram + offset + sizeof(u32);
@@ -1107,6 +1158,8 @@ static int glink_rpm_parse_toc(struct device *dev,
 static int glink_rpm_probe(struct platform_device *pdev)
 {
 	struct qcom_glink *glink;
+	struct glink_rpm_pipe *rx_pipe;
+	struct glink_rpm_pipe *tx_pipe;
 	struct device_node *np;
 	void __iomem *msg_ram;
 	size_t msg_ram_size;
@@ -1121,6 +1174,11 @@ static int glink_rpm_probe(struct platform_device *pdev)
 
 	glink->dev = dev;
 
+	rx_pipe = devm_kzalloc(&pdev->dev, sizeof(*rx_pipe), GFP_KERNEL);
+	tx_pipe = devm_kzalloc(&pdev->dev, sizeof(*tx_pipe), GFP_KERNEL);
+	if (!rx_pipe || !tx_pipe)
+		return -ENOMEM;
+
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
 	INIT_LIST_HEAD(&glink->rx_queue);
@@ -1150,12 +1208,22 @@ static int glink_rpm_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	ret = glink_rpm_parse_toc(dev, msg_ram, msg_ram_size,
-				  &glink->rx_pipe, &glink->tx_pipe);
+				  rx_pipe, tx_pipe);
 	if (ret)
 		return ret;
 
-	writel(0, glink->tx_pipe.head);
-	writel(0, glink->rx_pipe.tail);
+	/* Pipe specific accessors */
+	rx_pipe->native.avail = glink_rpm_rx_avail;
+	rx_pipe->native.peak = glink_rpm_rx_peak;
+	rx_pipe->native.advance = glink_rpm_rx_advance;
+	tx_pipe->native.avail = glink_rpm_tx_avail;
+	tx_pipe->native.write = glink_rpm_tx_write;
+
+	glink->tx_pipe = &tx_pipe->native;
+	glink->rx_pipe = &rx_pipe->native;
+
+	writel(0, tx_pipe->head);
+	writel(0, rx_pipe->tail);
 
 	irq = platform_get_irq(pdev, 0);
 	ret = devm_request_irq(dev, irq,
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 03/18] rpmsg: glink: Split rpm_probe to reuse the common code
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:18   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

From: Bjorn Andersson <bjorn.andersson@linaro.org>

There is quite some code common in glink_rpm_probe that
can reused for glink-smem based transport as well. So
split the function and move the code to glink_native_probe
that can be used later when we add the support for
glink-smem based transport. Also reuse driver's remove as well.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_rpm.c | 85 ++++++++++++++++++++++++------------------
 1 file changed, 49 insertions(+), 36 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 870ce32..5f0fa0d 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/rpmsg.h>
@@ -1155,29 +1156,21 @@ static int glink_rpm_parse_toc(struct device *dev,
 	return -EINVAL;
 }
 
-static int glink_rpm_probe(struct platform_device *pdev)
+struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   struct qcom_glink_pipe *rx,
+					   struct qcom_glink_pipe *tx)
 {
-	struct qcom_glink *glink;
-	struct glink_rpm_pipe *rx_pipe;
-	struct glink_rpm_pipe *tx_pipe;
-	struct device_node *np;
-	void __iomem *msg_ram;
-	size_t msg_ram_size;
-	struct device *dev = &pdev->dev;
-	struct resource r;
 	int irq;
 	int ret;
+	struct qcom_glink *glink;
 
 	glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
 	if (!glink)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	glink->dev = dev;
-
-	rx_pipe = devm_kzalloc(&pdev->dev, sizeof(*rx_pipe), GFP_KERNEL);
-	tx_pipe = devm_kzalloc(&pdev->dev, sizeof(*tx_pipe), GFP_KERNEL);
-	if (!rx_pipe || !tx_pipe)
-		return -ENOMEM;
+	glink->tx_pipe = tx;
+	glink->rx_pipe = rx;
 
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
@@ -1188,14 +1181,48 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	idr_init(&glink->lcids);
 	idr_init(&glink->rcids);
 
-	glink->mbox_client.dev = &pdev->dev;
+	glink->mbox_client.dev = dev;
 	glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
 	if (IS_ERR(glink->mbox_chan)) {
 		if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
-			dev_err(&pdev->dev, "failed to acquire IPC channel\n");
-		return PTR_ERR(glink->mbox_chan);
+			dev_err(dev, "failed to acquire IPC channel\n");
+		return ERR_CAST(glink->mbox_chan);
+	}
+
+	irq = of_irq_get(dev->of_node, 0);
+	ret = devm_request_irq(dev, irq,
+			       qcom_glink_intr,
+			       IRQF_NO_SUSPEND | IRQF_SHARED,
+			       "glink-native", glink);
+	if (ret) {
+		dev_err(dev, "failed to request IRQ\n");
+		return ERR_PTR(ret);
 	}
 
+	ret = qcom_glink_send_version(glink);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return glink;
+}
+
+static int glink_rpm_probe(struct platform_device *pdev)
+{
+	struct qcom_glink *glink;
+	struct glink_rpm_pipe *rx_pipe;
+	struct glink_rpm_pipe *tx_pipe;
+	struct device_node *np;
+	void __iomem *msg_ram;
+	size_t msg_ram_size;
+	struct device *dev = &pdev->dev;
+	struct resource r;
+	int ret;
+
+	rx_pipe = devm_kzalloc(&pdev->dev, sizeof(*rx_pipe), GFP_KERNEL);
+	tx_pipe = devm_kzalloc(&pdev->dev, sizeof(*tx_pipe), GFP_KERNEL);
+	if (!rx_pipe || !tx_pipe)
+		return -ENOMEM;
+
 	np = of_parse_phandle(dev->of_node, "qcom,rpm-msg-ram", 0);
 	ret = of_address_to_resource(np, 0, &r);
 	of_node_put(np);
@@ -1219,27 +1246,13 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	tx_pipe->native.avail = glink_rpm_tx_avail;
 	tx_pipe->native.write = glink_rpm_tx_write;
 
-	glink->tx_pipe = &tx_pipe->native;
-	glink->rx_pipe = &rx_pipe->native;
-
 	writel(0, tx_pipe->head);
 	writel(0, rx_pipe->tail);
 
-	irq = platform_get_irq(pdev, 0);
-	ret = devm_request_irq(dev, irq,
-			       qcom_glink_intr,
-			       IRQF_NO_SUSPEND | IRQF_SHARED,
-			       "glink-rpm", glink);
-	if (ret) {
-		dev_err(dev, "Failed to request IRQ\n");
-		return ret;
-	}
-
-	glink->irq = irq;
-
-	ret = qcom_glink_send_version(glink);
-	if (ret)
-		return ret;
+	glink = qcom_glink_native_probe(&pdev->dev, &rx_pipe->native,
+					&tx_pipe->native);
+	if (IS_ERR(glink))
+		return PTR_ERR(glink);
 
 	platform_set_drvdata(pdev, glink);
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 03/18] rpmsg: glink: Split rpm_probe to reuse the common code
@ 2017-08-16 17:18   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: Bjorn Andersson <bjorn.andersson@linaro.org>

There is quite some code common in glink_rpm_probe that
can reused for glink-smem based transport as well. So
split the function and move the code to glink_native_probe
that can be used later when we add the support for
glink-smem based transport. Also reuse driver's remove as well.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_rpm.c | 85 ++++++++++++++++++++++++------------------
 1 file changed, 49 insertions(+), 36 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 870ce32..5f0fa0d 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/rpmsg.h>
@@ -1155,29 +1156,21 @@ static int glink_rpm_parse_toc(struct device *dev,
 	return -EINVAL;
 }
 
-static int glink_rpm_probe(struct platform_device *pdev)
+struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   struct qcom_glink_pipe *rx,
+					   struct qcom_glink_pipe *tx)
 {
-	struct qcom_glink *glink;
-	struct glink_rpm_pipe *rx_pipe;
-	struct glink_rpm_pipe *tx_pipe;
-	struct device_node *np;
-	void __iomem *msg_ram;
-	size_t msg_ram_size;
-	struct device *dev = &pdev->dev;
-	struct resource r;
 	int irq;
 	int ret;
+	struct qcom_glink *glink;
 
 	glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
 	if (!glink)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	glink->dev = dev;
-
-	rx_pipe = devm_kzalloc(&pdev->dev, sizeof(*rx_pipe), GFP_KERNEL);
-	tx_pipe = devm_kzalloc(&pdev->dev, sizeof(*tx_pipe), GFP_KERNEL);
-	if (!rx_pipe || !tx_pipe)
-		return -ENOMEM;
+	glink->tx_pipe = tx;
+	glink->rx_pipe = rx;
 
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
@@ -1188,14 +1181,48 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	idr_init(&glink->lcids);
 	idr_init(&glink->rcids);
 
-	glink->mbox_client.dev = &pdev->dev;
+	glink->mbox_client.dev = dev;
 	glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
 	if (IS_ERR(glink->mbox_chan)) {
 		if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
-			dev_err(&pdev->dev, "failed to acquire IPC channel\n");
-		return PTR_ERR(glink->mbox_chan);
+			dev_err(dev, "failed to acquire IPC channel\n");
+		return ERR_CAST(glink->mbox_chan);
+	}
+
+	irq = of_irq_get(dev->of_node, 0);
+	ret = devm_request_irq(dev, irq,
+			       qcom_glink_intr,
+			       IRQF_NO_SUSPEND | IRQF_SHARED,
+			       "glink-native", glink);
+	if (ret) {
+		dev_err(dev, "failed to request IRQ\n");
+		return ERR_PTR(ret);
 	}
 
+	ret = qcom_glink_send_version(glink);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return glink;
+}
+
+static int glink_rpm_probe(struct platform_device *pdev)
+{
+	struct qcom_glink *glink;
+	struct glink_rpm_pipe *rx_pipe;
+	struct glink_rpm_pipe *tx_pipe;
+	struct device_node *np;
+	void __iomem *msg_ram;
+	size_t msg_ram_size;
+	struct device *dev = &pdev->dev;
+	struct resource r;
+	int ret;
+
+	rx_pipe = devm_kzalloc(&pdev->dev, sizeof(*rx_pipe), GFP_KERNEL);
+	tx_pipe = devm_kzalloc(&pdev->dev, sizeof(*tx_pipe), GFP_KERNEL);
+	if (!rx_pipe || !tx_pipe)
+		return -ENOMEM;
+
 	np = of_parse_phandle(dev->of_node, "qcom,rpm-msg-ram", 0);
 	ret = of_address_to_resource(np, 0, &r);
 	of_node_put(np);
@@ -1219,27 +1246,13 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	tx_pipe->native.avail = glink_rpm_tx_avail;
 	tx_pipe->native.write = glink_rpm_tx_write;
 
-	glink->tx_pipe = &tx_pipe->native;
-	glink->rx_pipe = &rx_pipe->native;
-
 	writel(0, tx_pipe->head);
 	writel(0, rx_pipe->tail);
 
-	irq = platform_get_irq(pdev, 0);
-	ret = devm_request_irq(dev, irq,
-			       qcom_glink_intr,
-			       IRQF_NO_SUSPEND | IRQF_SHARED,
-			       "glink-rpm", glink);
-	if (ret) {
-		dev_err(dev, "Failed to request IRQ\n");
-		return ret;
-	}
-
-	glink->irq = irq;
-
-	ret = qcom_glink_send_version(glink);
-	if (ret)
-		return ret;
+	glink = qcom_glink_native_probe(&pdev->dev, &rx_pipe->native,
+					&tx_pipe->native);
+	if (IS_ERR(glink))
+		return PTR_ERR(glink);
 
 	platform_set_drvdata(pdev, glink);
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 04/18] rpmsg: glink: Move the common glink protocol implementation to glink_native.c
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:18   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

From: Bjorn Andersson <bjorn.andersson@linaro.org>

Move the common part of glink core protocol implementation to
glink_native.c that can be shared with the smem based glink
transport in the later patches.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/Kconfig             |    6 +-
 drivers/rpmsg/Makefile            |    1 +
 drivers/rpmsg/qcom_glink_native.c | 1014 +++++++++++++++++++++++++++++++++++++
 drivers/rpmsg/qcom_glink_native.h |   38 ++
 drivers/rpmsg/qcom_glink_rpm.c    |  995 +-----------------------------------
 5 files changed, 1061 insertions(+), 993 deletions(-)
 create mode 100644 drivers/rpmsg/qcom_glink_native.c
 create mode 100644 drivers/rpmsg/qcom_glink_native.h

diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 2a5d2b4..ac33688 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -13,9 +13,13 @@ config RPMSG_CHAR
 	  in /dev. They make it possible for user-space programs to send and
 	  receive rpmsg packets.
 
+config RPMSG_QCOM_GLINK_NATIVE
+	tristate
+	select RPMSG
+
 config RPMSG_QCOM_GLINK_RPM
 	tristate "Qualcomm RPM Glink driver"
-	select RPMSG
+        select RPMSG_QCOM_GLINK_NATIVE
 	depends on HAS_IOMEM
 	depends on MAILBOX
 	help
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 28cc190..09a756c 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_RPMSG)		+= rpmsg_core.o
 obj-$(CONFIG_RPMSG_CHAR)	+= rpmsg_char.o
 obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
+obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o
 obj-$(CONFIG_RPMSG_QCOM_SMD)	+= qcom_smd.o
 obj-$(CONFIG_RPMSG_VIRTIO)	+= virtio_rpmsg_bus.o
diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
new file mode 100644
index 0000000..04afbb2
--- /dev/null
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -0,0 +1,1014 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/mailbox_client.h>
+
+#include "rpmsg_internal.h"
+#include "qcom_glink_native.h"
+
+#define GLINK_NAME_SIZE		32
+
+#define RPM_GLINK_CID_MIN	1
+#define RPM_GLINK_CID_MAX	65536
+
+struct glink_msg {
+	__le16 cmd;
+	__le16 param1;
+	__le32 param2;
+	u8 data[];
+} __packed;
+
+/**
+ * struct glink_defer_cmd - deferred incoming control message
+ * @node:	list node
+ * @msg:	message header
+ * data:	payload of the message
+ *
+ * Copy of a received control message, to be added to @rx_queue and processed
+ * by @rx_work of @glink_rpm.
+ */
+struct glink_defer_cmd {
+	struct list_head node;
+
+	struct glink_msg msg;
+	u8 data[];
+};
+
+/**
+ * struct glink_rpm - driver context, relates to one remote subsystem
+ * @dev:	reference to the associated struct device
+ * @doorbell:	"rpm_hlos" ipc doorbell
+ * @rx_pipe:	pipe object for receive FIFO
+ * @tx_pipe:	pipe object for transmit FIFO
+ * @irq:	IRQ for signaling incoming events
+ * @rx_work:	worker for handling received control messages
+ * @rx_lock:	protects the @rx_queue
+ * @rx_queue:	queue of received control messages to be processed in @rx_work
+ * @tx_lock:	synchronizes operations on the tx fifo
+ * @idr_lock:	synchronizes @lcids and @rcids modifications
+ * @lcids:	idr of all channels with a known local channel id
+ * @rcids:	idr of all channels with a known remote channel id
+ */
+struct qcom_glink {
+	struct device *dev;
+
+	struct mbox_client mbox_client;
+	struct mbox_chan *mbox_chan;
+
+	struct qcom_glink_pipe *rx_pipe;
+	struct qcom_glink_pipe *tx_pipe;
+
+	int irq;
+
+	struct work_struct rx_work;
+	spinlock_t rx_lock;
+	struct list_head rx_queue;
+
+	struct mutex tx_lock;
+
+	struct mutex idr_lock;
+	struct idr lcids;
+	struct idr rcids;
+};
+
+enum {
+	GLINK_STATE_CLOSED,
+	GLINK_STATE_OPENING,
+	GLINK_STATE_OPEN,
+	GLINK_STATE_CLOSING,
+};
+
+/**
+ * struct glink_channel - internal representation of a channel
+ * @rpdev:	rpdev reference, only used for primary endpoints
+ * @ept:	rpmsg endpoint this channel is associated with
+ * @glink:	qcom_glink context handle
+ * @refcount:	refcount for the channel object
+ * @recv_lock:	guard for @ept.cb
+ * @name:	unique channel name/identifier
+ * @lcid:	channel id, in local space
+ * @rcid:	channel id, in remote space
+ * @buf:	receive buffer, for gathering fragments
+ * @buf_offset:	write offset in @buf
+ * @buf_size:	size of current @buf
+ * @open_ack:	completed once remote has acked the open-request
+ * @open_req:	completed once open-request has been received
+ */
+struct glink_channel {
+	struct rpmsg_endpoint ept;
+
+	struct rpmsg_device *rpdev;
+	struct qcom_glink *glink;
+
+	struct kref refcount;
+
+	spinlock_t recv_lock;
+
+	char *name;
+	unsigned int lcid;
+	unsigned int rcid;
+
+	void *buf;
+	int buf_offset;
+	int buf_size;
+
+	struct completion open_ack;
+	struct completion open_req;
+};
+
+#define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept)
+
+static const struct rpmsg_endpoint_ops glink_endpoint_ops;
+
+#define RPM_CMD_VERSION			0
+#define RPM_CMD_VERSION_ACK		1
+#define RPM_CMD_OPEN			2
+#define RPM_CMD_CLOSE			3
+#define RPM_CMD_OPEN_ACK		4
+#define RPM_CMD_TX_DATA			9
+#define RPM_CMD_CLOSE_ACK		11
+#define RPM_CMD_TX_DATA_CONT		12
+#define RPM_CMD_READ_NOTIF		13
+
+#define GLINK_FEATURE_INTENTLESS	BIT(1)
+
+static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
+						      const char *name)
+{
+	struct glink_channel *channel;
+
+	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+	if (!channel)
+		return ERR_PTR(-ENOMEM);
+
+	/* Setup glink internal glink_channel data */
+	spin_lock_init(&channel->recv_lock);
+	channel->glink = glink;
+	channel->name = kstrdup(name, GFP_KERNEL);
+
+	init_completion(&channel->open_req);
+	init_completion(&channel->open_ack);
+
+	kref_init(&channel->refcount);
+
+	return channel;
+}
+
+static void qcom_glink_channel_release(struct kref *ref)
+{
+	struct glink_channel *channel = container_of(ref, struct glink_channel,
+						     refcount);
+
+	kfree(channel->name);
+	kfree(channel);
+}
+
+static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
+{
+	return glink->rx_pipe->avail(glink->rx_pipe);
+}
+
+static void qcom_glink_rx_peak(struct qcom_glink *glink,
+			       void *data, size_t count)
+{
+	glink->rx_pipe->peak(glink->rx_pipe, data, count);
+}
+
+static void qcom_glink_rx_advance(struct qcom_glink *glink, size_t count)
+{
+	glink->rx_pipe->advance(glink->rx_pipe, count);
+}
+
+static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
+{
+	return glink->tx_pipe->avail(glink->tx_pipe);
+}
+
+static void qcom_glink_tx_write(struct qcom_glink *glink,
+				const void *hdr, size_t hlen,
+				const void *data, size_t dlen)
+{
+	glink->tx_pipe->write(glink->tx_pipe, hdr, hlen, data, dlen);
+}
+
+static int qcom_glink_tx(struct qcom_glink *glink,
+			 const void *hdr, size_t hlen,
+			 const void *data, size_t dlen, bool wait)
+{
+	unsigned int tlen = hlen + dlen;
+	int ret;
+
+	/* Reject packets that are too big */
+	if (tlen >= glink->tx_pipe->length)
+		return -EINVAL;
+
+	if (WARN(tlen % 8, "Unaligned TX request"))
+		return -EINVAL;
+
+	ret = mutex_lock_interruptible(&glink->tx_lock);
+	if (ret)
+		return ret;
+
+	while (qcom_glink_tx_avail(glink) < tlen) {
+		if (!wait) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		msleep(10);
+	}
+
+	qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
+
+	mbox_send_message(glink->mbox_chan, NULL);
+	mbox_client_txdone(glink->mbox_chan, 0);
+
+out:
+	mutex_unlock(&glink->tx_lock);
+
+	return ret;
+}
+
+static int qcom_glink_send_version(struct qcom_glink *glink)
+{
+	struct glink_msg msg;
+
+	msg.cmd = cpu_to_le16(RPM_CMD_VERSION);
+	msg.param1 = cpu_to_le16(1);
+	msg.param2 = cpu_to_le32(GLINK_FEATURE_INTENTLESS);
+
+	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+}
+
+static void qcom_glink_send_version_ack(struct qcom_glink *glink)
+{
+	struct glink_msg msg;
+
+	msg.cmd = cpu_to_le16(RPM_CMD_VERSION_ACK);
+	msg.param1 = cpu_to_le16(1);
+	msg.param2 = cpu_to_le32(0);
+
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+}
+
+static void qcom_glink_send_open_ack(struct qcom_glink *glink,
+				     struct glink_channel *channel)
+{
+	struct glink_msg msg;
+
+	msg.cmd = cpu_to_le16(RPM_CMD_OPEN_ACK);
+	msg.param1 = cpu_to_le16(channel->rcid);
+	msg.param2 = cpu_to_le32(0);
+
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+}
+
+/**
+ * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
+ * @glink:
+ * @channel:
+ *
+ * Allocates a local channel id and sends a RPM_CMD_OPEN message to the remote.
+ * Will return with refcount held, regardless of outcome.
+ *
+ * Returns 0 on success, negative errno otherwise.
+ */
+static int qcom_glink_send_open_req(struct qcom_glink *glink,
+				    struct glink_channel *channel)
+{
+	struct {
+		struct glink_msg msg;
+		u8 name[GLINK_NAME_SIZE];
+	} __packed req;
+	int name_len = strlen(channel->name) + 1;
+	int req_len = ALIGN(sizeof(req.msg) + name_len, 8);
+	int ret;
+
+	kref_get(&channel->refcount);
+
+	mutex_lock(&glink->idr_lock);
+	ret = idr_alloc_cyclic(&glink->lcids, channel,
+			       RPM_GLINK_CID_MIN, RPM_GLINK_CID_MAX,
+			       GFP_KERNEL);
+	mutex_unlock(&glink->idr_lock);
+	if (ret < 0)
+		return ret;
+
+	channel->lcid = ret;
+
+	req.msg.cmd = cpu_to_le16(RPM_CMD_OPEN);
+	req.msg.param1 = cpu_to_le16(channel->lcid);
+	req.msg.param2 = cpu_to_le32(name_len);
+	strcpy(req.name, channel->name);
+
+	ret = qcom_glink_tx(glink, &req, req_len, NULL, 0, true);
+	if (ret)
+		goto remove_idr;
+
+	return 0;
+
+remove_idr:
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->lcids, channel->lcid);
+	channel->lcid = 0;
+	mutex_unlock(&glink->idr_lock);
+
+	return ret;
+}
+
+static void qcom_glink_send_close_req(struct qcom_glink *glink,
+				      struct glink_channel *channel)
+{
+	struct glink_msg req;
+
+	req.cmd = cpu_to_le16(RPM_CMD_CLOSE);
+	req.param1 = cpu_to_le16(channel->lcid);
+	req.param2 = 0;
+
+	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
+}
+
+static void qcom_glink_send_close_ack(struct qcom_glink *glink,
+				      unsigned int rcid)
+{
+	struct glink_msg req;
+
+	req.cmd = cpu_to_le16(RPM_CMD_CLOSE_ACK);
+	req.param1 = cpu_to_le16(rcid);
+	req.param2 = 0;
+
+	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
+}
+
+static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
+{
+	struct glink_defer_cmd *dcmd;
+
+	extra = ALIGN(extra, 8);
+
+	if (qcom_glink_rx_avail(glink) < sizeof(struct glink_msg) + extra) {
+		dev_dbg(glink->dev, "Insufficient data in rx fifo");
+		return -ENXIO;
+	}
+
+	dcmd = kzalloc(sizeof(*dcmd) + extra, GFP_ATOMIC);
+	if (!dcmd)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dcmd->node);
+
+	qcom_glink_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
+
+	spin_lock(&glink->rx_lock);
+	list_add_tail(&dcmd->node, &glink->rx_queue);
+	spin_unlock(&glink->rx_lock);
+
+	schedule_work(&glink->rx_work);
+	qcom_glink_rx_advance(glink, sizeof(dcmd->msg) + extra);
+
+	return 0;
+}
+
+static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
+{
+	struct glink_channel *channel;
+	struct {
+		struct glink_msg msg;
+		__le32 chunk_size;
+		__le32 left_size;
+	} __packed hdr;
+	unsigned int chunk_size;
+	unsigned int left_size;
+	unsigned int rcid;
+
+	if (avail < sizeof(hdr)) {
+		dev_dbg(glink->dev, "Not enough data in fifo\n");
+		return -EAGAIN;
+	}
+
+	qcom_glink_rx_peak(glink, &hdr, sizeof(hdr));
+	chunk_size = le32_to_cpu(hdr.chunk_size);
+	left_size = le32_to_cpu(hdr.left_size);
+
+	if (avail < sizeof(hdr) + chunk_size) {
+		dev_dbg(glink->dev, "Payload not yet in fifo\n");
+		return -EAGAIN;
+	}
+
+	if (WARN(chunk_size % 4, "Incoming data must be word aligned\n"))
+		return -EINVAL;
+
+	rcid = le16_to_cpu(hdr.msg.param1);
+	channel = idr_find(&glink->rcids, rcid);
+	if (!channel) {
+		dev_dbg(glink->dev, "Data on non-existing channel\n");
+
+		/* Drop the message */
+		qcom_glink_rx_advance(glink,
+				      ALIGN(sizeof(hdr) + chunk_size, 8));
+		return 0;
+	}
+
+	/* Might have an ongoing, fragmented, message to append */
+	if (!channel->buf) {
+		channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
+		if (!channel->buf)
+			return -ENOMEM;
+
+		channel->buf_size = chunk_size + left_size;
+		channel->buf_offset = 0;
+	}
+
+	qcom_glink_rx_advance(glink, sizeof(hdr));
+
+	if (channel->buf_size - channel->buf_offset < chunk_size) {
+		dev_err(glink->dev, "Insufficient space in input buffer\n");
+
+		/* The packet header lied, drop payload */
+		qcom_glink_rx_advance(glink, chunk_size);
+		return -ENOMEM;
+	}
+
+	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
+			   chunk_size);
+	channel->buf_offset += chunk_size;
+
+	/* Handle message when no fragments remain to be received */
+	if (!left_size) {
+		spin_lock(&channel->recv_lock);
+		if (channel->ept.cb) {
+			channel->ept.cb(channel->ept.rpdev,
+					channel->buf,
+					channel->buf_offset,
+					channel->ept.priv,
+					RPMSG_ADDR_ANY);
+		}
+		spin_unlock(&channel->recv_lock);
+
+		kfree(channel->buf);
+		channel->buf = NULL;
+		channel->buf_size = 0;
+	}
+
+	/* Each message starts at 8 byte aligned address */
+	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
+
+	return 0;
+}
+
+static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
+{
+	struct glink_channel *channel;
+
+	channel = idr_find(&glink->lcids, lcid);
+	if (!channel) {
+		dev_err(glink->dev, "Invalid open ack packet\n");
+		return -EINVAL;
+	}
+
+	complete(&channel->open_ack);
+
+	return 0;
+}
+
+static irqreturn_t qcom_glink_native_intr(int irq, void *data)
+{
+	struct qcom_glink *glink = data;
+	struct glink_msg msg;
+	unsigned int param1;
+	unsigned int param2;
+	unsigned int avail;
+	unsigned int cmd;
+	int ret;
+
+	for (;;) {
+		avail = qcom_glink_rx_avail(glink);
+		if (avail < sizeof(msg))
+			break;
+
+		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
+
+		cmd = le16_to_cpu(msg.cmd);
+		param1 = le16_to_cpu(msg.param1);
+		param2 = le32_to_cpu(msg.param2);
+
+		switch (cmd) {
+		case RPM_CMD_VERSION:
+		case RPM_CMD_VERSION_ACK:
+		case RPM_CMD_CLOSE:
+		case RPM_CMD_CLOSE_ACK:
+			ret = qcom_glink_rx_defer(glink, 0);
+			break;
+		case RPM_CMD_OPEN_ACK:
+			ret = qcom_glink_rx_open_ack(glink, param1);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			break;
+		case RPM_CMD_OPEN:
+			ret = qcom_glink_rx_defer(glink, param2);
+			break;
+		case RPM_CMD_TX_DATA:
+		case RPM_CMD_TX_DATA_CONT:
+			ret = qcom_glink_rx_data(glink, avail);
+			break;
+		case RPM_CMD_READ_NOTIF:
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+
+			mbox_send_message(glink->mbox_chan, NULL);
+			mbox_client_txdone(glink->mbox_chan, 0);
+
+			ret = 0;
+			break;
+		default:
+			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
+			ret = -EINVAL;
+			break;
+		}
+
+		if (ret)
+			break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* Locally initiated rpmsg_create_ept */
+static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
+						     const char *name)
+{
+	struct glink_channel *channel;
+	int ret;
+
+	channel = qcom_glink_alloc_channel(glink, name);
+	if (IS_ERR(channel))
+		return ERR_CAST(channel);
+
+	ret = qcom_glink_send_open_req(glink, channel);
+	if (ret)
+		goto release_channel;
+
+	ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ);
+	if (!ret)
+		goto err_timeout;
+
+	ret = wait_for_completion_timeout(&channel->open_req, 5 * HZ);
+	if (!ret)
+		goto err_timeout;
+
+	qcom_glink_send_open_ack(glink, channel);
+
+	return channel;
+
+err_timeout:
+	/* qcom_glink_send_open_req() did register the channel in lcids*/
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->lcids, channel->lcid);
+	mutex_unlock(&glink->idr_lock);
+
+release_channel:
+	/* Release qcom_glink_send_open_req() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+	/* Release qcom_glink_alloc_channel() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+
+	return ERR_PTR(-ETIMEDOUT);
+}
+
+/* Remote initiated rpmsg_create_ept */
+static int qcom_glink_create_remote(struct qcom_glink *glink,
+				    struct glink_channel *channel)
+{
+	int ret;
+
+	qcom_glink_send_open_ack(glink, channel);
+
+	ret = qcom_glink_send_open_req(glink, channel);
+	if (ret)
+		goto close_link;
+
+	ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ);
+	if (!ret) {
+		ret = -ETIMEDOUT;
+		goto close_link;
+	}
+
+	return 0;
+
+close_link:
+	/*
+	 * Send a close request to "undo" our open-ack. The close-ack will
+	 * release the last reference.
+	 */
+	qcom_glink_send_close_req(glink, channel);
+
+	/* Release qcom_glink_send_open_req() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+
+	return ret;
+}
+
+static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
+						    rpmsg_rx_cb_t cb,
+						    void *priv,
+						    struct rpmsg_channel_info
+									chinfo)
+{
+	struct glink_channel *parent = to_glink_channel(rpdev->ept);
+	struct glink_channel *channel;
+	struct qcom_glink *glink = parent->glink;
+	struct rpmsg_endpoint *ept;
+	const char *name = chinfo.name;
+	int cid;
+	int ret;
+
+	idr_for_each_entry(&glink->rcids, channel, cid) {
+		if (!strcmp(channel->name, name))
+			break;
+	}
+
+	if (!channel) {
+		channel = qcom_glink_create_local(glink, name);
+		if (IS_ERR(channel))
+			return NULL;
+	} else {
+		ret = qcom_glink_create_remote(glink, channel);
+		if (ret)
+			return NULL;
+	}
+
+	ept = &channel->ept;
+	ept->rpdev = rpdev;
+	ept->cb = cb;
+	ept->priv = priv;
+	ept->ops = &glink_endpoint_ops;
+
+	return ept;
+}
+
+static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
+{
+	struct glink_channel *channel = to_glink_channel(ept);
+	struct qcom_glink *glink = channel->glink;
+	unsigned long flags;
+
+	spin_lock_irqsave(&channel->recv_lock, flags);
+	channel->ept.cb = NULL;
+	spin_unlock_irqrestore(&channel->recv_lock, flags);
+
+	/* Decouple the potential rpdev from the channel */
+	channel->rpdev = NULL;
+
+	qcom_glink_send_close_req(glink, channel);
+}
+
+static int __qcom_glink_send(struct glink_channel *channel,
+			     void *data, int len, bool wait)
+{
+	struct qcom_glink *glink = channel->glink;
+	struct {
+		struct glink_msg msg;
+		__le32 chunk_size;
+		__le32 left_size;
+	} __packed req;
+
+	if (WARN(len % 8, "RPM GLINK expects 8 byte aligned messages\n"))
+		return -EINVAL;
+
+	req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
+	req.msg.param1 = cpu_to_le16(channel->lcid);
+	req.msg.param2 = cpu_to_le32(channel->rcid);
+	req.chunk_size = cpu_to_le32(len);
+	req.left_size = cpu_to_le32(0);
+
+	return qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
+}
+
+static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+	struct glink_channel *channel = to_glink_channel(ept);
+
+	return __qcom_glink_send(channel, data, len, true);
+}
+
+static int qcom_glink_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+	struct glink_channel *channel = to_glink_channel(ept);
+
+	return __qcom_glink_send(channel, data, len, false);
+}
+
+/*
+ * Finds the device_node for the glink child interested in this channel.
+ */
+static struct device_node *qcom_glink_match_channel(struct device_node *node,
+						    const char *channel)
+{
+	struct device_node *child;
+	const char *name;
+	const char *key;
+	int ret;
+
+	for_each_available_child_of_node(node, child) {
+		key = "qcom,glink-channels";
+		ret = of_property_read_string(child, key, &name);
+		if (ret)
+			continue;
+
+		if (strcmp(name, channel) == 0)
+			return child;
+	}
+
+	return NULL;
+}
+
+static const struct rpmsg_device_ops glink_device_ops = {
+	.create_ept = qcom_glink_create_ept,
+};
+
+static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
+	.destroy_ept = qcom_glink_destroy_ept,
+	.send = qcom_glink_send,
+	.trysend = qcom_glink_trysend,
+};
+
+static void qcom_glink_rpdev_release(struct device *dev)
+{
+	struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+	struct glink_channel *channel = to_glink_channel(rpdev->ept);
+
+	channel->rpdev = NULL;
+	kfree(rpdev);
+}
+
+static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
+			      char *name)
+{
+	struct glink_channel *channel;
+	struct rpmsg_device *rpdev;
+	bool create_device = false;
+	struct device_node *node;
+	int lcid;
+	int ret;
+
+	idr_for_each_entry(&glink->lcids, channel, lcid) {
+		if (!strcmp(channel->name, name))
+			break;
+	}
+
+	if (!channel) {
+		channel = qcom_glink_alloc_channel(glink, name);
+		if (IS_ERR(channel))
+			return PTR_ERR(channel);
+
+		/* The opening dance was initiated by the remote */
+		create_device = true;
+	}
+
+	mutex_lock(&glink->idr_lock);
+	ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_KERNEL);
+	if (ret < 0) {
+		dev_err(glink->dev, "Unable to insert channel into rcid list\n");
+		mutex_unlock(&glink->idr_lock);
+		goto free_channel;
+	}
+	channel->rcid = ret;
+	mutex_unlock(&glink->idr_lock);
+
+	complete(&channel->open_req);
+
+	if (create_device) {
+		rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL);
+		if (!rpdev) {
+			ret = -ENOMEM;
+			goto rcid_remove;
+		}
+
+		rpdev->ept = &channel->ept;
+		strncpy(rpdev->id.name, name, RPMSG_NAME_SIZE);
+		rpdev->src = RPMSG_ADDR_ANY;
+		rpdev->dst = RPMSG_ADDR_ANY;
+		rpdev->ops = &glink_device_ops;
+
+		node = qcom_glink_match_channel(glink->dev->of_node, name);
+		rpdev->dev.of_node = node;
+		rpdev->dev.parent = glink->dev;
+		rpdev->dev.release = qcom_glink_rpdev_release;
+
+		ret = rpmsg_register_device(rpdev);
+		if (ret)
+			goto free_rpdev;
+
+		channel->rpdev = rpdev;
+	}
+
+	return 0;
+
+free_rpdev:
+	kfree(rpdev);
+rcid_remove:
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->rcids, channel->rcid);
+	channel->rcid = 0;
+	mutex_unlock(&glink->idr_lock);
+free_channel:
+	/* Release the reference, iff we took it */
+	if (create_device)
+		kref_put(&channel->refcount, qcom_glink_channel_release);
+
+	return ret;
+}
+
+static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
+{
+	struct rpmsg_channel_info chinfo;
+	struct glink_channel *channel;
+
+	channel = idr_find(&glink->rcids, rcid);
+	if (WARN(!channel, "close request on unknown channel\n"))
+		return;
+
+	if (channel->rpdev) {
+		strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
+		chinfo.src = RPMSG_ADDR_ANY;
+		chinfo.dst = RPMSG_ADDR_ANY;
+
+		rpmsg_unregister_device(glink->dev, &chinfo);
+	}
+
+	qcom_glink_send_close_ack(glink, channel->rcid);
+
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->rcids, channel->rcid);
+	channel->rcid = 0;
+	mutex_unlock(&glink->idr_lock);
+
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+}
+
+static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
+{
+	struct glink_channel *channel;
+
+	channel = idr_find(&glink->lcids, lcid);
+	if (WARN(!channel, "close ack on unknown channel\n"))
+		return;
+
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->lcids, channel->lcid);
+	channel->lcid = 0;
+	mutex_unlock(&glink->idr_lock);
+
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+}
+
+static void qcom_glink_work(struct work_struct *work)
+{
+	struct qcom_glink *glink = container_of(work, struct qcom_glink,
+						rx_work);
+	struct glink_defer_cmd *dcmd;
+	struct glink_msg *msg;
+	unsigned long flags;
+	unsigned int param1;
+	unsigned int param2;
+	unsigned int cmd;
+
+	for (;;) {
+		spin_lock_irqsave(&glink->rx_lock, flags);
+		if (list_empty(&glink->rx_queue)) {
+			spin_unlock_irqrestore(&glink->rx_lock, flags);
+			break;
+		}
+		dcmd = list_first_entry(&glink->rx_queue,
+					struct glink_defer_cmd, node);
+		list_del(&dcmd->node);
+		spin_unlock_irqrestore(&glink->rx_lock, flags);
+
+		msg = &dcmd->msg;
+		cmd = le16_to_cpu(msg->cmd);
+		param1 = le16_to_cpu(msg->param1);
+		param2 = le32_to_cpu(msg->param2);
+
+		switch (cmd) {
+		case RPM_CMD_VERSION:
+			qcom_glink_send_version_ack(glink);
+			break;
+		case RPM_CMD_VERSION_ACK:
+			break;
+		case RPM_CMD_OPEN:
+			qcom_glink_rx_open(glink, param1, msg->data);
+			break;
+		case RPM_CMD_CLOSE:
+			qcom_glink_rx_close(glink, param1);
+			break;
+		case RPM_CMD_CLOSE_ACK:
+			qcom_glink_rx_close_ack(glink, param1);
+			break;
+		default:
+			WARN(1, "Unknown defer object %d\n", cmd);
+			break;
+		}
+
+		kfree(dcmd);
+	}
+}
+
+struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   struct qcom_glink_pipe *rx,
+					   struct qcom_glink_pipe *tx)
+{
+	int irq;
+	int ret;
+	struct qcom_glink *glink;
+
+	glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
+	if (!glink)
+		return ERR_PTR(-ENOMEM);
+
+	glink->dev = dev;
+	glink->tx_pipe = tx;
+	glink->rx_pipe = rx;
+
+	mutex_init(&glink->tx_lock);
+	spin_lock_init(&glink->rx_lock);
+	INIT_LIST_HEAD(&glink->rx_queue);
+	INIT_WORK(&glink->rx_work, qcom_glink_work);
+
+	mutex_init(&glink->idr_lock);
+	idr_init(&glink->lcids);
+	idr_init(&glink->rcids);
+
+	glink->mbox_client.dev = dev;
+	glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
+	if (IS_ERR(glink->mbox_chan)) {
+		if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
+			dev_err(dev, "failed to acquire IPC channel\n");
+		return ERR_CAST(glink->mbox_chan);
+	}
+
+	irq = of_irq_get(dev->of_node, 0);
+	ret = devm_request_irq(dev, irq,
+			       qcom_glink_native_intr,
+			       IRQF_NO_SUSPEND | IRQF_SHARED,
+			       "glink-native", glink);
+	if (ret) {
+		dev_err(dev, "failed to request IRQ\n");
+		return ERR_PTR(ret);
+	}
+
+	ret = qcom_glink_send_version(glink);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return glink;
+}
+
+static int qcom_glink_remove_device(struct device *dev, void *data)
+{
+	device_unregister(dev);
+
+	return 0;
+}
+
+void qcom_glink_native_remove(struct qcom_glink *glink)
+{
+	struct glink_channel *channel;
+	int cid;
+	int ret;
+
+	disable_irq(glink->irq);
+	cancel_work_sync(&glink->rx_work);
+
+	ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device);
+	if (ret)
+		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
+
+	/* Release any defunct local channels, waiting for close-ack */
+	idr_for_each_entry(&glink->lcids, channel, cid)
+		kref_put(&channel->refcount, qcom_glink_channel_release);
+
+	idr_destroy(&glink->lcids);
+	idr_destroy(&glink->rcids);
+}
diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
new file mode 100644
index 0000000..d5627a4
--- /dev/null
+++ b/drivers/rpmsg/qcom_glink_native.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_GLINK_NATIVE_H__
+#define __QCOM_GLINK_NATIVE_H__
+
+struct qcom_glink_pipe {
+	size_t length;
+
+	size_t (*avail)(struct qcom_glink_pipe *glink_pipe);
+
+	void (*peak)(struct qcom_glink_pipe *glink_pipe, void *data,
+		     size_t count);
+	void (*advance)(struct qcom_glink_pipe *glink_pipe, size_t count);
+
+	void (*write)(struct qcom_glink_pipe *glink_pipe,
+		      const void *hdr, size_t hlen,
+		      const void *data, size_t dlen);
+};
+
+struct qcom_glink;
+
+struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   struct qcom_glink_pipe *rx,
+					   struct qcom_glink_pipe *tx);
+void qcom_glink_native_remove(struct qcom_glink *glink);
+
+#endif
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 5f0fa0d..33daa32 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/rpmsg.h>
@@ -28,6 +27,7 @@
 #include <linux/mailbox_client.h>
 
 #include "rpmsg_internal.h"
+#include "qcom_glink_native.h"
 
 #define RPM_TOC_SIZE		256
 #define RPM_TOC_MAGIC		0x67727430 /* grt0 */
@@ -37,12 +37,7 @@
 #define RPM_TX_FIFO_ID		0x61703272 /* ap2r */
 #define RPM_RX_FIFO_ID		0x72326170 /* r2ap */
 
-#define GLINK_NAME_SIZE		32
-
-#define RPM_GLINK_CID_MIN	1
-#define RPM_GLINK_CID_MAX	65536
-
-#define to_rpm_pipe(p)	container_of(p, struct glink_rpm_pipe, native)
+#define to_rpm_pipe(p) container_of(p, struct glink_rpm_pipe, native)
 
 struct rpm_toc_entry {
 	__le32 id;
@@ -50,20 +45,6 @@ struct rpm_toc_entry {
 	__le32 size;
 } __packed;
 
-struct qcom_glink;
-
-struct qcom_glink_pipe {
-	size_t length;
-
-	size_t (*avail)(struct qcom_glink_pipe *glink_pipe);
-	void (*peak)(struct qcom_glink_pipe *glink_pipe, void *data,
-		     size_t count);
-	void (*advance)(struct qcom_glink_pipe *glink_pipe, size_t count);
-	void (*write)(struct qcom_glink_pipe *glink_pipe,
-		      const void *hdr, size_t hlen,
-		      const void *data, size_t dlen);
-};
-
 struct rpm_toc {
 	__le32 magic;
 	__le32 count;
@@ -71,13 +52,6 @@ struct rpm_toc {
 	struct rpm_toc_entry entries[];
 } __packed;
 
-struct glink_msg {
-	__le16 cmd;
-	__le16 param1;
-	__le32 param2;
-	u8 data[];
-} __packed;
-
 struct glink_rpm_pipe {
 	struct qcom_glink_pipe native;
 
@@ -87,151 +61,6 @@ struct glink_rpm_pipe {
 	void __iomem *fifo;
 };
 
-/**
- * struct glink_defer_cmd - deferred incoming control message
- * @node:	list node
- * @msg:	message header
- * data:	payload of the message
- *
- * Copy of a received control message, to be added to @rx_queue and processed
- * by @rx_work of @glink_rpm.
- */
-struct glink_defer_cmd {
-	struct list_head node;
-
-	struct glink_msg msg;
-	u8 data[];
-};
-
-/**
- * struct glink_rpm - driver context, relates to one remote subsystem
- * @dev:	reference to the associated struct device
- * @doorbell:	"rpm_hlos" ipc doorbell
- * @rx_pipe:	pipe object for receive FIFO
- * @tx_pipe:	pipe object for transmit FIFO
- * @irq:	IRQ for signaling incoming events
- * @rx_work:	worker for handling received control messages
- * @rx_lock:	protects the @rx_queue
- * @rx_queue:	queue of received control messages to be processed in @rx_work
- * @tx_lock:	synchronizes operations on the tx fifo
- * @idr_lock:	synchronizes @lcids and @rcids modifications
- * @lcids:	idr of all channels with a known local channel id
- * @rcids:	idr of all channels with a known remote channel id
- */
-struct qcom_glink {
-	struct device *dev;
-
-	struct mbox_client mbox_client;
-	struct mbox_chan *mbox_chan;
-
-	struct qcom_glink_pipe *rx_pipe;
-	struct qcom_glink_pipe *tx_pipe;
-
-	int irq;
-
-	struct work_struct rx_work;
-	spinlock_t rx_lock;
-	struct list_head rx_queue;
-
-	struct mutex tx_lock;
-
-	struct mutex idr_lock;
-	struct idr lcids;
-	struct idr rcids;
-};
-
-enum {
-	GLINK_STATE_CLOSED,
-	GLINK_STATE_OPENING,
-	GLINK_STATE_OPEN,
-	GLINK_STATE_CLOSING,
-};
-
-/**
- * struct glink_channel - internal representation of a channel
- * @rpdev:	rpdev reference, only used for primary endpoints
- * @ept:	rpmsg endpoint this channel is associated with
- * @glink:	qcom_glink context handle
- * @refcount:	refcount for the channel object
- * @recv_lock:	guard for @ept.cb
- * @name:	unique channel name/identifier
- * @lcid:	channel id, in local space
- * @rcid:	channel id, in remote space
- * @buf:	receive buffer, for gathering fragments
- * @buf_offset:	write offset in @buf
- * @buf_size:	size of current @buf
- * @open_ack:	completed once remote has acked the open-request
- * @open_req:	completed once open-request has been received
- */
-struct glink_channel {
-	struct rpmsg_endpoint ept;
-
-	struct rpmsg_device *rpdev;
-	struct qcom_glink *glink;
-
-	struct kref refcount;
-
-	spinlock_t recv_lock;
-
-	char *name;
-	unsigned int lcid;
-	unsigned int rcid;
-
-	void *buf;
-	int buf_offset;
-	int buf_size;
-
-	struct completion open_ack;
-	struct completion open_req;
-};
-
-#define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept)
-
-static const struct rpmsg_endpoint_ops glink_endpoint_ops;
-
-#define RPM_CMD_VERSION			0
-#define RPM_CMD_VERSION_ACK		1
-#define RPM_CMD_OPEN			2
-#define RPM_CMD_CLOSE			3
-#define RPM_CMD_OPEN_ACK		4
-#define RPM_CMD_TX_DATA			9
-#define RPM_CMD_CLOSE_ACK		11
-#define RPM_CMD_TX_DATA_CONT		12
-#define RPM_CMD_READ_NOTIF		13
-
-#define GLINK_FEATURE_INTENTLESS	BIT(1)
-
-static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
-						      const char *name)
-{
-	struct glink_channel *channel;
-
-	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
-	if (!channel)
-		return ERR_PTR(-ENOMEM);
-
-	/* Setup glink internal glink_channel data */
-	spin_lock_init(&channel->recv_lock);
-	channel->glink = glink;
-	channel->name = kstrdup(name, GFP_KERNEL);
-
-	init_completion(&channel->open_req);
-	init_completion(&channel->open_ack);
-
-	kref_init(&channel->refcount);
-
-	return channel;
-}
-
-static void qcom_glink_channel_release(struct kref *ref)
-{
-	struct glink_channel *channel = container_of(ref, struct glink_channel,
-						     refcount);
-
-	kfree(channel->name);
-	kfree(channel);
-}
-
 static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
 {
 	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
@@ -247,11 +76,6 @@ static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
 		return head - tail;
 }
 
-static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
-{
-	return glink->rx_pipe->avail(glink->rx_pipe);
-}
-
 static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
 			      void *data, size_t count)
 {
@@ -273,12 +97,6 @@ static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
 	}
 }
 
-static void qcom_glink_rx_peak(struct qcom_glink *glink,
-			       void *data, size_t count)
-{
-	glink->rx_pipe->peak(glink->rx_pipe, data, count);
-}
-
 static void glink_rpm_rx_advance(struct qcom_glink_pipe *glink_pipe,
 				 size_t count)
 {
@@ -294,11 +112,6 @@ static void glink_rpm_rx_advance(struct qcom_glink_pipe *glink_pipe,
 	writel(tail, pipe->tail);
 }
 
-static void qcom_glink_rx_advance(struct qcom_glink *glink, size_t count)
-{
-	glink->rx_pipe->advance(glink->rx_pipe, count);
-}
-
 static size_t glink_rpm_tx_avail(struct qcom_glink_pipe *glink_pipe)
 {
 	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
@@ -314,11 +127,6 @@ static size_t glink_rpm_tx_avail(struct qcom_glink_pipe *glink_pipe)
 		return tail - head;
 }
 
-static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
-{
-	return glink->tx_pipe->avail(glink->tx_pipe);
-}
-
 static unsigned int glink_rpm_tx_write_one(struct glink_rpm_pipe *pipe,
 					   unsigned int head,
 					   const void *data, size_t count)
@@ -356,731 +164,6 @@ static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
 	writel(head, pipe->head);
 }
 
-static void qcom_glink_tx_write(struct qcom_glink *glink,
-				const void *hdr, size_t hlen,
-				const void *data, size_t dlen)
-{
-	glink->tx_pipe->write(glink->tx_pipe, hdr, hlen, data, dlen);
-}
-
-static int qcom_glink_tx(struct qcom_glink *glink,
-			 const void *hdr, size_t hlen,
-			const void *data, size_t dlen, bool wait)
-{
-	unsigned int tlen = hlen + dlen;
-	int ret;
-
-	/* Reject packets that are too big */
-	if (tlen >= glink->tx_pipe->length)
-		return -EINVAL;
-
-	if (WARN(tlen % 8, "Unaligned TX request"))
-		return -EINVAL;
-
-	ret = mutex_lock_interruptible(&glink->tx_lock);
-	if (ret)
-		return ret;
-
-	while (qcom_glink_tx_avail(glink) < tlen) {
-		if (!wait) {
-			ret = -ENOMEM;
-			goto out;
-		}
-
-		msleep(10);
-	}
-
-	qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
-
-	mbox_send_message(glink->mbox_chan, NULL);
-	mbox_client_txdone(glink->mbox_chan, 0);
-
-out:
-	mutex_unlock(&glink->tx_lock);
-
-	return ret;
-}
-
-static int qcom_glink_send_version(struct qcom_glink *glink)
-{
-	struct glink_msg msg;
-
-	msg.cmd = cpu_to_le16(RPM_CMD_VERSION);
-	msg.param1 = cpu_to_le16(1);
-	msg.param2 = cpu_to_le32(GLINK_FEATURE_INTENTLESS);
-
-	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
-}
-
-static void qcom_glink_send_version_ack(struct qcom_glink *glink)
-{
-	struct glink_msg msg;
-
-	msg.cmd = cpu_to_le16(RPM_CMD_VERSION_ACK);
-	msg.param1 = cpu_to_le16(1);
-	msg.param2 = cpu_to_le32(0);
-
-	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
-}
-
-static void qcom_glink_send_open_ack(struct qcom_glink *glink,
-				     struct glink_channel *channel)
-{
-	struct glink_msg msg;
-
-	msg.cmd = cpu_to_le16(RPM_CMD_OPEN_ACK);
-	msg.param1 = cpu_to_le16(channel->rcid);
-	msg.param2 = cpu_to_le32(0);
-
-	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
-}
-
-/**
- * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
- * @glink:
- * @channel:
- *
- * Allocates a local channel id and sends a RPM_CMD_OPEN message to the remote.
- * Will return with refcount held, regardless of outcome.
- *
- * Returns 0 on success, negative errno otherwise.
- */
-static int qcom_glink_send_open_req(struct qcom_glink *glink,
-				    struct glink_channel *channel)
-{
-	struct {
-		struct glink_msg msg;
-		u8 name[GLINK_NAME_SIZE];
-	} __packed req;
-	int name_len = strlen(channel->name) + 1;
-	int req_len = ALIGN(sizeof(req.msg) + name_len, 8);
-	int ret;
-
-	kref_get(&channel->refcount);
-
-	mutex_lock(&glink->idr_lock);
-	ret = idr_alloc_cyclic(&glink->lcids, channel,
-			       RPM_GLINK_CID_MIN, RPM_GLINK_CID_MAX, GFP_KERNEL);
-	mutex_unlock(&glink->idr_lock);
-	if (ret < 0)
-		return ret;
-
-	channel->lcid = ret;
-
-	req.msg.cmd = cpu_to_le16(RPM_CMD_OPEN);
-	req.msg.param1 = cpu_to_le16(channel->lcid);
-	req.msg.param2 = cpu_to_le32(name_len);
-	strcpy(req.name, channel->name);
-
-	ret = qcom_glink_tx(glink, &req, req_len, NULL, 0, true);
-	if (ret)
-		goto remove_idr;
-
-	return 0;
-
-remove_idr:
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->lcids, channel->lcid);
-	channel->lcid = 0;
-	mutex_unlock(&glink->idr_lock);
-
-	return ret;
-}
-
-static void qcom_glink_send_close_req(struct qcom_glink *glink,
-				      struct glink_channel *channel)
-{
-	struct glink_msg req;
-
-	req.cmd = cpu_to_le16(RPM_CMD_CLOSE);
-	req.param1 = cpu_to_le16(channel->lcid);
-	req.param2 = 0;
-
-	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
-}
-
-static void qcom_glink_send_close_ack(struct qcom_glink *glink,
-				      unsigned int rcid)
-{
-	struct glink_msg req;
-
-	req.cmd = cpu_to_le16(RPM_CMD_CLOSE_ACK);
-	req.param1 = cpu_to_le16(rcid);
-	req.param2 = 0;
-
-	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
-}
-
-static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
-{
-	struct glink_defer_cmd *dcmd;
-
-	extra = ALIGN(extra, 8);
-
-	if (qcom_glink_rx_avail(glink) < sizeof(struct glink_msg) + extra) {
-		dev_dbg(glink->dev, "Insufficient data in rx fifo");
-		return -ENXIO;
-	}
-
-	dcmd = kzalloc(sizeof(*dcmd) + extra, GFP_ATOMIC);
-	if (!dcmd)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&dcmd->node);
-
-	qcom_glink_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
-
-	spin_lock(&glink->rx_lock);
-	list_add_tail(&dcmd->node, &glink->rx_queue);
-	spin_unlock(&glink->rx_lock);
-
-	schedule_work(&glink->rx_work);
-	qcom_glink_rx_advance(glink, sizeof(dcmd->msg) + extra);
-
-	return 0;
-}
-
-static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
-{
-	struct glink_channel *channel;
-	struct {
-		struct glink_msg msg;
-		__le32 chunk_size;
-		__le32 left_size;
-	} __packed hdr;
-	unsigned int chunk_size;
-	unsigned int left_size;
-	unsigned int rcid;
-
-	if (avail < sizeof(hdr)) {
-		dev_dbg(glink->dev, "Not enough data in fifo\n");
-		return -EAGAIN;
-	}
-
-	qcom_glink_rx_peak(glink, &hdr, sizeof(hdr));
-	chunk_size = le32_to_cpu(hdr.chunk_size);
-	left_size = le32_to_cpu(hdr.left_size);
-
-	if (avail < sizeof(hdr) + chunk_size) {
-		dev_dbg(glink->dev, "Payload not yet in fifo\n");
-		return -EAGAIN;
-	}
-
-	if (WARN(chunk_size % 4, "Incoming data must be word aligned\n"))
-		return -EINVAL;
-
-	rcid = le16_to_cpu(hdr.msg.param1);
-	channel = idr_find(&glink->rcids, rcid);
-	if (!channel) {
-		dev_dbg(glink->dev, "Data on non-existing channel\n");
-
-		/* Drop the message */
-		qcom_glink_rx_advance(glink,
-				      ALIGN(sizeof(hdr) + chunk_size, 8));
-		return 0;
-	}
-
-	/* Might have an ongoing, fragmented, message to append */
-	if (!channel->buf) {
-		channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
-		if (!channel->buf)
-			return -ENOMEM;
-
-		channel->buf_size = chunk_size + left_size;
-		channel->buf_offset = 0;
-	}
-
-	qcom_glink_rx_advance(glink, sizeof(hdr));
-
-	if (channel->buf_size - channel->buf_offset < chunk_size) {
-		dev_err(glink->dev, "Insufficient space in input buffer\n");
-
-		/* The packet header lied, drop payload */
-		qcom_glink_rx_advance(glink, chunk_size);
-		return -ENOMEM;
-	}
-
-	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
-			   chunk_size);
-	channel->buf_offset += chunk_size;
-
-	/* Handle message when no fragments remain to be received */
-	if (!left_size) {
-		spin_lock(&channel->recv_lock);
-		if (channel->ept.cb) {
-			channel->ept.cb(channel->ept.rpdev,
-					channel->buf,
-					channel->buf_offset,
-					channel->ept.priv,
-					RPMSG_ADDR_ANY);
-		}
-		spin_unlock(&channel->recv_lock);
-
-		kfree(channel->buf);
-		channel->buf = NULL;
-		channel->buf_size = 0;
-	}
-
-	/* Each message starts at 8 byte aligned address */
-	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
-
-	return 0;
-}
-
-static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
-{
-	struct glink_channel *channel;
-
-	channel = idr_find(&glink->lcids, lcid);
-	if (!channel) {
-		dev_err(glink->dev, "Invalid open ack packet\n");
-		return -EINVAL;
-	}
-
-	complete(&channel->open_ack);
-
-	return 0;
-}
-
-static irqreturn_t qcom_glink_intr(int irq, void *data)
-{
-	struct qcom_glink *glink = data;
-	struct glink_msg msg;
-	unsigned int param1;
-	unsigned int param2;
-	unsigned int avail;
-	unsigned int cmd;
-	int ret;
-
-	for (;;) {
-		avail = qcom_glink_rx_avail(glink);
-		if (avail < sizeof(msg))
-			break;
-
-		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
-
-		cmd = le16_to_cpu(msg.cmd);
-		param1 = le16_to_cpu(msg.param1);
-		param2 = le32_to_cpu(msg.param2);
-
-		switch (cmd) {
-		case RPM_CMD_VERSION:
-		case RPM_CMD_VERSION_ACK:
-		case RPM_CMD_CLOSE:
-		case RPM_CMD_CLOSE_ACK:
-			ret = qcom_glink_rx_defer(glink, 0);
-			break;
-		case RPM_CMD_OPEN_ACK:
-			ret = qcom_glink_rx_open_ack(glink, param1);
-			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
-			break;
-		case RPM_CMD_OPEN:
-			ret = qcom_glink_rx_defer(glink, param2);
-			break;
-		case RPM_CMD_TX_DATA:
-		case RPM_CMD_TX_DATA_CONT:
-			ret = qcom_glink_rx_data(glink, avail);
-			break;
-		case RPM_CMD_READ_NOTIF:
-			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
-
-			mbox_send_message(glink->mbox_chan, NULL);
-			mbox_client_txdone(glink->mbox_chan, 0);
-
-			ret = 0;
-			break;
-		default:
-			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
-			ret = -EINVAL;
-			break;
-		}
-
-		if (ret)
-			break;
-	}
-
-	return IRQ_HANDLED;
-}
-
-/* Locally initiated rpmsg_create_ept */
-static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
-						     const char *name)
-{
-	struct glink_channel *channel;
-	int ret;
-
-	channel = qcom_glink_alloc_channel(glink, name);
-	if (IS_ERR(channel))
-		return ERR_CAST(channel);
-
-	ret = qcom_glink_send_open_req(glink, channel);
-	if (ret)
-		goto release_channel;
-
-	ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ);
-	if (!ret)
-		goto err_timeout;
-
-	ret = wait_for_completion_timeout(&channel->open_req, 5 * HZ);
-	if (!ret)
-		goto err_timeout;
-
-	qcom_glink_send_open_ack(glink, channel);
-
-	return channel;
-
-err_timeout:
-	/* qcom_glink_send_open_req() did register the channel in lcids*/
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->lcids, channel->lcid);
-	mutex_unlock(&glink->idr_lock);
-
-release_channel:
-	/* Release qcom_glink_send_open_req() reference */
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-	/* Release qcom_glink_alloc_channel() reference */
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-
-	return ERR_PTR(-ETIMEDOUT);
-}
-
-/* Remote initiated rpmsg_create_ept */
-static int qcom_glink_create_remote(struct qcom_glink *glink,
-				    struct glink_channel *channel)
-{
-	int ret;
-
-	qcom_glink_send_open_ack(glink, channel);
-
-	ret = qcom_glink_send_open_req(glink, channel);
-	if (ret)
-		goto close_link;
-
-	ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ);
-	if (!ret) {
-		ret = -ETIMEDOUT;
-		goto close_link;
-	}
-
-	return 0;
-
-close_link:
-	/*
-	 * Send a close request to "undo" our open-ack. The close-ack will
-	 * release the last reference.
-	 */
-	qcom_glink_send_close_req(glink, channel);
-
-	/* Release qcom_glink_send_open_req() reference */
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-
-	return ret;
-}
-
-static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
-						    rpmsg_rx_cb_t cb,
-						    void *priv,
-						    struct rpmsg_channel_info
-						    chinfo)
-{
-	struct glink_channel *parent = to_glink_channel(rpdev->ept);
-	struct glink_channel *channel;
-	struct qcom_glink *glink = parent->glink;
-	struct rpmsg_endpoint *ept;
-	const char *name = chinfo.name;
-	int cid;
-	int ret;
-
-	idr_for_each_entry(&glink->rcids, channel, cid) {
-		if (!strcmp(channel->name, name))
-			break;
-	}
-
-	if (!channel) {
-		channel = qcom_glink_create_local(glink, name);
-		if (IS_ERR(channel))
-			return NULL;
-	} else {
-		ret = qcom_glink_create_remote(glink, channel);
-		if (ret)
-			return NULL;
-	}
-
-	ept = &channel->ept;
-	ept->rpdev = rpdev;
-	ept->cb = cb;
-	ept->priv = priv;
-	ept->ops = &glink_endpoint_ops;
-
-	return ept;
-}
-
-static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
-{
-	struct glink_channel *channel = to_glink_channel(ept);
-	struct qcom_glink *glink = channel->glink;
-	unsigned long flags;
-
-	spin_lock_irqsave(&channel->recv_lock, flags);
-	channel->ept.cb = NULL;
-	spin_unlock_irqrestore(&channel->recv_lock, flags);
-
-	/* Decouple the potential rpdev from the channel */
-	channel->rpdev = NULL;
-
-	qcom_glink_send_close_req(glink, channel);
-}
-
-static int __qcom_glink_send(struct glink_channel *channel,
-			     void *data, int len, bool wait)
-{
-	struct qcom_glink *glink = channel->glink;
-	struct {
-		struct glink_msg msg;
-		__le32 chunk_size;
-		__le32 left_size;
-	} __packed req;
-
-	if (WARN(len % 8, "RPM GLINK expects 8 byte aligned messages\n"))
-		return -EINVAL;
-
-	req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
-	req.msg.param1 = cpu_to_le16(channel->lcid);
-	req.msg.param2 = cpu_to_le32(channel->rcid);
-	req.chunk_size = cpu_to_le32(len);
-	req.left_size = cpu_to_le32(0);
-
-	return qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
-}
-
-static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len)
-{
-	struct glink_channel *channel = to_glink_channel(ept);
-
-	return __qcom_glink_send(channel, data, len, true);
-}
-
-static int qcom_glink_trysend(struct rpmsg_endpoint *ept, void *data, int len)
-{
-	struct glink_channel *channel = to_glink_channel(ept);
-
-	return __qcom_glink_send(channel, data, len, false);
-}
-
-/*
- * Finds the device_node for the glink child interested in this channel.
- */
-static struct device_node *qcom_glink_match_channel(struct device_node *node,
-						    const char *channel)
-{
-	struct device_node *child;
-	const char *name;
-	const char *key;
-	int ret;
-
-	for_each_available_child_of_node(node, child) {
-		key = "qcom,glink-channels";
-		ret = of_property_read_string(child, key, &name);
-		if (ret)
-			continue;
-
-		if (strcmp(name, channel) == 0)
-			return child;
-	}
-
-	return NULL;
-}
-
-static const struct rpmsg_device_ops glink_device_ops = {
-	.create_ept = qcom_glink_create_ept,
-};
-
-static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
-	.destroy_ept = qcom_glink_destroy_ept,
-	.send = qcom_glink_send,
-	.trysend = qcom_glink_trysend,
-};
-
-static void qcom_glink_rpdev_release(struct device *dev)
-{
-	struct rpmsg_device *rpdev = to_rpmsg_device(dev);
-	struct glink_channel *channel = to_glink_channel(rpdev->ept);
-
-	channel->rpdev = NULL;
-	kfree(rpdev);
-}
-
-static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
-			      char *name)
-{
-	struct glink_channel *channel;
-	struct rpmsg_device *rpdev;
-	bool create_device = false;
-	int lcid;
-	int ret;
-	struct device_node *node;
-
-	idr_for_each_entry(&glink->lcids, channel, lcid) {
-		if (!strcmp(channel->name, name))
-			break;
-	}
-
-	if (!channel) {
-		channel = qcom_glink_alloc_channel(glink, name);
-		if (IS_ERR(channel))
-			return PTR_ERR(channel);
-
-		/* The opening dance was initiated by the remote */
-		create_device = true;
-	}
-
-	mutex_lock(&glink->idr_lock);
-	ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_KERNEL);
-	if (ret < 0) {
-		dev_err(glink->dev, "Unable to insert channel into rcid list\n");
-		mutex_unlock(&glink->idr_lock);
-		goto free_channel;
-	}
-	channel->rcid = ret;
-	mutex_unlock(&glink->idr_lock);
-
-	complete(&channel->open_req);
-
-	if (create_device) {
-		rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL);
-		if (!rpdev) {
-			ret = -ENOMEM;
-			goto rcid_remove;
-		}
-
-		rpdev->ept = &channel->ept;
-		strncpy(rpdev->id.name, name, RPMSG_NAME_SIZE);
-		rpdev->src = RPMSG_ADDR_ANY;
-		rpdev->dst = RPMSG_ADDR_ANY;
-		rpdev->ops = &glink_device_ops;
-
-		node = qcom_glink_match_channel(glink->dev->of_node, name);
-		rpdev->dev.of_node = node;
-		rpdev->dev.parent = glink->dev;
-		rpdev->dev.release = qcom_glink_rpdev_release;
-
-		ret = rpmsg_register_device(rpdev);
-		if (ret)
-			goto free_rpdev;
-
-		channel->rpdev = rpdev;
-	}
-
-	return 0;
-
-free_rpdev:
-	kfree(rpdev);
-rcid_remove:
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->rcids, channel->rcid);
-	channel->rcid = 0;
-	mutex_unlock(&glink->idr_lock);
-free_channel:
-	/* Release the reference, iff we took it */
-	if (create_device)
-		kref_put(&channel->refcount, qcom_glink_channel_release);
-
-	return ret;
-}
-
-static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
-{
-	struct rpmsg_channel_info chinfo;
-	struct glink_channel *channel;
-
-	channel = idr_find(&glink->rcids, rcid);
-	if (WARN(!channel, "close request on unknown channel\n"))
-		return;
-
-	if (channel->rpdev) {
-		strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
-		chinfo.src = RPMSG_ADDR_ANY;
-		chinfo.dst = RPMSG_ADDR_ANY;
-
-		rpmsg_unregister_device(glink->dev, &chinfo);
-	}
-
-	qcom_glink_send_close_ack(glink, channel->rcid);
-
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->rcids, channel->rcid);
-	channel->rcid = 0;
-	mutex_unlock(&glink->idr_lock);
-
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-}
-
-static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
-{
-	struct glink_channel *channel;
-
-	channel = idr_find(&glink->lcids, lcid);
-	if (WARN(!channel, "close ack on unknown channel\n"))
-		return;
-
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->lcids, channel->lcid);
-	channel->lcid = 0;
-	mutex_unlock(&glink->idr_lock);
-
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-}
-
-static void qcom_glink_work(struct work_struct *work)
-{
-	struct qcom_glink *glink = container_of(work, struct qcom_glink,
-						rx_work);
-	struct glink_defer_cmd *dcmd;
-	struct glink_msg *msg;
-	unsigned long flags;
-	unsigned int param1;
-	unsigned int param2;
-	unsigned int cmd;
-
-	for (;;) {
-		spin_lock_irqsave(&glink->rx_lock, flags);
-		if (list_empty(&glink->rx_queue)) {
-			spin_unlock_irqrestore(&glink->rx_lock, flags);
-			break;
-		}
-		dcmd = list_first_entry(&glink->rx_queue, struct glink_defer_cmd, node);
-		list_del(&dcmd->node);
-		spin_unlock_irqrestore(&glink->rx_lock, flags);
-
-		msg = &dcmd->msg;
-		cmd = le16_to_cpu(msg->cmd);
-		param1 = le16_to_cpu(msg->param1);
-		param2 = le32_to_cpu(msg->param2);
-
-		switch (cmd) {
-		case RPM_CMD_VERSION:
-			qcom_glink_send_version_ack(glink);
-			break;
-		case RPM_CMD_VERSION_ACK:
-			break;
-		case RPM_CMD_OPEN:
-			qcom_glink_rx_open(glink, param1, msg->data);
-			break;
-		case RPM_CMD_CLOSE:
-			qcom_glink_rx_close(glink, param1);
-			break;
-		case RPM_CMD_CLOSE_ACK:
-			qcom_glink_rx_close_ack(glink, param1);
-			break;
-		default:
-			WARN(1, "Unknown defer object %d\n", cmd);
-			break;
-		}
-
-		kfree(dcmd);
-	}
-}
-
 static int glink_rpm_parse_toc(struct device *dev,
 			       void __iomem *msg_ram,
 			       size_t msg_ram_size,
@@ -1156,56 +239,6 @@ static int glink_rpm_parse_toc(struct device *dev,
 	return -EINVAL;
 }
 
-struct qcom_glink *qcom_glink_native_probe(struct device *dev,
-					   struct qcom_glink_pipe *rx,
-					   struct qcom_glink_pipe *tx)
-{
-	int irq;
-	int ret;
-	struct qcom_glink *glink;
-
-	glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
-	if (!glink)
-		return ERR_PTR(-ENOMEM);
-
-	glink->dev = dev;
-	glink->tx_pipe = tx;
-	glink->rx_pipe = rx;
-
-	mutex_init(&glink->tx_lock);
-	spin_lock_init(&glink->rx_lock);
-	INIT_LIST_HEAD(&glink->rx_queue);
-	INIT_WORK(&glink->rx_work, qcom_glink_work);
-
-	mutex_init(&glink->idr_lock);
-	idr_init(&glink->lcids);
-	idr_init(&glink->rcids);
-
-	glink->mbox_client.dev = dev;
-	glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
-	if (IS_ERR(glink->mbox_chan)) {
-		if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
-			dev_err(dev, "failed to acquire IPC channel\n");
-		return ERR_CAST(glink->mbox_chan);
-	}
-
-	irq = of_irq_get(dev->of_node, 0);
-	ret = devm_request_irq(dev, irq,
-			       qcom_glink_intr,
-			       IRQF_NO_SUSPEND | IRQF_SHARED,
-			       "glink-native", glink);
-	if (ret) {
-		dev_err(dev, "failed to request IRQ\n");
-		return ERR_PTR(ret);
-	}
-
-	ret = qcom_glink_send_version(glink);
-	if (ret)
-		return ERR_PTR(ret);
-
-	return glink;
-}
-
 static int glink_rpm_probe(struct platform_device *pdev)
 {
 	struct qcom_glink *glink;
@@ -1259,33 +292,11 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int glink_rpm_remove_device(struct device *dev, void *data)
-{
-	device_unregister(dev);
-
-	return 0;
-}
-
 static int glink_rpm_remove(struct platform_device *pdev)
 {
 	struct qcom_glink *glink = platform_get_drvdata(pdev);
-	struct glink_channel *channel;
-	int cid;
-	int ret;
-
-	disable_irq(glink->irq);
-	cancel_work_sync(&glink->rx_work);
-
-	ret = device_for_each_child(glink->dev, NULL, glink_rpm_remove_device);
-	if (ret)
-		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
-
-	/* Release any defunct local channels, waiting for close-ack */
-	idr_for_each_entry(&glink->lcids, channel, cid)
-		kref_put(&channel->refcount, qcom_glink_channel_release);
 
-	idr_destroy(&glink->lcids);
-	idr_destroy(&glink->rcids);
+	qcom_glink_native_remove(glink);
 
 	return 0;
 }
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 04/18] rpmsg: glink: Move the common glink protocol implementation to glink_native.c
@ 2017-08-16 17:18   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: Bjorn Andersson <bjorn.andersson@linaro.org>

Move the common part of glink core protocol implementation to
glink_native.c that can be shared with the smem based glink
transport in the later patches.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/Kconfig             |    6 +-
 drivers/rpmsg/Makefile            |    1 +
 drivers/rpmsg/qcom_glink_native.c | 1014 +++++++++++++++++++++++++++++++++++++
 drivers/rpmsg/qcom_glink_native.h |   38 ++
 drivers/rpmsg/qcom_glink_rpm.c    |  995 +-----------------------------------
 5 files changed, 1061 insertions(+), 993 deletions(-)
 create mode 100644 drivers/rpmsg/qcom_glink_native.c
 create mode 100644 drivers/rpmsg/qcom_glink_native.h

diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index 2a5d2b4..ac33688 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -13,9 +13,13 @@ config RPMSG_CHAR
 	  in /dev. They make it possible for user-space programs to send and
 	  receive rpmsg packets.
 
+config RPMSG_QCOM_GLINK_NATIVE
+	tristate
+	select RPMSG
+
 config RPMSG_QCOM_GLINK_RPM
 	tristate "Qualcomm RPM Glink driver"
-	select RPMSG
+        select RPMSG_QCOM_GLINK_NATIVE
 	depends on HAS_IOMEM
 	depends on MAILBOX
 	help
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 28cc190..09a756c 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_RPMSG)		+= rpmsg_core.o
 obj-$(CONFIG_RPMSG_CHAR)	+= rpmsg_char.o
 obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
+obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o
 obj-$(CONFIG_RPMSG_QCOM_SMD)	+= qcom_smd.o
 obj-$(CONFIG_RPMSG_VIRTIO)	+= virtio_rpmsg_bus.o
diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
new file mode 100644
index 0000000..04afbb2
--- /dev/null
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -0,0 +1,1014 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/mailbox_client.h>
+
+#include "rpmsg_internal.h"
+#include "qcom_glink_native.h"
+
+#define GLINK_NAME_SIZE		32
+
+#define RPM_GLINK_CID_MIN	1
+#define RPM_GLINK_CID_MAX	65536
+
+struct glink_msg {
+	__le16 cmd;
+	__le16 param1;
+	__le32 param2;
+	u8 data[];
+} __packed;
+
+/**
+ * struct glink_defer_cmd - deferred incoming control message
+ * @node:	list node
+ * @msg:	message header
+ * data:	payload of the message
+ *
+ * Copy of a received control message, to be added to @rx_queue and processed
+ * by @rx_work of @glink_rpm.
+ */
+struct glink_defer_cmd {
+	struct list_head node;
+
+	struct glink_msg msg;
+	u8 data[];
+};
+
+/**
+ * struct glink_rpm - driver context, relates to one remote subsystem
+ * @dev:	reference to the associated struct device
+ * @doorbell:	"rpm_hlos" ipc doorbell
+ * @rx_pipe:	pipe object for receive FIFO
+ * @tx_pipe:	pipe object for transmit FIFO
+ * @irq:	IRQ for signaling incoming events
+ * @rx_work:	worker for handling received control messages
+ * @rx_lock:	protects the @rx_queue
+ * @rx_queue:	queue of received control messages to be processed in @rx_work
+ * @tx_lock:	synchronizes operations on the tx fifo
+ * @idr_lock:	synchronizes @lcids and @rcids modifications
+ * @lcids:	idr of all channels with a known local channel id
+ * @rcids:	idr of all channels with a known remote channel id
+ */
+struct qcom_glink {
+	struct device *dev;
+
+	struct mbox_client mbox_client;
+	struct mbox_chan *mbox_chan;
+
+	struct qcom_glink_pipe *rx_pipe;
+	struct qcom_glink_pipe *tx_pipe;
+
+	int irq;
+
+	struct work_struct rx_work;
+	spinlock_t rx_lock;
+	struct list_head rx_queue;
+
+	struct mutex tx_lock;
+
+	struct mutex idr_lock;
+	struct idr lcids;
+	struct idr rcids;
+};
+
+enum {
+	GLINK_STATE_CLOSED,
+	GLINK_STATE_OPENING,
+	GLINK_STATE_OPEN,
+	GLINK_STATE_CLOSING,
+};
+
+/**
+ * struct glink_channel - internal representation of a channel
+ * @rpdev:	rpdev reference, only used for primary endpoints
+ * @ept:	rpmsg endpoint this channel is associated with
+ * @glink:	qcom_glink context handle
+ * @refcount:	refcount for the channel object
+ * @recv_lock:	guard for @ept.cb
+ * @name:	unique channel name/identifier
+ * @lcid:	channel id, in local space
+ * @rcid:	channel id, in remote space
+ * @buf:	receive buffer, for gathering fragments
+ * @buf_offset:	write offset in @buf
+ * @buf_size:	size of current @buf
+ * @open_ack:	completed once remote has acked the open-request
+ * @open_req:	completed once open-request has been received
+ */
+struct glink_channel {
+	struct rpmsg_endpoint ept;
+
+	struct rpmsg_device *rpdev;
+	struct qcom_glink *glink;
+
+	struct kref refcount;
+
+	spinlock_t recv_lock;
+
+	char *name;
+	unsigned int lcid;
+	unsigned int rcid;
+
+	void *buf;
+	int buf_offset;
+	int buf_size;
+
+	struct completion open_ack;
+	struct completion open_req;
+};
+
+#define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept)
+
+static const struct rpmsg_endpoint_ops glink_endpoint_ops;
+
+#define RPM_CMD_VERSION			0
+#define RPM_CMD_VERSION_ACK		1
+#define RPM_CMD_OPEN			2
+#define RPM_CMD_CLOSE			3
+#define RPM_CMD_OPEN_ACK		4
+#define RPM_CMD_TX_DATA			9
+#define RPM_CMD_CLOSE_ACK		11
+#define RPM_CMD_TX_DATA_CONT		12
+#define RPM_CMD_READ_NOTIF		13
+
+#define GLINK_FEATURE_INTENTLESS	BIT(1)
+
+static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
+						      const char *name)
+{
+	struct glink_channel *channel;
+
+	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+	if (!channel)
+		return ERR_PTR(-ENOMEM);
+
+	/* Setup glink internal glink_channel data */
+	spin_lock_init(&channel->recv_lock);
+	channel->glink = glink;
+	channel->name = kstrdup(name, GFP_KERNEL);
+
+	init_completion(&channel->open_req);
+	init_completion(&channel->open_ack);
+
+	kref_init(&channel->refcount);
+
+	return channel;
+}
+
+static void qcom_glink_channel_release(struct kref *ref)
+{
+	struct glink_channel *channel = container_of(ref, struct glink_channel,
+						     refcount);
+
+	kfree(channel->name);
+	kfree(channel);
+}
+
+static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
+{
+	return glink->rx_pipe->avail(glink->rx_pipe);
+}
+
+static void qcom_glink_rx_peak(struct qcom_glink *glink,
+			       void *data, size_t count)
+{
+	glink->rx_pipe->peak(glink->rx_pipe, data, count);
+}
+
+static void qcom_glink_rx_advance(struct qcom_glink *glink, size_t count)
+{
+	glink->rx_pipe->advance(glink->rx_pipe, count);
+}
+
+static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
+{
+	return glink->tx_pipe->avail(glink->tx_pipe);
+}
+
+static void qcom_glink_tx_write(struct qcom_glink *glink,
+				const void *hdr, size_t hlen,
+				const void *data, size_t dlen)
+{
+	glink->tx_pipe->write(glink->tx_pipe, hdr, hlen, data, dlen);
+}
+
+static int qcom_glink_tx(struct qcom_glink *glink,
+			 const void *hdr, size_t hlen,
+			 const void *data, size_t dlen, bool wait)
+{
+	unsigned int tlen = hlen + dlen;
+	int ret;
+
+	/* Reject packets that are too big */
+	if (tlen >= glink->tx_pipe->length)
+		return -EINVAL;
+
+	if (WARN(tlen % 8, "Unaligned TX request"))
+		return -EINVAL;
+
+	ret = mutex_lock_interruptible(&glink->tx_lock);
+	if (ret)
+		return ret;
+
+	while (qcom_glink_tx_avail(glink) < tlen) {
+		if (!wait) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		msleep(10);
+	}
+
+	qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
+
+	mbox_send_message(glink->mbox_chan, NULL);
+	mbox_client_txdone(glink->mbox_chan, 0);
+
+out:
+	mutex_unlock(&glink->tx_lock);
+
+	return ret;
+}
+
+static int qcom_glink_send_version(struct qcom_glink *glink)
+{
+	struct glink_msg msg;
+
+	msg.cmd = cpu_to_le16(RPM_CMD_VERSION);
+	msg.param1 = cpu_to_le16(1);
+	msg.param2 = cpu_to_le32(GLINK_FEATURE_INTENTLESS);
+
+	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+}
+
+static void qcom_glink_send_version_ack(struct qcom_glink *glink)
+{
+	struct glink_msg msg;
+
+	msg.cmd = cpu_to_le16(RPM_CMD_VERSION_ACK);
+	msg.param1 = cpu_to_le16(1);
+	msg.param2 = cpu_to_le32(0);
+
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+}
+
+static void qcom_glink_send_open_ack(struct qcom_glink *glink,
+				     struct glink_channel *channel)
+{
+	struct glink_msg msg;
+
+	msg.cmd = cpu_to_le16(RPM_CMD_OPEN_ACK);
+	msg.param1 = cpu_to_le16(channel->rcid);
+	msg.param2 = cpu_to_le32(0);
+
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+}
+
+/**
+ * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
+ * @glink:
+ * @channel:
+ *
+ * Allocates a local channel id and sends a RPM_CMD_OPEN message to the remote.
+ * Will return with refcount held, regardless of outcome.
+ *
+ * Returns 0 on success, negative errno otherwise.
+ */
+static int qcom_glink_send_open_req(struct qcom_glink *glink,
+				    struct glink_channel *channel)
+{
+	struct {
+		struct glink_msg msg;
+		u8 name[GLINK_NAME_SIZE];
+	} __packed req;
+	int name_len = strlen(channel->name) + 1;
+	int req_len = ALIGN(sizeof(req.msg) + name_len, 8);
+	int ret;
+
+	kref_get(&channel->refcount);
+
+	mutex_lock(&glink->idr_lock);
+	ret = idr_alloc_cyclic(&glink->lcids, channel,
+			       RPM_GLINK_CID_MIN, RPM_GLINK_CID_MAX,
+			       GFP_KERNEL);
+	mutex_unlock(&glink->idr_lock);
+	if (ret < 0)
+		return ret;
+
+	channel->lcid = ret;
+
+	req.msg.cmd = cpu_to_le16(RPM_CMD_OPEN);
+	req.msg.param1 = cpu_to_le16(channel->lcid);
+	req.msg.param2 = cpu_to_le32(name_len);
+	strcpy(req.name, channel->name);
+
+	ret = qcom_glink_tx(glink, &req, req_len, NULL, 0, true);
+	if (ret)
+		goto remove_idr;
+
+	return 0;
+
+remove_idr:
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->lcids, channel->lcid);
+	channel->lcid = 0;
+	mutex_unlock(&glink->idr_lock);
+
+	return ret;
+}
+
+static void qcom_glink_send_close_req(struct qcom_glink *glink,
+				      struct glink_channel *channel)
+{
+	struct glink_msg req;
+
+	req.cmd = cpu_to_le16(RPM_CMD_CLOSE);
+	req.param1 = cpu_to_le16(channel->lcid);
+	req.param2 = 0;
+
+	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
+}
+
+static void qcom_glink_send_close_ack(struct qcom_glink *glink,
+				      unsigned int rcid)
+{
+	struct glink_msg req;
+
+	req.cmd = cpu_to_le16(RPM_CMD_CLOSE_ACK);
+	req.param1 = cpu_to_le16(rcid);
+	req.param2 = 0;
+
+	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
+}
+
+static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
+{
+	struct glink_defer_cmd *dcmd;
+
+	extra = ALIGN(extra, 8);
+
+	if (qcom_glink_rx_avail(glink) < sizeof(struct glink_msg) + extra) {
+		dev_dbg(glink->dev, "Insufficient data in rx fifo");
+		return -ENXIO;
+	}
+
+	dcmd = kzalloc(sizeof(*dcmd) + extra, GFP_ATOMIC);
+	if (!dcmd)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dcmd->node);
+
+	qcom_glink_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
+
+	spin_lock(&glink->rx_lock);
+	list_add_tail(&dcmd->node, &glink->rx_queue);
+	spin_unlock(&glink->rx_lock);
+
+	schedule_work(&glink->rx_work);
+	qcom_glink_rx_advance(glink, sizeof(dcmd->msg) + extra);
+
+	return 0;
+}
+
+static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
+{
+	struct glink_channel *channel;
+	struct {
+		struct glink_msg msg;
+		__le32 chunk_size;
+		__le32 left_size;
+	} __packed hdr;
+	unsigned int chunk_size;
+	unsigned int left_size;
+	unsigned int rcid;
+
+	if (avail < sizeof(hdr)) {
+		dev_dbg(glink->dev, "Not enough data in fifo\n");
+		return -EAGAIN;
+	}
+
+	qcom_glink_rx_peak(glink, &hdr, sizeof(hdr));
+	chunk_size = le32_to_cpu(hdr.chunk_size);
+	left_size = le32_to_cpu(hdr.left_size);
+
+	if (avail < sizeof(hdr) + chunk_size) {
+		dev_dbg(glink->dev, "Payload not yet in fifo\n");
+		return -EAGAIN;
+	}
+
+	if (WARN(chunk_size % 4, "Incoming data must be word aligned\n"))
+		return -EINVAL;
+
+	rcid = le16_to_cpu(hdr.msg.param1);
+	channel = idr_find(&glink->rcids, rcid);
+	if (!channel) {
+		dev_dbg(glink->dev, "Data on non-existing channel\n");
+
+		/* Drop the message */
+		qcom_glink_rx_advance(glink,
+				      ALIGN(sizeof(hdr) + chunk_size, 8));
+		return 0;
+	}
+
+	/* Might have an ongoing, fragmented, message to append */
+	if (!channel->buf) {
+		channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
+		if (!channel->buf)
+			return -ENOMEM;
+
+		channel->buf_size = chunk_size + left_size;
+		channel->buf_offset = 0;
+	}
+
+	qcom_glink_rx_advance(glink, sizeof(hdr));
+
+	if (channel->buf_size - channel->buf_offset < chunk_size) {
+		dev_err(glink->dev, "Insufficient space in input buffer\n");
+
+		/* The packet header lied, drop payload */
+		qcom_glink_rx_advance(glink, chunk_size);
+		return -ENOMEM;
+	}
+
+	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
+			   chunk_size);
+	channel->buf_offset += chunk_size;
+
+	/* Handle message when no fragments remain to be received */
+	if (!left_size) {
+		spin_lock(&channel->recv_lock);
+		if (channel->ept.cb) {
+			channel->ept.cb(channel->ept.rpdev,
+					channel->buf,
+					channel->buf_offset,
+					channel->ept.priv,
+					RPMSG_ADDR_ANY);
+		}
+		spin_unlock(&channel->recv_lock);
+
+		kfree(channel->buf);
+		channel->buf = NULL;
+		channel->buf_size = 0;
+	}
+
+	/* Each message starts at 8 byte aligned address */
+	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
+
+	return 0;
+}
+
+static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
+{
+	struct glink_channel *channel;
+
+	channel = idr_find(&glink->lcids, lcid);
+	if (!channel) {
+		dev_err(glink->dev, "Invalid open ack packet\n");
+		return -EINVAL;
+	}
+
+	complete(&channel->open_ack);
+
+	return 0;
+}
+
+static irqreturn_t qcom_glink_native_intr(int irq, void *data)
+{
+	struct qcom_glink *glink = data;
+	struct glink_msg msg;
+	unsigned int param1;
+	unsigned int param2;
+	unsigned int avail;
+	unsigned int cmd;
+	int ret;
+
+	for (;;) {
+		avail = qcom_glink_rx_avail(glink);
+		if (avail < sizeof(msg))
+			break;
+
+		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
+
+		cmd = le16_to_cpu(msg.cmd);
+		param1 = le16_to_cpu(msg.param1);
+		param2 = le32_to_cpu(msg.param2);
+
+		switch (cmd) {
+		case RPM_CMD_VERSION:
+		case RPM_CMD_VERSION_ACK:
+		case RPM_CMD_CLOSE:
+		case RPM_CMD_CLOSE_ACK:
+			ret = qcom_glink_rx_defer(glink, 0);
+			break;
+		case RPM_CMD_OPEN_ACK:
+			ret = qcom_glink_rx_open_ack(glink, param1);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			break;
+		case RPM_CMD_OPEN:
+			ret = qcom_glink_rx_defer(glink, param2);
+			break;
+		case RPM_CMD_TX_DATA:
+		case RPM_CMD_TX_DATA_CONT:
+			ret = qcom_glink_rx_data(glink, avail);
+			break;
+		case RPM_CMD_READ_NOTIF:
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+
+			mbox_send_message(glink->mbox_chan, NULL);
+			mbox_client_txdone(glink->mbox_chan, 0);
+
+			ret = 0;
+			break;
+		default:
+			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
+			ret = -EINVAL;
+			break;
+		}
+
+		if (ret)
+			break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* Locally initiated rpmsg_create_ept */
+static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
+						     const char *name)
+{
+	struct glink_channel *channel;
+	int ret;
+
+	channel = qcom_glink_alloc_channel(glink, name);
+	if (IS_ERR(channel))
+		return ERR_CAST(channel);
+
+	ret = qcom_glink_send_open_req(glink, channel);
+	if (ret)
+		goto release_channel;
+
+	ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ);
+	if (!ret)
+		goto err_timeout;
+
+	ret = wait_for_completion_timeout(&channel->open_req, 5 * HZ);
+	if (!ret)
+		goto err_timeout;
+
+	qcom_glink_send_open_ack(glink, channel);
+
+	return channel;
+
+err_timeout:
+	/* qcom_glink_send_open_req() did register the channel in lcids*/
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->lcids, channel->lcid);
+	mutex_unlock(&glink->idr_lock);
+
+release_channel:
+	/* Release qcom_glink_send_open_req() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+	/* Release qcom_glink_alloc_channel() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+
+	return ERR_PTR(-ETIMEDOUT);
+}
+
+/* Remote initiated rpmsg_create_ept */
+static int qcom_glink_create_remote(struct qcom_glink *glink,
+				    struct glink_channel *channel)
+{
+	int ret;
+
+	qcom_glink_send_open_ack(glink, channel);
+
+	ret = qcom_glink_send_open_req(glink, channel);
+	if (ret)
+		goto close_link;
+
+	ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ);
+	if (!ret) {
+		ret = -ETIMEDOUT;
+		goto close_link;
+	}
+
+	return 0;
+
+close_link:
+	/*
+	 * Send a close request to "undo" our open-ack. The close-ack will
+	 * release the last reference.
+	 */
+	qcom_glink_send_close_req(glink, channel);
+
+	/* Release qcom_glink_send_open_req() reference */
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+
+	return ret;
+}
+
+static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
+						    rpmsg_rx_cb_t cb,
+						    void *priv,
+						    struct rpmsg_channel_info
+									chinfo)
+{
+	struct glink_channel *parent = to_glink_channel(rpdev->ept);
+	struct glink_channel *channel;
+	struct qcom_glink *glink = parent->glink;
+	struct rpmsg_endpoint *ept;
+	const char *name = chinfo.name;
+	int cid;
+	int ret;
+
+	idr_for_each_entry(&glink->rcids, channel, cid) {
+		if (!strcmp(channel->name, name))
+			break;
+	}
+
+	if (!channel) {
+		channel = qcom_glink_create_local(glink, name);
+		if (IS_ERR(channel))
+			return NULL;
+	} else {
+		ret = qcom_glink_create_remote(glink, channel);
+		if (ret)
+			return NULL;
+	}
+
+	ept = &channel->ept;
+	ept->rpdev = rpdev;
+	ept->cb = cb;
+	ept->priv = priv;
+	ept->ops = &glink_endpoint_ops;
+
+	return ept;
+}
+
+static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
+{
+	struct glink_channel *channel = to_glink_channel(ept);
+	struct qcom_glink *glink = channel->glink;
+	unsigned long flags;
+
+	spin_lock_irqsave(&channel->recv_lock, flags);
+	channel->ept.cb = NULL;
+	spin_unlock_irqrestore(&channel->recv_lock, flags);
+
+	/* Decouple the potential rpdev from the channel */
+	channel->rpdev = NULL;
+
+	qcom_glink_send_close_req(glink, channel);
+}
+
+static int __qcom_glink_send(struct glink_channel *channel,
+			     void *data, int len, bool wait)
+{
+	struct qcom_glink *glink = channel->glink;
+	struct {
+		struct glink_msg msg;
+		__le32 chunk_size;
+		__le32 left_size;
+	} __packed req;
+
+	if (WARN(len % 8, "RPM GLINK expects 8 byte aligned messages\n"))
+		return -EINVAL;
+
+	req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
+	req.msg.param1 = cpu_to_le16(channel->lcid);
+	req.msg.param2 = cpu_to_le32(channel->rcid);
+	req.chunk_size = cpu_to_le32(len);
+	req.left_size = cpu_to_le32(0);
+
+	return qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
+}
+
+static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len)
+{
+	struct glink_channel *channel = to_glink_channel(ept);
+
+	return __qcom_glink_send(channel, data, len, true);
+}
+
+static int qcom_glink_trysend(struct rpmsg_endpoint *ept, void *data, int len)
+{
+	struct glink_channel *channel = to_glink_channel(ept);
+
+	return __qcom_glink_send(channel, data, len, false);
+}
+
+/*
+ * Finds the device_node for the glink child interested in this channel.
+ */
+static struct device_node *qcom_glink_match_channel(struct device_node *node,
+						    const char *channel)
+{
+	struct device_node *child;
+	const char *name;
+	const char *key;
+	int ret;
+
+	for_each_available_child_of_node(node, child) {
+		key = "qcom,glink-channels";
+		ret = of_property_read_string(child, key, &name);
+		if (ret)
+			continue;
+
+		if (strcmp(name, channel) == 0)
+			return child;
+	}
+
+	return NULL;
+}
+
+static const struct rpmsg_device_ops glink_device_ops = {
+	.create_ept = qcom_glink_create_ept,
+};
+
+static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
+	.destroy_ept = qcom_glink_destroy_ept,
+	.send = qcom_glink_send,
+	.trysend = qcom_glink_trysend,
+};
+
+static void qcom_glink_rpdev_release(struct device *dev)
+{
+	struct rpmsg_device *rpdev = to_rpmsg_device(dev);
+	struct glink_channel *channel = to_glink_channel(rpdev->ept);
+
+	channel->rpdev = NULL;
+	kfree(rpdev);
+}
+
+static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
+			      char *name)
+{
+	struct glink_channel *channel;
+	struct rpmsg_device *rpdev;
+	bool create_device = false;
+	struct device_node *node;
+	int lcid;
+	int ret;
+
+	idr_for_each_entry(&glink->lcids, channel, lcid) {
+		if (!strcmp(channel->name, name))
+			break;
+	}
+
+	if (!channel) {
+		channel = qcom_glink_alloc_channel(glink, name);
+		if (IS_ERR(channel))
+			return PTR_ERR(channel);
+
+		/* The opening dance was initiated by the remote */
+		create_device = true;
+	}
+
+	mutex_lock(&glink->idr_lock);
+	ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_KERNEL);
+	if (ret < 0) {
+		dev_err(glink->dev, "Unable to insert channel into rcid list\n");
+		mutex_unlock(&glink->idr_lock);
+		goto free_channel;
+	}
+	channel->rcid = ret;
+	mutex_unlock(&glink->idr_lock);
+
+	complete(&channel->open_req);
+
+	if (create_device) {
+		rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL);
+		if (!rpdev) {
+			ret = -ENOMEM;
+			goto rcid_remove;
+		}
+
+		rpdev->ept = &channel->ept;
+		strncpy(rpdev->id.name, name, RPMSG_NAME_SIZE);
+		rpdev->src = RPMSG_ADDR_ANY;
+		rpdev->dst = RPMSG_ADDR_ANY;
+		rpdev->ops = &glink_device_ops;
+
+		node = qcom_glink_match_channel(glink->dev->of_node, name);
+		rpdev->dev.of_node = node;
+		rpdev->dev.parent = glink->dev;
+		rpdev->dev.release = qcom_glink_rpdev_release;
+
+		ret = rpmsg_register_device(rpdev);
+		if (ret)
+			goto free_rpdev;
+
+		channel->rpdev = rpdev;
+	}
+
+	return 0;
+
+free_rpdev:
+	kfree(rpdev);
+rcid_remove:
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->rcids, channel->rcid);
+	channel->rcid = 0;
+	mutex_unlock(&glink->idr_lock);
+free_channel:
+	/* Release the reference, iff we took it */
+	if (create_device)
+		kref_put(&channel->refcount, qcom_glink_channel_release);
+
+	return ret;
+}
+
+static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
+{
+	struct rpmsg_channel_info chinfo;
+	struct glink_channel *channel;
+
+	channel = idr_find(&glink->rcids, rcid);
+	if (WARN(!channel, "close request on unknown channel\n"))
+		return;
+
+	if (channel->rpdev) {
+		strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
+		chinfo.src = RPMSG_ADDR_ANY;
+		chinfo.dst = RPMSG_ADDR_ANY;
+
+		rpmsg_unregister_device(glink->dev, &chinfo);
+	}
+
+	qcom_glink_send_close_ack(glink, channel->rcid);
+
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->rcids, channel->rcid);
+	channel->rcid = 0;
+	mutex_unlock(&glink->idr_lock);
+
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+}
+
+static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
+{
+	struct glink_channel *channel;
+
+	channel = idr_find(&glink->lcids, lcid);
+	if (WARN(!channel, "close ack on unknown channel\n"))
+		return;
+
+	mutex_lock(&glink->idr_lock);
+	idr_remove(&glink->lcids, channel->lcid);
+	channel->lcid = 0;
+	mutex_unlock(&glink->idr_lock);
+
+	kref_put(&channel->refcount, qcom_glink_channel_release);
+}
+
+static void qcom_glink_work(struct work_struct *work)
+{
+	struct qcom_glink *glink = container_of(work, struct qcom_glink,
+						rx_work);
+	struct glink_defer_cmd *dcmd;
+	struct glink_msg *msg;
+	unsigned long flags;
+	unsigned int param1;
+	unsigned int param2;
+	unsigned int cmd;
+
+	for (;;) {
+		spin_lock_irqsave(&glink->rx_lock, flags);
+		if (list_empty(&glink->rx_queue)) {
+			spin_unlock_irqrestore(&glink->rx_lock, flags);
+			break;
+		}
+		dcmd = list_first_entry(&glink->rx_queue,
+					struct glink_defer_cmd, node);
+		list_del(&dcmd->node);
+		spin_unlock_irqrestore(&glink->rx_lock, flags);
+
+		msg = &dcmd->msg;
+		cmd = le16_to_cpu(msg->cmd);
+		param1 = le16_to_cpu(msg->param1);
+		param2 = le32_to_cpu(msg->param2);
+
+		switch (cmd) {
+		case RPM_CMD_VERSION:
+			qcom_glink_send_version_ack(glink);
+			break;
+		case RPM_CMD_VERSION_ACK:
+			break;
+		case RPM_CMD_OPEN:
+			qcom_glink_rx_open(glink, param1, msg->data);
+			break;
+		case RPM_CMD_CLOSE:
+			qcom_glink_rx_close(glink, param1);
+			break;
+		case RPM_CMD_CLOSE_ACK:
+			qcom_glink_rx_close_ack(glink, param1);
+			break;
+		default:
+			WARN(1, "Unknown defer object %d\n", cmd);
+			break;
+		}
+
+		kfree(dcmd);
+	}
+}
+
+struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   struct qcom_glink_pipe *rx,
+					   struct qcom_glink_pipe *tx)
+{
+	int irq;
+	int ret;
+	struct qcom_glink *glink;
+
+	glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
+	if (!glink)
+		return ERR_PTR(-ENOMEM);
+
+	glink->dev = dev;
+	glink->tx_pipe = tx;
+	glink->rx_pipe = rx;
+
+	mutex_init(&glink->tx_lock);
+	spin_lock_init(&glink->rx_lock);
+	INIT_LIST_HEAD(&glink->rx_queue);
+	INIT_WORK(&glink->rx_work, qcom_glink_work);
+
+	mutex_init(&glink->idr_lock);
+	idr_init(&glink->lcids);
+	idr_init(&glink->rcids);
+
+	glink->mbox_client.dev = dev;
+	glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
+	if (IS_ERR(glink->mbox_chan)) {
+		if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
+			dev_err(dev, "failed to acquire IPC channel\n");
+		return ERR_CAST(glink->mbox_chan);
+	}
+
+	irq = of_irq_get(dev->of_node, 0);
+	ret = devm_request_irq(dev, irq,
+			       qcom_glink_native_intr,
+			       IRQF_NO_SUSPEND | IRQF_SHARED,
+			       "glink-native", glink);
+	if (ret) {
+		dev_err(dev, "failed to request IRQ\n");
+		return ERR_PTR(ret);
+	}
+
+	ret = qcom_glink_send_version(glink);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return glink;
+}
+
+static int qcom_glink_remove_device(struct device *dev, void *data)
+{
+	device_unregister(dev);
+
+	return 0;
+}
+
+void qcom_glink_native_remove(struct qcom_glink *glink)
+{
+	struct glink_channel *channel;
+	int cid;
+	int ret;
+
+	disable_irq(glink->irq);
+	cancel_work_sync(&glink->rx_work);
+
+	ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device);
+	if (ret)
+		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
+
+	/* Release any defunct local channels, waiting for close-ack */
+	idr_for_each_entry(&glink->lcids, channel, cid)
+		kref_put(&channel->refcount, qcom_glink_channel_release);
+
+	idr_destroy(&glink->lcids);
+	idr_destroy(&glink->rcids);
+}
diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
new file mode 100644
index 0000000..d5627a4
--- /dev/null
+++ b/drivers/rpmsg/qcom_glink_native.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_GLINK_NATIVE_H__
+#define __QCOM_GLINK_NATIVE_H__
+
+struct qcom_glink_pipe {
+	size_t length;
+
+	size_t (*avail)(struct qcom_glink_pipe *glink_pipe);
+
+	void (*peak)(struct qcom_glink_pipe *glink_pipe, void *data,
+		     size_t count);
+	void (*advance)(struct qcom_glink_pipe *glink_pipe, size_t count);
+
+	void (*write)(struct qcom_glink_pipe *glink_pipe,
+		      const void *hdr, size_t hlen,
+		      const void *data, size_t dlen);
+};
+
+struct qcom_glink;
+
+struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   struct qcom_glink_pipe *rx,
+					   struct qcom_glink_pipe *tx);
+void qcom_glink_native_remove(struct qcom_glink *glink);
+
+#endif
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 5f0fa0d..33daa32 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/rpmsg.h>
@@ -28,6 +27,7 @@
 #include <linux/mailbox_client.h>
 
 #include "rpmsg_internal.h"
+#include "qcom_glink_native.h"
 
 #define RPM_TOC_SIZE		256
 #define RPM_TOC_MAGIC		0x67727430 /* grt0 */
@@ -37,12 +37,7 @@
 #define RPM_TX_FIFO_ID		0x61703272 /* ap2r */
 #define RPM_RX_FIFO_ID		0x72326170 /* r2ap */
 
-#define GLINK_NAME_SIZE		32
-
-#define RPM_GLINK_CID_MIN	1
-#define RPM_GLINK_CID_MAX	65536
-
-#define to_rpm_pipe(p)	container_of(p, struct glink_rpm_pipe, native)
+#define to_rpm_pipe(p) container_of(p, struct glink_rpm_pipe, native)
 
 struct rpm_toc_entry {
 	__le32 id;
@@ -50,20 +45,6 @@ struct rpm_toc_entry {
 	__le32 size;
 } __packed;
 
-struct qcom_glink;
-
-struct qcom_glink_pipe {
-	size_t length;
-
-	size_t (*avail)(struct qcom_glink_pipe *glink_pipe);
-	void (*peak)(struct qcom_glink_pipe *glink_pipe, void *data,
-		     size_t count);
-	void (*advance)(struct qcom_glink_pipe *glink_pipe, size_t count);
-	void (*write)(struct qcom_glink_pipe *glink_pipe,
-		      const void *hdr, size_t hlen,
-		      const void *data, size_t dlen);
-};
-
 struct rpm_toc {
 	__le32 magic;
 	__le32 count;
@@ -71,13 +52,6 @@ struct rpm_toc {
 	struct rpm_toc_entry entries[];
 } __packed;
 
-struct glink_msg {
-	__le16 cmd;
-	__le16 param1;
-	__le32 param2;
-	u8 data[];
-} __packed;
-
 struct glink_rpm_pipe {
 	struct qcom_glink_pipe native;
 
@@ -87,151 +61,6 @@ struct glink_rpm_pipe {
 	void __iomem *fifo;
 };
 
-/**
- * struct glink_defer_cmd - deferred incoming control message
- * @node:	list node
- * @msg:	message header
- * data:	payload of the message
- *
- * Copy of a received control message, to be added to @rx_queue and processed
- * by @rx_work of @glink_rpm.
- */
-struct glink_defer_cmd {
-	struct list_head node;
-
-	struct glink_msg msg;
-	u8 data[];
-};
-
-/**
- * struct glink_rpm - driver context, relates to one remote subsystem
- * @dev:	reference to the associated struct device
- * @doorbell:	"rpm_hlos" ipc doorbell
- * @rx_pipe:	pipe object for receive FIFO
- * @tx_pipe:	pipe object for transmit FIFO
- * @irq:	IRQ for signaling incoming events
- * @rx_work:	worker for handling received control messages
- * @rx_lock:	protects the @rx_queue
- * @rx_queue:	queue of received control messages to be processed in @rx_work
- * @tx_lock:	synchronizes operations on the tx fifo
- * @idr_lock:	synchronizes @lcids and @rcids modifications
- * @lcids:	idr of all channels with a known local channel id
- * @rcids:	idr of all channels with a known remote channel id
- */
-struct qcom_glink {
-	struct device *dev;
-
-	struct mbox_client mbox_client;
-	struct mbox_chan *mbox_chan;
-
-	struct qcom_glink_pipe *rx_pipe;
-	struct qcom_glink_pipe *tx_pipe;
-
-	int irq;
-
-	struct work_struct rx_work;
-	spinlock_t rx_lock;
-	struct list_head rx_queue;
-
-	struct mutex tx_lock;
-
-	struct mutex idr_lock;
-	struct idr lcids;
-	struct idr rcids;
-};
-
-enum {
-	GLINK_STATE_CLOSED,
-	GLINK_STATE_OPENING,
-	GLINK_STATE_OPEN,
-	GLINK_STATE_CLOSING,
-};
-
-/**
- * struct glink_channel - internal representation of a channel
- * @rpdev:	rpdev reference, only used for primary endpoints
- * @ept:	rpmsg endpoint this channel is associated with
- * @glink:	qcom_glink context handle
- * @refcount:	refcount for the channel object
- * @recv_lock:	guard for @ept.cb
- * @name:	unique channel name/identifier
- * @lcid:	channel id, in local space
- * @rcid:	channel id, in remote space
- * @buf:	receive buffer, for gathering fragments
- * @buf_offset:	write offset in @buf
- * @buf_size:	size of current @buf
- * @open_ack:	completed once remote has acked the open-request
- * @open_req:	completed once open-request has been received
- */
-struct glink_channel {
-	struct rpmsg_endpoint ept;
-
-	struct rpmsg_device *rpdev;
-	struct qcom_glink *glink;
-
-	struct kref refcount;
-
-	spinlock_t recv_lock;
-
-	char *name;
-	unsigned int lcid;
-	unsigned int rcid;
-
-	void *buf;
-	int buf_offset;
-	int buf_size;
-
-	struct completion open_ack;
-	struct completion open_req;
-};
-
-#define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept)
-
-static const struct rpmsg_endpoint_ops glink_endpoint_ops;
-
-#define RPM_CMD_VERSION			0
-#define RPM_CMD_VERSION_ACK		1
-#define RPM_CMD_OPEN			2
-#define RPM_CMD_CLOSE			3
-#define RPM_CMD_OPEN_ACK		4
-#define RPM_CMD_TX_DATA			9
-#define RPM_CMD_CLOSE_ACK		11
-#define RPM_CMD_TX_DATA_CONT		12
-#define RPM_CMD_READ_NOTIF		13
-
-#define GLINK_FEATURE_INTENTLESS	BIT(1)
-
-static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
-						      const char *name)
-{
-	struct glink_channel *channel;
-
-	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
-	if (!channel)
-		return ERR_PTR(-ENOMEM);
-
-	/* Setup glink internal glink_channel data */
-	spin_lock_init(&channel->recv_lock);
-	channel->glink = glink;
-	channel->name = kstrdup(name, GFP_KERNEL);
-
-	init_completion(&channel->open_req);
-	init_completion(&channel->open_ack);
-
-	kref_init(&channel->refcount);
-
-	return channel;
-}
-
-static void qcom_glink_channel_release(struct kref *ref)
-{
-	struct glink_channel *channel = container_of(ref, struct glink_channel,
-						     refcount);
-
-	kfree(channel->name);
-	kfree(channel);
-}
-
 static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
 {
 	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
@@ -247,11 +76,6 @@ static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
 		return head - tail;
 }
 
-static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
-{
-	return glink->rx_pipe->avail(glink->rx_pipe);
-}
-
 static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
 			      void *data, size_t count)
 {
@@ -273,12 +97,6 @@ static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
 	}
 }
 
-static void qcom_glink_rx_peak(struct qcom_glink *glink,
-			       void *data, size_t count)
-{
-	glink->rx_pipe->peak(glink->rx_pipe, data, count);
-}
-
 static void glink_rpm_rx_advance(struct qcom_glink_pipe *glink_pipe,
 				 size_t count)
 {
@@ -294,11 +112,6 @@ static void glink_rpm_rx_advance(struct qcom_glink_pipe *glink_pipe,
 	writel(tail, pipe->tail);
 }
 
-static void qcom_glink_rx_advance(struct qcom_glink *glink, size_t count)
-{
-	glink->rx_pipe->advance(glink->rx_pipe, count);
-}
-
 static size_t glink_rpm_tx_avail(struct qcom_glink_pipe *glink_pipe)
 {
 	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
@@ -314,11 +127,6 @@ static size_t glink_rpm_tx_avail(struct qcom_glink_pipe *glink_pipe)
 		return tail - head;
 }
 
-static size_t qcom_glink_tx_avail(struct qcom_glink *glink)
-{
-	return glink->tx_pipe->avail(glink->tx_pipe);
-}
-
 static unsigned int glink_rpm_tx_write_one(struct glink_rpm_pipe *pipe,
 					   unsigned int head,
 					   const void *data, size_t count)
@@ -356,731 +164,6 @@ static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
 	writel(head, pipe->head);
 }
 
-static void qcom_glink_tx_write(struct qcom_glink *glink,
-				const void *hdr, size_t hlen,
-				const void *data, size_t dlen)
-{
-	glink->tx_pipe->write(glink->tx_pipe, hdr, hlen, data, dlen);
-}
-
-static int qcom_glink_tx(struct qcom_glink *glink,
-			 const void *hdr, size_t hlen,
-			const void *data, size_t dlen, bool wait)
-{
-	unsigned int tlen = hlen + dlen;
-	int ret;
-
-	/* Reject packets that are too big */
-	if (tlen >= glink->tx_pipe->length)
-		return -EINVAL;
-
-	if (WARN(tlen % 8, "Unaligned TX request"))
-		return -EINVAL;
-
-	ret = mutex_lock_interruptible(&glink->tx_lock);
-	if (ret)
-		return ret;
-
-	while (qcom_glink_tx_avail(glink) < tlen) {
-		if (!wait) {
-			ret = -ENOMEM;
-			goto out;
-		}
-
-		msleep(10);
-	}
-
-	qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
-
-	mbox_send_message(glink->mbox_chan, NULL);
-	mbox_client_txdone(glink->mbox_chan, 0);
-
-out:
-	mutex_unlock(&glink->tx_lock);
-
-	return ret;
-}
-
-static int qcom_glink_send_version(struct qcom_glink *glink)
-{
-	struct glink_msg msg;
-
-	msg.cmd = cpu_to_le16(RPM_CMD_VERSION);
-	msg.param1 = cpu_to_le16(1);
-	msg.param2 = cpu_to_le32(GLINK_FEATURE_INTENTLESS);
-
-	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
-}
-
-static void qcom_glink_send_version_ack(struct qcom_glink *glink)
-{
-	struct glink_msg msg;
-
-	msg.cmd = cpu_to_le16(RPM_CMD_VERSION_ACK);
-	msg.param1 = cpu_to_le16(1);
-	msg.param2 = cpu_to_le32(0);
-
-	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
-}
-
-static void qcom_glink_send_open_ack(struct qcom_glink *glink,
-				     struct glink_channel *channel)
-{
-	struct glink_msg msg;
-
-	msg.cmd = cpu_to_le16(RPM_CMD_OPEN_ACK);
-	msg.param1 = cpu_to_le16(channel->rcid);
-	msg.param2 = cpu_to_le32(0);
-
-	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
-}
-
-/**
- * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
- * @glink:
- * @channel:
- *
- * Allocates a local channel id and sends a RPM_CMD_OPEN message to the remote.
- * Will return with refcount held, regardless of outcome.
- *
- * Returns 0 on success, negative errno otherwise.
- */
-static int qcom_glink_send_open_req(struct qcom_glink *glink,
-				    struct glink_channel *channel)
-{
-	struct {
-		struct glink_msg msg;
-		u8 name[GLINK_NAME_SIZE];
-	} __packed req;
-	int name_len = strlen(channel->name) + 1;
-	int req_len = ALIGN(sizeof(req.msg) + name_len, 8);
-	int ret;
-
-	kref_get(&channel->refcount);
-
-	mutex_lock(&glink->idr_lock);
-	ret = idr_alloc_cyclic(&glink->lcids, channel,
-			       RPM_GLINK_CID_MIN, RPM_GLINK_CID_MAX, GFP_KERNEL);
-	mutex_unlock(&glink->idr_lock);
-	if (ret < 0)
-		return ret;
-
-	channel->lcid = ret;
-
-	req.msg.cmd = cpu_to_le16(RPM_CMD_OPEN);
-	req.msg.param1 = cpu_to_le16(channel->lcid);
-	req.msg.param2 = cpu_to_le32(name_len);
-	strcpy(req.name, channel->name);
-
-	ret = qcom_glink_tx(glink, &req, req_len, NULL, 0, true);
-	if (ret)
-		goto remove_idr;
-
-	return 0;
-
-remove_idr:
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->lcids, channel->lcid);
-	channel->lcid = 0;
-	mutex_unlock(&glink->idr_lock);
-
-	return ret;
-}
-
-static void qcom_glink_send_close_req(struct qcom_glink *glink,
-				      struct glink_channel *channel)
-{
-	struct glink_msg req;
-
-	req.cmd = cpu_to_le16(RPM_CMD_CLOSE);
-	req.param1 = cpu_to_le16(channel->lcid);
-	req.param2 = 0;
-
-	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
-}
-
-static void qcom_glink_send_close_ack(struct qcom_glink *glink,
-				      unsigned int rcid)
-{
-	struct glink_msg req;
-
-	req.cmd = cpu_to_le16(RPM_CMD_CLOSE_ACK);
-	req.param1 = cpu_to_le16(rcid);
-	req.param2 = 0;
-
-	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
-}
-
-static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
-{
-	struct glink_defer_cmd *dcmd;
-
-	extra = ALIGN(extra, 8);
-
-	if (qcom_glink_rx_avail(glink) < sizeof(struct glink_msg) + extra) {
-		dev_dbg(glink->dev, "Insufficient data in rx fifo");
-		return -ENXIO;
-	}
-
-	dcmd = kzalloc(sizeof(*dcmd) + extra, GFP_ATOMIC);
-	if (!dcmd)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&dcmd->node);
-
-	qcom_glink_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
-
-	spin_lock(&glink->rx_lock);
-	list_add_tail(&dcmd->node, &glink->rx_queue);
-	spin_unlock(&glink->rx_lock);
-
-	schedule_work(&glink->rx_work);
-	qcom_glink_rx_advance(glink, sizeof(dcmd->msg) + extra);
-
-	return 0;
-}
-
-static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
-{
-	struct glink_channel *channel;
-	struct {
-		struct glink_msg msg;
-		__le32 chunk_size;
-		__le32 left_size;
-	} __packed hdr;
-	unsigned int chunk_size;
-	unsigned int left_size;
-	unsigned int rcid;
-
-	if (avail < sizeof(hdr)) {
-		dev_dbg(glink->dev, "Not enough data in fifo\n");
-		return -EAGAIN;
-	}
-
-	qcom_glink_rx_peak(glink, &hdr, sizeof(hdr));
-	chunk_size = le32_to_cpu(hdr.chunk_size);
-	left_size = le32_to_cpu(hdr.left_size);
-
-	if (avail < sizeof(hdr) + chunk_size) {
-		dev_dbg(glink->dev, "Payload not yet in fifo\n");
-		return -EAGAIN;
-	}
-
-	if (WARN(chunk_size % 4, "Incoming data must be word aligned\n"))
-		return -EINVAL;
-
-	rcid = le16_to_cpu(hdr.msg.param1);
-	channel = idr_find(&glink->rcids, rcid);
-	if (!channel) {
-		dev_dbg(glink->dev, "Data on non-existing channel\n");
-
-		/* Drop the message */
-		qcom_glink_rx_advance(glink,
-				      ALIGN(sizeof(hdr) + chunk_size, 8));
-		return 0;
-	}
-
-	/* Might have an ongoing, fragmented, message to append */
-	if (!channel->buf) {
-		channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
-		if (!channel->buf)
-			return -ENOMEM;
-
-		channel->buf_size = chunk_size + left_size;
-		channel->buf_offset = 0;
-	}
-
-	qcom_glink_rx_advance(glink, sizeof(hdr));
-
-	if (channel->buf_size - channel->buf_offset < chunk_size) {
-		dev_err(glink->dev, "Insufficient space in input buffer\n");
-
-		/* The packet header lied, drop payload */
-		qcom_glink_rx_advance(glink, chunk_size);
-		return -ENOMEM;
-	}
-
-	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
-			   chunk_size);
-	channel->buf_offset += chunk_size;
-
-	/* Handle message when no fragments remain to be received */
-	if (!left_size) {
-		spin_lock(&channel->recv_lock);
-		if (channel->ept.cb) {
-			channel->ept.cb(channel->ept.rpdev,
-					channel->buf,
-					channel->buf_offset,
-					channel->ept.priv,
-					RPMSG_ADDR_ANY);
-		}
-		spin_unlock(&channel->recv_lock);
-
-		kfree(channel->buf);
-		channel->buf = NULL;
-		channel->buf_size = 0;
-	}
-
-	/* Each message starts at 8 byte aligned address */
-	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
-
-	return 0;
-}
-
-static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
-{
-	struct glink_channel *channel;
-
-	channel = idr_find(&glink->lcids, lcid);
-	if (!channel) {
-		dev_err(glink->dev, "Invalid open ack packet\n");
-		return -EINVAL;
-	}
-
-	complete(&channel->open_ack);
-
-	return 0;
-}
-
-static irqreturn_t qcom_glink_intr(int irq, void *data)
-{
-	struct qcom_glink *glink = data;
-	struct glink_msg msg;
-	unsigned int param1;
-	unsigned int param2;
-	unsigned int avail;
-	unsigned int cmd;
-	int ret;
-
-	for (;;) {
-		avail = qcom_glink_rx_avail(glink);
-		if (avail < sizeof(msg))
-			break;
-
-		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
-
-		cmd = le16_to_cpu(msg.cmd);
-		param1 = le16_to_cpu(msg.param1);
-		param2 = le32_to_cpu(msg.param2);
-
-		switch (cmd) {
-		case RPM_CMD_VERSION:
-		case RPM_CMD_VERSION_ACK:
-		case RPM_CMD_CLOSE:
-		case RPM_CMD_CLOSE_ACK:
-			ret = qcom_glink_rx_defer(glink, 0);
-			break;
-		case RPM_CMD_OPEN_ACK:
-			ret = qcom_glink_rx_open_ack(glink, param1);
-			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
-			break;
-		case RPM_CMD_OPEN:
-			ret = qcom_glink_rx_defer(glink, param2);
-			break;
-		case RPM_CMD_TX_DATA:
-		case RPM_CMD_TX_DATA_CONT:
-			ret = qcom_glink_rx_data(glink, avail);
-			break;
-		case RPM_CMD_READ_NOTIF:
-			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
-
-			mbox_send_message(glink->mbox_chan, NULL);
-			mbox_client_txdone(glink->mbox_chan, 0);
-
-			ret = 0;
-			break;
-		default:
-			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
-			ret = -EINVAL;
-			break;
-		}
-
-		if (ret)
-			break;
-	}
-
-	return IRQ_HANDLED;
-}
-
-/* Locally initiated rpmsg_create_ept */
-static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
-						     const char *name)
-{
-	struct glink_channel *channel;
-	int ret;
-
-	channel = qcom_glink_alloc_channel(glink, name);
-	if (IS_ERR(channel))
-		return ERR_CAST(channel);
-
-	ret = qcom_glink_send_open_req(glink, channel);
-	if (ret)
-		goto release_channel;
-
-	ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ);
-	if (!ret)
-		goto err_timeout;
-
-	ret = wait_for_completion_timeout(&channel->open_req, 5 * HZ);
-	if (!ret)
-		goto err_timeout;
-
-	qcom_glink_send_open_ack(glink, channel);
-
-	return channel;
-
-err_timeout:
-	/* qcom_glink_send_open_req() did register the channel in lcids*/
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->lcids, channel->lcid);
-	mutex_unlock(&glink->idr_lock);
-
-release_channel:
-	/* Release qcom_glink_send_open_req() reference */
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-	/* Release qcom_glink_alloc_channel() reference */
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-
-	return ERR_PTR(-ETIMEDOUT);
-}
-
-/* Remote initiated rpmsg_create_ept */
-static int qcom_glink_create_remote(struct qcom_glink *glink,
-				    struct glink_channel *channel)
-{
-	int ret;
-
-	qcom_glink_send_open_ack(glink, channel);
-
-	ret = qcom_glink_send_open_req(glink, channel);
-	if (ret)
-		goto close_link;
-
-	ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ);
-	if (!ret) {
-		ret = -ETIMEDOUT;
-		goto close_link;
-	}
-
-	return 0;
-
-close_link:
-	/*
-	 * Send a close request to "undo" our open-ack. The close-ack will
-	 * release the last reference.
-	 */
-	qcom_glink_send_close_req(glink, channel);
-
-	/* Release qcom_glink_send_open_req() reference */
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-
-	return ret;
-}
-
-static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
-						    rpmsg_rx_cb_t cb,
-						    void *priv,
-						    struct rpmsg_channel_info
-						    chinfo)
-{
-	struct glink_channel *parent = to_glink_channel(rpdev->ept);
-	struct glink_channel *channel;
-	struct qcom_glink *glink = parent->glink;
-	struct rpmsg_endpoint *ept;
-	const char *name = chinfo.name;
-	int cid;
-	int ret;
-
-	idr_for_each_entry(&glink->rcids, channel, cid) {
-		if (!strcmp(channel->name, name))
-			break;
-	}
-
-	if (!channel) {
-		channel = qcom_glink_create_local(glink, name);
-		if (IS_ERR(channel))
-			return NULL;
-	} else {
-		ret = qcom_glink_create_remote(glink, channel);
-		if (ret)
-			return NULL;
-	}
-
-	ept = &channel->ept;
-	ept->rpdev = rpdev;
-	ept->cb = cb;
-	ept->priv = priv;
-	ept->ops = &glink_endpoint_ops;
-
-	return ept;
-}
-
-static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
-{
-	struct glink_channel *channel = to_glink_channel(ept);
-	struct qcom_glink *glink = channel->glink;
-	unsigned long flags;
-
-	spin_lock_irqsave(&channel->recv_lock, flags);
-	channel->ept.cb = NULL;
-	spin_unlock_irqrestore(&channel->recv_lock, flags);
-
-	/* Decouple the potential rpdev from the channel */
-	channel->rpdev = NULL;
-
-	qcom_glink_send_close_req(glink, channel);
-}
-
-static int __qcom_glink_send(struct glink_channel *channel,
-			     void *data, int len, bool wait)
-{
-	struct qcom_glink *glink = channel->glink;
-	struct {
-		struct glink_msg msg;
-		__le32 chunk_size;
-		__le32 left_size;
-	} __packed req;
-
-	if (WARN(len % 8, "RPM GLINK expects 8 byte aligned messages\n"))
-		return -EINVAL;
-
-	req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
-	req.msg.param1 = cpu_to_le16(channel->lcid);
-	req.msg.param2 = cpu_to_le32(channel->rcid);
-	req.chunk_size = cpu_to_le32(len);
-	req.left_size = cpu_to_le32(0);
-
-	return qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
-}
-
-static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len)
-{
-	struct glink_channel *channel = to_glink_channel(ept);
-
-	return __qcom_glink_send(channel, data, len, true);
-}
-
-static int qcom_glink_trysend(struct rpmsg_endpoint *ept, void *data, int len)
-{
-	struct glink_channel *channel = to_glink_channel(ept);
-
-	return __qcom_glink_send(channel, data, len, false);
-}
-
-/*
- * Finds the device_node for the glink child interested in this channel.
- */
-static struct device_node *qcom_glink_match_channel(struct device_node *node,
-						    const char *channel)
-{
-	struct device_node *child;
-	const char *name;
-	const char *key;
-	int ret;
-
-	for_each_available_child_of_node(node, child) {
-		key = "qcom,glink-channels";
-		ret = of_property_read_string(child, key, &name);
-		if (ret)
-			continue;
-
-		if (strcmp(name, channel) == 0)
-			return child;
-	}
-
-	return NULL;
-}
-
-static const struct rpmsg_device_ops glink_device_ops = {
-	.create_ept = qcom_glink_create_ept,
-};
-
-static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
-	.destroy_ept = qcom_glink_destroy_ept,
-	.send = qcom_glink_send,
-	.trysend = qcom_glink_trysend,
-};
-
-static void qcom_glink_rpdev_release(struct device *dev)
-{
-	struct rpmsg_device *rpdev = to_rpmsg_device(dev);
-	struct glink_channel *channel = to_glink_channel(rpdev->ept);
-
-	channel->rpdev = NULL;
-	kfree(rpdev);
-}
-
-static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
-			      char *name)
-{
-	struct glink_channel *channel;
-	struct rpmsg_device *rpdev;
-	bool create_device = false;
-	int lcid;
-	int ret;
-	struct device_node *node;
-
-	idr_for_each_entry(&glink->lcids, channel, lcid) {
-		if (!strcmp(channel->name, name))
-			break;
-	}
-
-	if (!channel) {
-		channel = qcom_glink_alloc_channel(glink, name);
-		if (IS_ERR(channel))
-			return PTR_ERR(channel);
-
-		/* The opening dance was initiated by the remote */
-		create_device = true;
-	}
-
-	mutex_lock(&glink->idr_lock);
-	ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_KERNEL);
-	if (ret < 0) {
-		dev_err(glink->dev, "Unable to insert channel into rcid list\n");
-		mutex_unlock(&glink->idr_lock);
-		goto free_channel;
-	}
-	channel->rcid = ret;
-	mutex_unlock(&glink->idr_lock);
-
-	complete(&channel->open_req);
-
-	if (create_device) {
-		rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL);
-		if (!rpdev) {
-			ret = -ENOMEM;
-			goto rcid_remove;
-		}
-
-		rpdev->ept = &channel->ept;
-		strncpy(rpdev->id.name, name, RPMSG_NAME_SIZE);
-		rpdev->src = RPMSG_ADDR_ANY;
-		rpdev->dst = RPMSG_ADDR_ANY;
-		rpdev->ops = &glink_device_ops;
-
-		node = qcom_glink_match_channel(glink->dev->of_node, name);
-		rpdev->dev.of_node = node;
-		rpdev->dev.parent = glink->dev;
-		rpdev->dev.release = qcom_glink_rpdev_release;
-
-		ret = rpmsg_register_device(rpdev);
-		if (ret)
-			goto free_rpdev;
-
-		channel->rpdev = rpdev;
-	}
-
-	return 0;
-
-free_rpdev:
-	kfree(rpdev);
-rcid_remove:
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->rcids, channel->rcid);
-	channel->rcid = 0;
-	mutex_unlock(&glink->idr_lock);
-free_channel:
-	/* Release the reference, iff we took it */
-	if (create_device)
-		kref_put(&channel->refcount, qcom_glink_channel_release);
-
-	return ret;
-}
-
-static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
-{
-	struct rpmsg_channel_info chinfo;
-	struct glink_channel *channel;
-
-	channel = idr_find(&glink->rcids, rcid);
-	if (WARN(!channel, "close request on unknown channel\n"))
-		return;
-
-	if (channel->rpdev) {
-		strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
-		chinfo.src = RPMSG_ADDR_ANY;
-		chinfo.dst = RPMSG_ADDR_ANY;
-
-		rpmsg_unregister_device(glink->dev, &chinfo);
-	}
-
-	qcom_glink_send_close_ack(glink, channel->rcid);
-
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->rcids, channel->rcid);
-	channel->rcid = 0;
-	mutex_unlock(&glink->idr_lock);
-
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-}
-
-static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
-{
-	struct glink_channel *channel;
-
-	channel = idr_find(&glink->lcids, lcid);
-	if (WARN(!channel, "close ack on unknown channel\n"))
-		return;
-
-	mutex_lock(&glink->idr_lock);
-	idr_remove(&glink->lcids, channel->lcid);
-	channel->lcid = 0;
-	mutex_unlock(&glink->idr_lock);
-
-	kref_put(&channel->refcount, qcom_glink_channel_release);
-}
-
-static void qcom_glink_work(struct work_struct *work)
-{
-	struct qcom_glink *glink = container_of(work, struct qcom_glink,
-						rx_work);
-	struct glink_defer_cmd *dcmd;
-	struct glink_msg *msg;
-	unsigned long flags;
-	unsigned int param1;
-	unsigned int param2;
-	unsigned int cmd;
-
-	for (;;) {
-		spin_lock_irqsave(&glink->rx_lock, flags);
-		if (list_empty(&glink->rx_queue)) {
-			spin_unlock_irqrestore(&glink->rx_lock, flags);
-			break;
-		}
-		dcmd = list_first_entry(&glink->rx_queue, struct glink_defer_cmd, node);
-		list_del(&dcmd->node);
-		spin_unlock_irqrestore(&glink->rx_lock, flags);
-
-		msg = &dcmd->msg;
-		cmd = le16_to_cpu(msg->cmd);
-		param1 = le16_to_cpu(msg->param1);
-		param2 = le32_to_cpu(msg->param2);
-
-		switch (cmd) {
-		case RPM_CMD_VERSION:
-			qcom_glink_send_version_ack(glink);
-			break;
-		case RPM_CMD_VERSION_ACK:
-			break;
-		case RPM_CMD_OPEN:
-			qcom_glink_rx_open(glink, param1, msg->data);
-			break;
-		case RPM_CMD_CLOSE:
-			qcom_glink_rx_close(glink, param1);
-			break;
-		case RPM_CMD_CLOSE_ACK:
-			qcom_glink_rx_close_ack(glink, param1);
-			break;
-		default:
-			WARN(1, "Unknown defer object %d\n", cmd);
-			break;
-		}
-
-		kfree(dcmd);
-	}
-}
-
 static int glink_rpm_parse_toc(struct device *dev,
 			       void __iomem *msg_ram,
 			       size_t msg_ram_size,
@@ -1156,56 +239,6 @@ static int glink_rpm_parse_toc(struct device *dev,
 	return -EINVAL;
 }
 
-struct qcom_glink *qcom_glink_native_probe(struct device *dev,
-					   struct qcom_glink_pipe *rx,
-					   struct qcom_glink_pipe *tx)
-{
-	int irq;
-	int ret;
-	struct qcom_glink *glink;
-
-	glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
-	if (!glink)
-		return ERR_PTR(-ENOMEM);
-
-	glink->dev = dev;
-	glink->tx_pipe = tx;
-	glink->rx_pipe = rx;
-
-	mutex_init(&glink->tx_lock);
-	spin_lock_init(&glink->rx_lock);
-	INIT_LIST_HEAD(&glink->rx_queue);
-	INIT_WORK(&glink->rx_work, qcom_glink_work);
-
-	mutex_init(&glink->idr_lock);
-	idr_init(&glink->lcids);
-	idr_init(&glink->rcids);
-
-	glink->mbox_client.dev = dev;
-	glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
-	if (IS_ERR(glink->mbox_chan)) {
-		if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
-			dev_err(dev, "failed to acquire IPC channel\n");
-		return ERR_CAST(glink->mbox_chan);
-	}
-
-	irq = of_irq_get(dev->of_node, 0);
-	ret = devm_request_irq(dev, irq,
-			       qcom_glink_intr,
-			       IRQF_NO_SUSPEND | IRQF_SHARED,
-			       "glink-native", glink);
-	if (ret) {
-		dev_err(dev, "failed to request IRQ\n");
-		return ERR_PTR(ret);
-	}
-
-	ret = qcom_glink_send_version(glink);
-	if (ret)
-		return ERR_PTR(ret);
-
-	return glink;
-}
-
 static int glink_rpm_probe(struct platform_device *pdev)
 {
 	struct qcom_glink *glink;
@@ -1259,33 +292,11 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int glink_rpm_remove_device(struct device *dev, void *data)
-{
-	device_unregister(dev);
-
-	return 0;
-}
-
 static int glink_rpm_remove(struct platform_device *pdev)
 {
 	struct qcom_glink *glink = platform_get_drvdata(pdev);
-	struct glink_channel *channel;
-	int cid;
-	int ret;
-
-	disable_irq(glink->irq);
-	cancel_work_sync(&glink->rx_work);
-
-	ret = device_for_each_child(glink->dev, NULL, glink_rpm_remove_device);
-	if (ret)
-		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
-
-	/* Release any defunct local channels, waiting for close-ack */
-	idr_for_each_entry(&glink->lcids, channel, cid)
-		kref_put(&channel->refcount, qcom_glink_channel_release);
 
-	idr_destroy(&glink->lcids);
-	idr_destroy(&glink->rcids);
+	qcom_glink_native_remove(glink);
 
 	return 0;
 }
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 05/18] rpmsg: glink: Allow unaligned data access
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:18   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

From: Bjorn Andersson <bjorn.andersson@linaro.org>

Glink protocol requires that each message is aligned
on a 8 byte offset. This is purely a restriction
from glink, so in order to support clients which
do not adher to this, allow data packets of any size,
but align the head index accordingly, effectively
removing the alignment restriction.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_native.c |  6 ------
 drivers/rpmsg/qcom_glink_rpm.c    | 22 +++++++++++++++++++++-
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 04afbb2..1aa92daf 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -226,9 +226,6 @@ static int qcom_glink_tx(struct qcom_glink *glink,
 	if (tlen >= glink->tx_pipe->length)
 		return -EINVAL;
 
-	if (WARN(tlen % 8, "Unaligned TX request"))
-		return -EINVAL;
-
 	ret = mutex_lock_interruptible(&glink->tx_lock);
 	if (ret)
 		return ret;
@@ -694,9 +691,6 @@ static int __qcom_glink_send(struct glink_channel *channel,
 		__le32 left_size;
 	} __packed req;
 
-	if (WARN(len % 8, "RPM GLINK expects 8 byte aligned messages\n"))
-		return -EINVAL;
-
 	req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
 	req.msg.param1 = cpu_to_le16(channel->lcid);
 	req.msg.param2 = cpu_to_le32(channel->rcid);
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 33daa32..cc73af0 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -156,11 +156,31 @@ static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
 			       const void *data, size_t dlen)
 {
 	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
+	size_t tlen = hlen + dlen;
+	size_t aligned_dlen;
 	unsigned int head;
+	char padding[8] = {0};
+	size_t pad;
+
+	/* Header length comes from glink native and is always 4 byte aligned */
+	if (WARN(hlen % 4, "Glink Header length must be 4 bytes aligned\n"))
+		return;
+
+	/*
+	 * Move the unaligned tail of the message to the padding chunk, to
+	 * ensure word aligned accesses
+	 */
+	aligned_dlen = ALIGN_DOWN(dlen, 4);
+	if (aligned_dlen != dlen)
+		memcpy(padding, data + aligned_dlen, dlen - aligned_dlen);
 
 	head = readl(pipe->head);
 	head = glink_rpm_tx_write_one(pipe, head, hdr, hlen);
-	head = glink_rpm_tx_write_one(pipe, head, data, dlen);
+	head = glink_rpm_tx_write_one(pipe, head, data, aligned_dlen);
+
+	pad = ALIGN(tlen, 8) - ALIGN_DOWN(tlen, 4);
+	if (pad)
+		head = glink_rpm_tx_write_one(pipe, head, padding, pad);
 	writel(head, pipe->head);
 }
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 05/18] rpmsg: glink: Allow unaligned data access
@ 2017-08-16 17:18   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: Bjorn Andersson <bjorn.andersson@linaro.org>

Glink protocol requires that each message is aligned
on a 8 byte offset. This is purely a restriction
from glink, so in order to support clients which
do not adher to this, allow data packets of any size,
but align the head index accordingly, effectively
removing the alignment restriction.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_native.c |  6 ------
 drivers/rpmsg/qcom_glink_rpm.c    | 22 +++++++++++++++++++++-
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 04afbb2..1aa92daf 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -226,9 +226,6 @@ static int qcom_glink_tx(struct qcom_glink *glink,
 	if (tlen >= glink->tx_pipe->length)
 		return -EINVAL;
 
-	if (WARN(tlen % 8, "Unaligned TX request"))
-		return -EINVAL;
-
 	ret = mutex_lock_interruptible(&glink->tx_lock);
 	if (ret)
 		return ret;
@@ -694,9 +691,6 @@ static int __qcom_glink_send(struct glink_channel *channel,
 		__le32 left_size;
 	} __packed req;
 
-	if (WARN(len % 8, "RPM GLINK expects 8 byte aligned messages\n"))
-		return -EINVAL;
-
 	req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
 	req.msg.param1 = cpu_to_le16(channel->lcid);
 	req.msg.param2 = cpu_to_le32(channel->rcid);
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 33daa32..cc73af0 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -156,11 +156,31 @@ static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
 			       const void *data, size_t dlen)
 {
 	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
+	size_t tlen = hlen + dlen;
+	size_t aligned_dlen;
 	unsigned int head;
+	char padding[8] = {0};
+	size_t pad;
+
+	/* Header length comes from glink native and is always 4 byte aligned */
+	if (WARN(hlen % 4, "Glink Header length must be 4 bytes aligned\n"))
+		return;
+
+	/*
+	 * Move the unaligned tail of the message to the padding chunk, to
+	 * ensure word aligned accesses
+	 */
+	aligned_dlen = ALIGN_DOWN(dlen, 4);
+	if (aligned_dlen != dlen)
+		memcpy(padding, data + aligned_dlen, dlen - aligned_dlen);
 
 	head = readl(pipe->head);
 	head = glink_rpm_tx_write_one(pipe, head, hdr, hlen);
-	head = glink_rpm_tx_write_one(pipe, head, data, dlen);
+	head = glink_rpm_tx_write_one(pipe, head, data, aligned_dlen);
+
+	pad = ALIGN(tlen, 8) - ALIGN_DOWN(tlen, 4);
+	if (pad)
+		head = glink_rpm_tx_write_one(pipe, head, padding, pad);
 	writel(head, pipe->head);
 }
 
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 06/18] rpmsg: glink: Introduce glink smem based transport
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:18   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

From: Bjorn Andersson <bjorn.andersson@linaro.org>

The glink protocol supports different types of
transports (shared memory). With the core protocol
remaining the same, the way the transport's memory is
probed and accessed is different. So add support for
glink's smem based transports.

Adding a new smem transport register function and the
fifo accessors for the same.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/Kconfig            |  10 ++
 drivers/rpmsg/Makefile           |   1 +
 drivers/rpmsg/qcom_glink_smem.c  | 304 +++++++++++++++++++++++++++++++++++++++
 include/linux/rpmsg/qcom_glink.h |  27 ++++
 4 files changed, 342 insertions(+)
 create mode 100644 drivers/rpmsg/qcom_glink_smem.c
 create mode 100644 include/linux/rpmsg/qcom_glink.h

diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index ac33688..4bd9ba3 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -27,6 +27,16 @@ config RPMSG_QCOM_GLINK_RPM
 	  which serves as a channel for communication with the RPM in GLINK
 	  enabled systems.
 
+config RPMSG_QCOM_GLINK_SMEM
+	tristate "Qualcomm SMEM Glink driver"
+	select RPMSG_QCOM_GLINK_NATIVE
+	depends on HAS_IOMEM
+	depends on MAILBOX
+	help
+	  Say y here to enable support for the GLINK SMEM communication driver,
+	  which provides support for using the GLINK communication protocol
+	  over SMEM.
+
 config RPMSG_QCOM_SMD
 	tristate "Qualcomm Shared Memory Driver (SMD)"
 	depends on QCOM_SMEM
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 09a756c..c71f4ab 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -2,5 +2,6 @@ obj-$(CONFIG_RPMSG)		+= rpmsg_core.o
 obj-$(CONFIG_RPMSG_CHAR)	+= rpmsg_char.o
 obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
 obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o
+obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o
 obj-$(CONFIG_RPMSG_QCOM_SMD)	+= qcom_smd.o
 obj-$(CONFIG_RPMSG_VIRTIO)	+= virtio_rpmsg_bus.o
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
new file mode 100644
index 0000000..defa10b
--- /dev/null
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2016, Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+#include <linux/rpmsg.h>
+#include <linux/idr.h>
+#include <linux/circ_buf.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/sizes.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <linux/list.h>
+
+#include <linux/delay.h>
+#include <linux/rpmsg.h>
+#include <linux/rpmsg/qcom_glink.h>
+
+#include "qcom_glink_native.h"
+
+#define FIFO_FULL_RESERVE 8
+#define FIFO_ALIGNMENT 8
+#define TX_BLOCKED_CMD_RESERVE 8 /* size of struct read_notif_request */
+
+#define SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR	478
+#define SMEM_GLINK_NATIVE_XPRT_FIFO_0		479
+#define SMEM_GLINK_NATIVE_XPRT_FIFO_1		480
+
+struct glink_smem_pipe {
+	struct qcom_glink_pipe native;
+
+	__le32 *tail;
+	__le32 *head;
+
+	void *fifo;
+
+	int remote_pid;
+};
+
+#define to_smem_pipe(p) container_of(p, struct glink_smem_pipe, native)
+
+static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(np);
+	size_t len;
+	void *fifo;
+	u32 head;
+	u32 tail;
+
+	if (!pipe->fifo) {
+		fifo = qcom_smem_get(pipe->remote_pid,
+				     SMEM_GLINK_NATIVE_XPRT_FIFO_1, &len);
+		if (IS_ERR(fifo)) {
+			pr_err("failed to acquire RX fifo handle: %ld\n",
+			       PTR_ERR(fifo));
+			return 0;
+		}
+
+		pipe->fifo = fifo;
+		pipe->native.length = len;
+	}
+
+	head = le32_to_cpu(*pipe->head);
+	tail = le32_to_cpu(*pipe->tail);
+
+	if (head < tail)
+		return pipe->native.length - tail + head;
+	else
+		return head - tail;
+}
+
+static void glink_smem_rx_peak(struct qcom_glink_pipe *np,
+			       void *data, size_t count)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(np);
+	size_t len;
+	u32 tail;
+
+	tail = le32_to_cpu(*pipe->tail);
+
+	len = min_t(size_t, count, pipe->native.length - tail);
+	if (len) {
+		__ioread32_copy(data, pipe->fifo + tail,
+				len / sizeof(u32));
+	}
+
+	if (len != count) {
+		__ioread32_copy(data + len, pipe->fifo,
+				(count - len) / sizeof(u32));
+	}
+}
+
+static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
+				  size_t count)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(np);
+	u32 tail;
+
+	tail = le32_to_cpu(*pipe->tail);
+
+	tail += count;
+	if (tail > pipe->native.length)
+		tail -= pipe->native.length;
+
+	*pipe->tail = cpu_to_le32(tail);
+}
+
+static size_t glink_smem_tx_avail(struct qcom_glink_pipe *np)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(np);
+	u32 head;
+	u32 tail;
+	u32 avail;
+
+	head = le32_to_cpu(*pipe->head);
+	tail = le32_to_cpu(*pipe->tail);
+
+	if (tail <= head)
+		avail = pipe->native.length - head + tail;
+	else
+		avail = tail - head;
+
+	if (avail < (FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE))
+		avail = 0;
+	else
+		avail -= FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE;
+
+	return avail;
+}
+
+static unsigned int glink_smem_tx_write_one(struct glink_smem_pipe *pipe,
+					    unsigned int head,
+					    const void *data, size_t count)
+{
+	size_t len;
+
+	len = min_t(size_t, count, pipe->native.length - head);
+	if (len)
+		memcpy(pipe->fifo + head, data, len);
+
+	if (len != count)
+		memcpy(pipe->fifo, data + len, count - len);
+
+	head += count;
+	if (head >= pipe->native.length)
+		head -= pipe->native.length;
+
+	return head;
+}
+
+static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe,
+				const void *hdr, size_t hlen,
+				const void *data, size_t dlen)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(glink_pipe);
+	unsigned int head;
+
+	head = le32_to_cpu(*pipe->head);
+
+	head = glink_smem_tx_write_one(pipe, head, hdr, hlen);
+	head = glink_smem_tx_write_one(pipe, head, data, dlen);
+
+	/* Ensure head is always aligned to 8 bytes */
+	head = ALIGN(head, 8);
+	if (head >= pipe->native.length)
+		head -= pipe->native.length;
+
+	*pipe->head = cpu_to_le32(head);
+}
+
+struct qcom_glink *qcom_glink_smem_register(struct device *parent,
+					    struct device_node *node)
+{
+	struct glink_smem_pipe *rx_pipe;
+	struct glink_smem_pipe *tx_pipe;
+	struct qcom_glink *glink;
+	struct device *dev;
+	u32 remote_pid;
+	__le32 *descs;
+	size_t size;
+	int ret;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+
+	dev->parent = parent;
+	dev->of_node = node;
+	dev_set_name(dev, "%s:%s", dev_name(parent), node->name);
+	ret = device_register(dev);
+	if (ret) {
+		pr_err("failed to register glink edge\n");
+		return ERR_PTR(ret);
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,remote-pid",
+				   &remote_pid);
+	if (ret) {
+		dev_err(dev, "failed to parse qcom,remote-pid\n");
+		goto err_put_dev;
+	}
+
+	rx_pipe = devm_kzalloc(dev, sizeof(*rx_pipe), GFP_KERNEL);
+	tx_pipe = devm_kzalloc(dev, sizeof(*tx_pipe), GFP_KERNEL);
+	if (!rx_pipe || !tx_pipe) {
+		ret = -ENOMEM;
+		goto err_put_dev;
+	}
+
+	ret = qcom_smem_alloc(remote_pid,
+			      SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, 32);
+	if (ret && ret != -EEXIST) {
+		dev_err(dev, "failed to allocate glink descriptors\n");
+		goto err_put_dev;
+	}
+
+	descs = qcom_smem_get(remote_pid,
+			      SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, &size);
+	if (IS_ERR(descs)) {
+		dev_err(dev, "failed to acquire xprt descriptor\n");
+		ret = PTR_ERR(descs);
+		goto err_put_dev;
+	}
+
+	if (size != 32) {
+		dev_err(dev, "glink descriptor of invalid size\n");
+		ret = -EINVAL;
+		goto err_put_dev;
+	}
+
+	tx_pipe->tail = &descs[0];
+	tx_pipe->head = &descs[1];
+	rx_pipe->tail = &descs[2];
+	rx_pipe->head = &descs[3];
+
+	ret = qcom_smem_alloc(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
+			      SZ_16K);
+	if (ret && ret != -EEXIST) {
+		dev_err(dev, "failed to allocate TX fifo\n");
+		goto err_put_dev;
+	}
+
+	tx_pipe->fifo = qcom_smem_get(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
+				      &tx_pipe->native.length);
+	if (IS_ERR(tx_pipe->fifo)) {
+		dev_err(dev, "failed to acquire TX fifo\n");
+		ret = PTR_ERR(tx_pipe->fifo);
+		goto err_put_dev;
+	}
+
+	rx_pipe->native.avail = glink_smem_rx_avail;
+	rx_pipe->native.peak = glink_smem_rx_peak;
+	rx_pipe->native.advance = glink_smem_rx_advance;
+	rx_pipe->remote_pid = remote_pid;
+
+	tx_pipe->native.avail = glink_smem_tx_avail;
+	tx_pipe->native.write = glink_smem_tx_write;
+	tx_pipe->remote_pid = remote_pid;
+
+	*rx_pipe->tail = 0;
+	*tx_pipe->head = 0;
+
+	glink = qcom_glink_native_probe(dev,
+					&rx_pipe->native, &tx_pipe->native);
+	if (IS_ERR(glink)) {
+		ret = PTR_ERR(glink);
+		goto err_put_dev;
+	}
+
+	return glink;
+
+err_put_dev:
+	put_device(dev);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(qcom_glink_smem_register);
+
+void qcom_glink_smem_unregister(struct qcom_glink *glink)
+{
+	qcom_glink_native_remove(glink);
+}
+EXPORT_SYMBOL_GPL(qcom_glink_smem_unregister);
+
+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm GLINK SMEM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/rpmsg/qcom_glink.h b/include/linux/rpmsg/qcom_glink.h
new file mode 100644
index 0000000..a622f02
--- /dev/null
+++ b/include/linux/rpmsg/qcom_glink.h
@@ -0,0 +1,27 @@
+#ifndef _LINUX_RPMSG_QCOM_GLINK_H
+#define _LINUX_RPMSG_QCOM_GLINK_H
+
+#include <linux/device.h>
+
+struct qcom_glink;
+
+#if IS_ENABLED(CONFIG_RPMSG_QCOM_GLINK_SMEM)
+
+struct qcom_glink *qcom_glink_smem_register(struct device *parent,
+					    struct device_node *node);
+void qcom_glink_smem_unregister(struct qcom_glink *glink);
+
+#else
+
+static inline struct qcom_glink *
+qcom_glink_smem_register(struct device *parent,
+			 struct device_node *node)
+{
+	return NULL;
+}
+
+static inline void qcom_glink_smem_unregister(struct qcom_glink *glink) {}
+
+#endif
+
+#endif
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 06/18] rpmsg: glink: Introduce glink smem based transport
@ 2017-08-16 17:18   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

From: Bjorn Andersson <bjorn.andersson@linaro.org>

The glink protocol supports different types of
transports (shared memory). With the core protocol
remaining the same, the way the transport's memory is
probed and accessed is different. So add support for
glink's smem based transports.

Adding a new smem transport register function and the
fifo accessors for the same.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/Kconfig            |  10 ++
 drivers/rpmsg/Makefile           |   1 +
 drivers/rpmsg/qcom_glink_smem.c  | 304 +++++++++++++++++++++++++++++++++++++++
 include/linux/rpmsg/qcom_glink.h |  27 ++++
 4 files changed, 342 insertions(+)
 create mode 100644 drivers/rpmsg/qcom_glink_smem.c
 create mode 100644 include/linux/rpmsg/qcom_glink.h

diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index ac33688..4bd9ba3 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -27,6 +27,16 @@ config RPMSG_QCOM_GLINK_RPM
 	  which serves as a channel for communication with the RPM in GLINK
 	  enabled systems.
 
+config RPMSG_QCOM_GLINK_SMEM
+	tristate "Qualcomm SMEM Glink driver"
+	select RPMSG_QCOM_GLINK_NATIVE
+	depends on HAS_IOMEM
+	depends on MAILBOX
+	help
+	  Say y here to enable support for the GLINK SMEM communication driver,
+	  which provides support for using the GLINK communication protocol
+	  over SMEM.
+
 config RPMSG_QCOM_SMD
 	tristate "Qualcomm Shared Memory Driver (SMD)"
 	depends on QCOM_SMEM
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index 09a756c..c71f4ab 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -2,5 +2,6 @@ obj-$(CONFIG_RPMSG)		+= rpmsg_core.o
 obj-$(CONFIG_RPMSG_CHAR)	+= rpmsg_char.o
 obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
 obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o
+obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o
 obj-$(CONFIG_RPMSG_QCOM_SMD)	+= qcom_smd.o
 obj-$(CONFIG_RPMSG_VIRTIO)	+= virtio_rpmsg_bus.o
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
new file mode 100644
index 0000000..defa10b
--- /dev/null
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2016, Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
+#include <linux/rpmsg.h>
+#include <linux/idr.h>
+#include <linux/circ_buf.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/sizes.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include <linux/list.h>
+
+#include <linux/delay.h>
+#include <linux/rpmsg.h>
+#include <linux/rpmsg/qcom_glink.h>
+
+#include "qcom_glink_native.h"
+
+#define FIFO_FULL_RESERVE 8
+#define FIFO_ALIGNMENT 8
+#define TX_BLOCKED_CMD_RESERVE 8 /* size of struct read_notif_request */
+
+#define SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR	478
+#define SMEM_GLINK_NATIVE_XPRT_FIFO_0		479
+#define SMEM_GLINK_NATIVE_XPRT_FIFO_1		480
+
+struct glink_smem_pipe {
+	struct qcom_glink_pipe native;
+
+	__le32 *tail;
+	__le32 *head;
+
+	void *fifo;
+
+	int remote_pid;
+};
+
+#define to_smem_pipe(p) container_of(p, struct glink_smem_pipe, native)
+
+static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(np);
+	size_t len;
+	void *fifo;
+	u32 head;
+	u32 tail;
+
+	if (!pipe->fifo) {
+		fifo = qcom_smem_get(pipe->remote_pid,
+				     SMEM_GLINK_NATIVE_XPRT_FIFO_1, &len);
+		if (IS_ERR(fifo)) {
+			pr_err("failed to acquire RX fifo handle: %ld\n",
+			       PTR_ERR(fifo));
+			return 0;
+		}
+
+		pipe->fifo = fifo;
+		pipe->native.length = len;
+	}
+
+	head = le32_to_cpu(*pipe->head);
+	tail = le32_to_cpu(*pipe->tail);
+
+	if (head < tail)
+		return pipe->native.length - tail + head;
+	else
+		return head - tail;
+}
+
+static void glink_smem_rx_peak(struct qcom_glink_pipe *np,
+			       void *data, size_t count)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(np);
+	size_t len;
+	u32 tail;
+
+	tail = le32_to_cpu(*pipe->tail);
+
+	len = min_t(size_t, count, pipe->native.length - tail);
+	if (len) {
+		__ioread32_copy(data, pipe->fifo + tail,
+				len / sizeof(u32));
+	}
+
+	if (len != count) {
+		__ioread32_copy(data + len, pipe->fifo,
+				(count - len) / sizeof(u32));
+	}
+}
+
+static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
+				  size_t count)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(np);
+	u32 tail;
+
+	tail = le32_to_cpu(*pipe->tail);
+
+	tail += count;
+	if (tail > pipe->native.length)
+		tail -= pipe->native.length;
+
+	*pipe->tail = cpu_to_le32(tail);
+}
+
+static size_t glink_smem_tx_avail(struct qcom_glink_pipe *np)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(np);
+	u32 head;
+	u32 tail;
+	u32 avail;
+
+	head = le32_to_cpu(*pipe->head);
+	tail = le32_to_cpu(*pipe->tail);
+
+	if (tail <= head)
+		avail = pipe->native.length - head + tail;
+	else
+		avail = tail - head;
+
+	if (avail < (FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE))
+		avail = 0;
+	else
+		avail -= FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE;
+
+	return avail;
+}
+
+static unsigned int glink_smem_tx_write_one(struct glink_smem_pipe *pipe,
+					    unsigned int head,
+					    const void *data, size_t count)
+{
+	size_t len;
+
+	len = min_t(size_t, count, pipe->native.length - head);
+	if (len)
+		memcpy(pipe->fifo + head, data, len);
+
+	if (len != count)
+		memcpy(pipe->fifo, data + len, count - len);
+
+	head += count;
+	if (head >= pipe->native.length)
+		head -= pipe->native.length;
+
+	return head;
+}
+
+static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe,
+				const void *hdr, size_t hlen,
+				const void *data, size_t dlen)
+{
+	struct glink_smem_pipe *pipe = to_smem_pipe(glink_pipe);
+	unsigned int head;
+
+	head = le32_to_cpu(*pipe->head);
+
+	head = glink_smem_tx_write_one(pipe, head, hdr, hlen);
+	head = glink_smem_tx_write_one(pipe, head, data, dlen);
+
+	/* Ensure head is always aligned to 8 bytes */
+	head = ALIGN(head, 8);
+	if (head >= pipe->native.length)
+		head -= pipe->native.length;
+
+	*pipe->head = cpu_to_le32(head);
+}
+
+struct qcom_glink *qcom_glink_smem_register(struct device *parent,
+					    struct device_node *node)
+{
+	struct glink_smem_pipe *rx_pipe;
+	struct glink_smem_pipe *tx_pipe;
+	struct qcom_glink *glink;
+	struct device *dev;
+	u32 remote_pid;
+	__le32 *descs;
+	size_t size;
+	int ret;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
+
+	dev->parent = parent;
+	dev->of_node = node;
+	dev_set_name(dev, "%s:%s", dev_name(parent), node->name);
+	ret = device_register(dev);
+	if (ret) {
+		pr_err("failed to register glink edge\n");
+		return ERR_PTR(ret);
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,remote-pid",
+				   &remote_pid);
+	if (ret) {
+		dev_err(dev, "failed to parse qcom,remote-pid\n");
+		goto err_put_dev;
+	}
+
+	rx_pipe = devm_kzalloc(dev, sizeof(*rx_pipe), GFP_KERNEL);
+	tx_pipe = devm_kzalloc(dev, sizeof(*tx_pipe), GFP_KERNEL);
+	if (!rx_pipe || !tx_pipe) {
+		ret = -ENOMEM;
+		goto err_put_dev;
+	}
+
+	ret = qcom_smem_alloc(remote_pid,
+			      SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, 32);
+	if (ret && ret != -EEXIST) {
+		dev_err(dev, "failed to allocate glink descriptors\n");
+		goto err_put_dev;
+	}
+
+	descs = qcom_smem_get(remote_pid,
+			      SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, &size);
+	if (IS_ERR(descs)) {
+		dev_err(dev, "failed to acquire xprt descriptor\n");
+		ret = PTR_ERR(descs);
+		goto err_put_dev;
+	}
+
+	if (size != 32) {
+		dev_err(dev, "glink descriptor of invalid size\n");
+		ret = -EINVAL;
+		goto err_put_dev;
+	}
+
+	tx_pipe->tail = &descs[0];
+	tx_pipe->head = &descs[1];
+	rx_pipe->tail = &descs[2];
+	rx_pipe->head = &descs[3];
+
+	ret = qcom_smem_alloc(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
+			      SZ_16K);
+	if (ret && ret != -EEXIST) {
+		dev_err(dev, "failed to allocate TX fifo\n");
+		goto err_put_dev;
+	}
+
+	tx_pipe->fifo = qcom_smem_get(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
+				      &tx_pipe->native.length);
+	if (IS_ERR(tx_pipe->fifo)) {
+		dev_err(dev, "failed to acquire TX fifo\n");
+		ret = PTR_ERR(tx_pipe->fifo);
+		goto err_put_dev;
+	}
+
+	rx_pipe->native.avail = glink_smem_rx_avail;
+	rx_pipe->native.peak = glink_smem_rx_peak;
+	rx_pipe->native.advance = glink_smem_rx_advance;
+	rx_pipe->remote_pid = remote_pid;
+
+	tx_pipe->native.avail = glink_smem_tx_avail;
+	tx_pipe->native.write = glink_smem_tx_write;
+	tx_pipe->remote_pid = remote_pid;
+
+	*rx_pipe->tail = 0;
+	*tx_pipe->head = 0;
+
+	glink = qcom_glink_native_probe(dev,
+					&rx_pipe->native, &tx_pipe->native);
+	if (IS_ERR(glink)) {
+		ret = PTR_ERR(glink);
+		goto err_put_dev;
+	}
+
+	return glink;
+
+err_put_dev:
+	put_device(dev);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(qcom_glink_smem_register);
+
+void qcom_glink_smem_unregister(struct qcom_glink *glink)
+{
+	qcom_glink_native_remove(glink);
+}
+EXPORT_SYMBOL_GPL(qcom_glink_smem_unregister);
+
+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm GLINK SMEM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/rpmsg/qcom_glink.h b/include/linux/rpmsg/qcom_glink.h
new file mode 100644
index 0000000..a622f02
--- /dev/null
+++ b/include/linux/rpmsg/qcom_glink.h
@@ -0,0 +1,27 @@
+#ifndef _LINUX_RPMSG_QCOM_GLINK_H
+#define _LINUX_RPMSG_QCOM_GLINK_H
+
+#include <linux/device.h>
+
+struct qcom_glink;
+
+#if IS_ENABLED(CONFIG_RPMSG_QCOM_GLINK_SMEM)
+
+struct qcom_glink *qcom_glink_smem_register(struct device *parent,
+					    struct device_node *node);
+void qcom_glink_smem_unregister(struct qcom_glink *glink);
+
+#else
+
+static inline struct qcom_glink *
+qcom_glink_smem_register(struct device *parent,
+			 struct device_node *node)
+{
+	return NULL;
+}
+
+static inline void qcom_glink_smem_unregister(struct qcom_glink *glink) {}
+
+#endif
+
+#endif
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 07/18] rpmsg: glink: Fix default case while handling received commands
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

Currently if we receive a command that we still do not
support, then its simply discarded. While doing so, the
RX FIFO pointer also needs to be incremented. Fixing this.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_native.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 1aa92daf..dd22a23 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -540,6 +540,7 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 			ret = 0;
 			break;
 		default:
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
 			ret = -EINVAL;
 			break;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 07/18] rpmsg: glink: Fix default case while handling received commands
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

Currently if we receive a command that we still do not
support, then its simply discarded. While doing so, the
RX FIFO pointer also needs to be incremented. Fixing this.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_native.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 1aa92daf..dd22a23 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -540,6 +540,7 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 			ret = 0;
 			break;
 		default:
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
 			ret = -EINVAL;
 			break;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 08/18] rpmsg: glink: Add support for transport version negotiation
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

G-link supports a version number and feature flags for each transport.
A combination of the version number and feature flags enable/disable:

 (*) G-Link software updates for each edge
 (*) Individual features for each edge

Endpoints negotiate both the version and the supported flags when
the transport is opened and they cannot be changed after negotiation has
been completed.

Each full implementation of G-Link must support a minimum of the current
version, the previous version, and the base negotiation version called v0.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 75 ++++++++++++++++++++++++++++++++++++---
 drivers/rpmsg/qcom_glink_native.h |  5 +++
 drivers/rpmsg/qcom_glink_rpm.c    |  4 ++-
 drivers/rpmsg/qcom_glink_smem.c   |  1 +
 4 files changed, 79 insertions(+), 6 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index dd22a23..4d24561 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -31,6 +31,7 @@
 #include "qcom_glink_native.h"
 
 #define GLINK_NAME_SIZE		32
+#define GLINK_VERSION_1		1
 
 #define RPM_GLINK_CID_MIN	1
 #define RPM_GLINK_CID_MAX	65536
@@ -93,6 +94,9 @@ struct qcom_glink {
 	struct mutex idr_lock;
 	struct idr lcids;
 	struct idr rcids;
+	unsigned long features;
+
+	bool intentless;
 };
 
 enum {
@@ -255,8 +259,8 @@ static int qcom_glink_send_version(struct qcom_glink *glink)
 	struct glink_msg msg;
 
 	msg.cmd = cpu_to_le16(RPM_CMD_VERSION);
-	msg.param1 = cpu_to_le16(1);
-	msg.param2 = cpu_to_le32(GLINK_FEATURE_INTENTLESS);
+	msg.param1 = cpu_to_le16(GLINK_VERSION_1);
+	msg.param2 = cpu_to_le32(glink->features);
 
 	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
@@ -266,8 +270,8 @@ static void qcom_glink_send_version_ack(struct qcom_glink *glink)
 	struct glink_msg msg;
 
 	msg.cmd = cpu_to_le16(RPM_CMD_VERSION_ACK);
-	msg.param1 = cpu_to_le16(1);
-	msg.param2 = cpu_to_le32(0);
+	msg.param1 = cpu_to_le16(GLINK_VERSION_1);
+	msg.param2 = cpu_to_le32(glink->features);
 
 	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
@@ -361,6 +365,63 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink,
 	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
 }
 
+/**
+ * qcom_glink_receive_version() - receive version/features from remote system
+ *
+ * @glink:	pointer to transport interface
+ * @r_version:	remote version
+ * @r_features:	remote features
+ *
+ * This function is called in response to a remote-initiated version/feature
+ * negotiation sequence.
+ */
+static void qcom_glink_receive_version(struct qcom_glink *glink,
+				       u32 version,
+				       u32 features)
+{
+	switch (version) {
+	case 0:
+		break;
+	case GLINK_VERSION_1:
+		glink->features &= features;
+		/* FALLTHROUGH */
+	default:
+		qcom_glink_send_version_ack(glink);
+		break;
+	}
+}
+
+/**
+ * qcom_glink_receive_version_ack() - receive negotiation ack from remote system
+ *
+ * @glink:	pointer to transport interface
+ * @r_version:	remote version response
+ * @r_features:	remote features response
+ *
+ * This function is called in response to a local-initiated version/feature
+ * negotiation sequence and is the counter-offer from the remote side based
+ * upon the initial version and feature set requested.
+ */
+static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
+					   u32 version,
+					   u32 features)
+{
+	switch (version) {
+	case 0:
+		/* Version negotiation failed */
+		break;
+	case GLINK_VERSION_1:
+		if (features == glink->features)
+			break;
+
+		glink->features &= features;
+		/* FALLTHROUGH */
+	default:
+		qcom_glink_send_version(glink);
+		break;
+	}
+}
+
 static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 {
 	struct glink_defer_cmd *dcmd;
@@ -908,9 +969,10 @@ static void qcom_glink_work(struct work_struct *work)
 
 		switch (cmd) {
 		case RPM_CMD_VERSION:
-			qcom_glink_send_version_ack(glink);
+			qcom_glink_receive_version(glink, param1, param2);
 			break;
 		case RPM_CMD_VERSION_ACK:
+			qcom_glink_receive_version_ack(glink, param1, param2);
 			break;
 		case RPM_CMD_OPEN:
 			qcom_glink_rx_open(glink, param1, msg->data);
@@ -931,6 +993,7 @@ static void qcom_glink_work(struct work_struct *work)
 }
 
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   unsigned long features,
 					   struct qcom_glink_pipe *rx,
 					   struct qcom_glink_pipe *tx)
 {
@@ -946,6 +1009,8 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 	glink->tx_pipe = tx;
 	glink->rx_pipe = rx;
 
+	glink->features = features;
+
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
 	INIT_LIST_HEAD(&glink->rx_queue);
diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
index d5627a4..f418787 100644
--- a/drivers/rpmsg/qcom_glink_native.h
+++ b/drivers/rpmsg/qcom_glink_native.h
@@ -14,6 +14,10 @@
 #ifndef __QCOM_GLINK_NATIVE_H__
 #define __QCOM_GLINK_NATIVE_H__
 
+#define GLINK_FEATURE_INTENT_REUSE	BIT(0)
+#define GLINK_FEATURE_MIGRATION		BIT(1)
+#define GLINK_FEATURE_TRACER_PKT	BIT(2)
+
 struct qcom_glink_pipe {
 	size_t length;
 
@@ -31,6 +35,7 @@ struct qcom_glink_pipe {
 struct qcom_glink;
 
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   unsigned long features,
 					   struct qcom_glink_pipe *rx,
 					   struct qcom_glink_pipe *tx);
 void qcom_glink_native_remove(struct qcom_glink *glink);
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index cc73af0..7d039cd 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -302,7 +302,9 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	writel(0, tx_pipe->head);
 	writel(0, rx_pipe->tail);
 
-	glink = qcom_glink_native_probe(&pdev->dev, &rx_pipe->native,
+	glink = qcom_glink_native_probe(&pdev->dev,
+					0,
+					&rx_pipe->native,
 					&tx_pipe->native);
 	if (IS_ERR(glink))
 		return PTR_ERR(glink);
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
index defa10b..496a5e3 100644
--- a/drivers/rpmsg/qcom_glink_smem.c
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -278,6 +278,7 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
 	*tx_pipe->head = 0;
 
 	glink = qcom_glink_native_probe(dev,
+					GLINK_FEATURE_TRACER_PKT,
 					&rx_pipe->native, &tx_pipe->native);
 	if (IS_ERR(glink)) {
 		ret = PTR_ERR(glink);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 08/18] rpmsg: glink: Add support for transport version negotiation
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

G-link supports a version number and feature flags for each transport.
A combination of the version number and feature flags enable/disable:

 (*) G-Link software updates for each edge
 (*) Individual features for each edge

Endpoints negotiate both the version and the supported flags when
the transport is opened and they cannot be changed after negotiation has
been completed.

Each full implementation of G-Link must support a minimum of the current
version, the previous version, and the base negotiation version called v0.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 75 ++++++++++++++++++++++++++++++++++++---
 drivers/rpmsg/qcom_glink_native.h |  5 +++
 drivers/rpmsg/qcom_glink_rpm.c    |  4 ++-
 drivers/rpmsg/qcom_glink_smem.c   |  1 +
 4 files changed, 79 insertions(+), 6 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index dd22a23..4d24561 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -31,6 +31,7 @@
 #include "qcom_glink_native.h"
 
 #define GLINK_NAME_SIZE		32
+#define GLINK_VERSION_1		1
 
 #define RPM_GLINK_CID_MIN	1
 #define RPM_GLINK_CID_MAX	65536
@@ -93,6 +94,9 @@ struct qcom_glink {
 	struct mutex idr_lock;
 	struct idr lcids;
 	struct idr rcids;
+	unsigned long features;
+
+	bool intentless;
 };
 
 enum {
@@ -255,8 +259,8 @@ static int qcom_glink_send_version(struct qcom_glink *glink)
 	struct glink_msg msg;
 
 	msg.cmd = cpu_to_le16(RPM_CMD_VERSION);
-	msg.param1 = cpu_to_le16(1);
-	msg.param2 = cpu_to_le32(GLINK_FEATURE_INTENTLESS);
+	msg.param1 = cpu_to_le16(GLINK_VERSION_1);
+	msg.param2 = cpu_to_le32(glink->features);
 
 	return qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
@@ -266,8 +270,8 @@ static void qcom_glink_send_version_ack(struct qcom_glink *glink)
 	struct glink_msg msg;
 
 	msg.cmd = cpu_to_le16(RPM_CMD_VERSION_ACK);
-	msg.param1 = cpu_to_le16(1);
-	msg.param2 = cpu_to_le32(0);
+	msg.param1 = cpu_to_le16(GLINK_VERSION_1);
+	msg.param2 = cpu_to_le32(glink->features);
 
 	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
@@ -361,6 +365,63 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink,
 	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
 }
 
+/**
+ * qcom_glink_receive_version() - receive version/features from remote system
+ *
+ * @glink:	pointer to transport interface
+ * @r_version:	remote version
+ * @r_features:	remote features
+ *
+ * This function is called in response to a remote-initiated version/feature
+ * negotiation sequence.
+ */
+static void qcom_glink_receive_version(struct qcom_glink *glink,
+				       u32 version,
+				       u32 features)
+{
+	switch (version) {
+	case 0:
+		break;
+	case GLINK_VERSION_1:
+		glink->features &= features;
+		/* FALLTHROUGH */
+	default:
+		qcom_glink_send_version_ack(glink);
+		break;
+	}
+}
+
+/**
+ * qcom_glink_receive_version_ack() - receive negotiation ack from remote system
+ *
+ * @glink:	pointer to transport interface
+ * @r_version:	remote version response
+ * @r_features:	remote features response
+ *
+ * This function is called in response to a local-initiated version/feature
+ * negotiation sequence and is the counter-offer from the remote side based
+ * upon the initial version and feature set requested.
+ */
+static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
+					   u32 version,
+					   u32 features)
+{
+	switch (version) {
+	case 0:
+		/* Version negotiation failed */
+		break;
+	case GLINK_VERSION_1:
+		if (features == glink->features)
+			break;
+
+		glink->features &= features;
+		/* FALLTHROUGH */
+	default:
+		qcom_glink_send_version(glink);
+		break;
+	}
+}
+
 static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 {
 	struct glink_defer_cmd *dcmd;
@@ -908,9 +969,10 @@ static void qcom_glink_work(struct work_struct *work)
 
 		switch (cmd) {
 		case RPM_CMD_VERSION:
-			qcom_glink_send_version_ack(glink);
+			qcom_glink_receive_version(glink, param1, param2);
 			break;
 		case RPM_CMD_VERSION_ACK:
+			qcom_glink_receive_version_ack(glink, param1, param2);
 			break;
 		case RPM_CMD_OPEN:
 			qcom_glink_rx_open(glink, param1, msg->data);
@@ -931,6 +993,7 @@ static void qcom_glink_work(struct work_struct *work)
 }
 
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   unsigned long features,
 					   struct qcom_glink_pipe *rx,
 					   struct qcom_glink_pipe *tx)
 {
@@ -946,6 +1009,8 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 	glink->tx_pipe = tx;
 	glink->rx_pipe = rx;
 
+	glink->features = features;
+
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
 	INIT_LIST_HEAD(&glink->rx_queue);
diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
index d5627a4..f418787 100644
--- a/drivers/rpmsg/qcom_glink_native.h
+++ b/drivers/rpmsg/qcom_glink_native.h
@@ -14,6 +14,10 @@
 #ifndef __QCOM_GLINK_NATIVE_H__
 #define __QCOM_GLINK_NATIVE_H__
 
+#define GLINK_FEATURE_INTENT_REUSE	BIT(0)
+#define GLINK_FEATURE_MIGRATION		BIT(1)
+#define GLINK_FEATURE_TRACER_PKT	BIT(2)
+
 struct qcom_glink_pipe {
 	size_t length;
 
@@ -31,6 +35,7 @@ struct qcom_glink_pipe {
 struct qcom_glink;
 
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
+					   unsigned long features,
 					   struct qcom_glink_pipe *rx,
 					   struct qcom_glink_pipe *tx);
 void qcom_glink_native_remove(struct qcom_glink *glink);
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index cc73af0..7d039cd 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -302,7 +302,9 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	writel(0, tx_pipe->head);
 	writel(0, rx_pipe->tail);
 
-	glink = qcom_glink_native_probe(&pdev->dev, &rx_pipe->native,
+	glink = qcom_glink_native_probe(&pdev->dev,
+					0,
+					&rx_pipe->native,
 					&tx_pipe->native);
 	if (IS_ERR(glink))
 		return PTR_ERR(glink);
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
index defa10b..496a5e3 100644
--- a/drivers/rpmsg/qcom_glink_smem.c
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -278,6 +278,7 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
 	*tx_pipe->head = 0;
 
 	glink = qcom_glink_native_probe(dev,
+					GLINK_FEATURE_TRACER_PKT,
 					&rx_pipe->native, &tx_pipe->native);
 	if (IS_ERR(glink)) {
 		ret = PTR_ERR(glink);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 09/18] rpmsg: glink: Fix idr_lock from mutex to spinlock
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

The channel members lcids, rcids synchronised using
the idr_lock is accessed in both atomic/non-atomic
contexts. The readers are not currently synchronised.
That no correct, so add the readers as well under the
lock and use a spinlock.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 58 +++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 18 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 4d24561..acf5558 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -91,7 +91,7 @@ struct qcom_glink {
 
 	struct mutex tx_lock;
 
-	struct mutex idr_lock;
+	spinlock_t idr_lock;
 	struct idr lcids;
 	struct idr rcids;
 	unsigned long features;
@@ -308,14 +308,15 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink,
 	int name_len = strlen(channel->name) + 1;
 	int req_len = ALIGN(sizeof(req.msg) + name_len, 8);
 	int ret;
+	unsigned long flags;
 
 	kref_get(&channel->refcount);
 
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	ret = idr_alloc_cyclic(&glink->lcids, channel,
 			       RPM_GLINK_CID_MIN, RPM_GLINK_CID_MAX,
 			       GFP_KERNEL);
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 	if (ret < 0)
 		return ret;
 
@@ -333,10 +334,10 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink,
 	return 0;
 
 remove_idr:
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_remove(&glink->lcids, channel->lcid);
 	channel->lcid = 0;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	return ret;
 }
@@ -462,6 +463,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 	unsigned int chunk_size;
 	unsigned int left_size;
 	unsigned int rcid;
+	unsigned long flags;
 
 	if (avail < sizeof(hdr)) {
 		dev_dbg(glink->dev, "Not enough data in fifo\n");
@@ -481,7 +483,9 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 		return -EINVAL;
 
 	rcid = le16_to_cpu(hdr.msg.param1);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	channel = idr_find(&glink->rcids, rcid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 	if (!channel) {
 		dev_dbg(glink->dev, "Data on non-existing channel\n");
 
@@ -542,11 +546,13 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
 
+	spin_lock(&glink->idr_lock);
 	channel = idr_find(&glink->lcids, lcid);
 	if (!channel) {
 		dev_err(glink->dev, "Invalid open ack packet\n");
 		return -EINVAL;
 	}
+	spin_unlock(&glink->idr_lock);
 
 	complete(&channel->open_ack);
 
@@ -620,6 +626,7 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
 {
 	struct glink_channel *channel;
 	int ret;
+	unsigned long flags;
 
 	channel = qcom_glink_alloc_channel(glink, name);
 	if (IS_ERR(channel))
@@ -643,9 +650,9 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
 
 err_timeout:
 	/* qcom_glink_send_open_req() did register the channel in lcids*/
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_remove(&glink->lcids, channel->lcid);
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 release_channel:
 	/* Release qcom_glink_send_open_req() reference */
@@ -702,11 +709,14 @@ static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
 	const char *name = chinfo.name;
 	int cid;
 	int ret;
+	unsigned long flags;
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_for_each_entry(&glink->rcids, channel, cid) {
 		if (!strcmp(channel->name, name))
 			break;
 	}
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	if (!channel) {
 		channel = qcom_glink_create_local(glink, name);
@@ -828,11 +838,14 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
 	struct device_node *node;
 	int lcid;
 	int ret;
+	unsigned long flags;
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_for_each_entry(&glink->lcids, channel, lcid) {
 		if (!strcmp(channel->name, name))
 			break;
 	}
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	if (!channel) {
 		channel = qcom_glink_alloc_channel(glink, name);
@@ -843,15 +856,15 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
 		create_device = true;
 	}
 
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_KERNEL);
 	if (ret < 0) {
 		dev_err(glink->dev, "Unable to insert channel into rcid list\n");
-		mutex_unlock(&glink->idr_lock);
+		spin_unlock_irqrestore(&glink->idr_lock, flags);
 		goto free_channel;
 	}
 	channel->rcid = ret;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	complete(&channel->open_req);
 
@@ -885,10 +898,10 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
 free_rpdev:
 	kfree(rpdev);
 rcid_remove:
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_remove(&glink->rcids, channel->rcid);
 	channel->rcid = 0;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 free_channel:
 	/* Release the reference, iff we took it */
 	if (create_device)
@@ -901,8 +914,11 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 {
 	struct rpmsg_channel_info chinfo;
 	struct glink_channel *channel;
+	unsigned long flags;
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	channel = idr_find(&glink->rcids, rcid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 	if (WARN(!channel, "close request on unknown channel\n"))
 		return;
 
@@ -916,10 +932,10 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 
 	qcom_glink_send_close_ack(glink, channel->rcid);
 
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_remove(&glink->rcids, channel->rcid);
 	channel->rcid = 0;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	kref_put(&channel->refcount, qcom_glink_channel_release);
 }
@@ -927,15 +943,18 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
+	unsigned long flags;
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	channel = idr_find(&glink->lcids, lcid);
-	if (WARN(!channel, "close ack on unknown channel\n"))
+	if (WARN(!channel, "close ack on unknown channel\n")) {
+		spin_unlock_irqrestore(&glink->idr_lock, flags);
 		return;
+	}
 
-	mutex_lock(&glink->idr_lock);
 	idr_remove(&glink->lcids, channel->lcid);
 	channel->lcid = 0;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	kref_put(&channel->refcount, qcom_glink_channel_release);
 }
@@ -1016,7 +1035,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 	INIT_LIST_HEAD(&glink->rx_queue);
 	INIT_WORK(&glink->rx_work, qcom_glink_work);
 
-	mutex_init(&glink->idr_lock);
+	spin_lock_init(&glink->idr_lock);
 	idr_init(&glink->lcids);
 	idr_init(&glink->rcids);
 
@@ -1057,6 +1076,7 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
 	struct glink_channel *channel;
 	int cid;
 	int ret;
+	unsigned long flags;
 
 	disable_irq(glink->irq);
 	cancel_work_sync(&glink->rx_work);
@@ -1065,10 +1085,12 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
 	if (ret)
 		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	/* Release any defunct local channels, waiting for close-ack */
 	idr_for_each_entry(&glink->lcids, channel, cid)
 		kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	idr_destroy(&glink->lcids);
 	idr_destroy(&glink->rcids);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 }
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 09/18] rpmsg: glink: Fix idr_lock from mutex to spinlock
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

The channel members lcids, rcids synchronised using
the idr_lock is accessed in both atomic/non-atomic
contexts. The readers are not currently synchronised.
That no correct, so add the readers as well under the
lock and use a spinlock.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 58 +++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 18 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 4d24561..acf5558 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -91,7 +91,7 @@ struct qcom_glink {
 
 	struct mutex tx_lock;
 
-	struct mutex idr_lock;
+	spinlock_t idr_lock;
 	struct idr lcids;
 	struct idr rcids;
 	unsigned long features;
@@ -308,14 +308,15 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink,
 	int name_len = strlen(channel->name) + 1;
 	int req_len = ALIGN(sizeof(req.msg) + name_len, 8);
 	int ret;
+	unsigned long flags;
 
 	kref_get(&channel->refcount);
 
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	ret = idr_alloc_cyclic(&glink->lcids, channel,
 			       RPM_GLINK_CID_MIN, RPM_GLINK_CID_MAX,
 			       GFP_KERNEL);
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 	if (ret < 0)
 		return ret;
 
@@ -333,10 +334,10 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink,
 	return 0;
 
 remove_idr:
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_remove(&glink->lcids, channel->lcid);
 	channel->lcid = 0;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	return ret;
 }
@@ -462,6 +463,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 	unsigned int chunk_size;
 	unsigned int left_size;
 	unsigned int rcid;
+	unsigned long flags;
 
 	if (avail < sizeof(hdr)) {
 		dev_dbg(glink->dev, "Not enough data in fifo\n");
@@ -481,7 +483,9 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 		return -EINVAL;
 
 	rcid = le16_to_cpu(hdr.msg.param1);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	channel = idr_find(&glink->rcids, rcid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 	if (!channel) {
 		dev_dbg(glink->dev, "Data on non-existing channel\n");
 
@@ -542,11 +546,13 @@ static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
 
+	spin_lock(&glink->idr_lock);
 	channel = idr_find(&glink->lcids, lcid);
 	if (!channel) {
 		dev_err(glink->dev, "Invalid open ack packet\n");
 		return -EINVAL;
 	}
+	spin_unlock(&glink->idr_lock);
 
 	complete(&channel->open_ack);
 
@@ -620,6 +626,7 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
 {
 	struct glink_channel *channel;
 	int ret;
+	unsigned long flags;
 
 	channel = qcom_glink_alloc_channel(glink, name);
 	if (IS_ERR(channel))
@@ -643,9 +650,9 @@ static struct glink_channel *qcom_glink_create_local(struct qcom_glink *glink,
 
 err_timeout:
 	/* qcom_glink_send_open_req() did register the channel in lcids*/
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_remove(&glink->lcids, channel->lcid);
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 release_channel:
 	/* Release qcom_glink_send_open_req() reference */
@@ -702,11 +709,14 @@ static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
 	const char *name = chinfo.name;
 	int cid;
 	int ret;
+	unsigned long flags;
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_for_each_entry(&glink->rcids, channel, cid) {
 		if (!strcmp(channel->name, name))
 			break;
 	}
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	if (!channel) {
 		channel = qcom_glink_create_local(glink, name);
@@ -828,11 +838,14 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
 	struct device_node *node;
 	int lcid;
 	int ret;
+	unsigned long flags;
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_for_each_entry(&glink->lcids, channel, lcid) {
 		if (!strcmp(channel->name, name))
 			break;
 	}
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	if (!channel) {
 		channel = qcom_glink_alloc_channel(glink, name);
@@ -843,15 +856,15 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
 		create_device = true;
 	}
 
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_KERNEL);
 	if (ret < 0) {
 		dev_err(glink->dev, "Unable to insert channel into rcid list\n");
-		mutex_unlock(&glink->idr_lock);
+		spin_unlock_irqrestore(&glink->idr_lock, flags);
 		goto free_channel;
 	}
 	channel->rcid = ret;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	complete(&channel->open_req);
 
@@ -885,10 +898,10 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid,
 free_rpdev:
 	kfree(rpdev);
 rcid_remove:
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_remove(&glink->rcids, channel->rcid);
 	channel->rcid = 0;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 free_channel:
 	/* Release the reference, iff we took it */
 	if (create_device)
@@ -901,8 +914,11 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 {
 	struct rpmsg_channel_info chinfo;
 	struct glink_channel *channel;
+	unsigned long flags;
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	channel = idr_find(&glink->rcids, rcid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 	if (WARN(!channel, "close request on unknown channel\n"))
 		return;
 
@@ -916,10 +932,10 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 
 	qcom_glink_send_close_ack(glink, channel->rcid);
 
-	mutex_lock(&glink->idr_lock);
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	idr_remove(&glink->rcids, channel->rcid);
 	channel->rcid = 0;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	kref_put(&channel->refcount, qcom_glink_channel_release);
 }
@@ -927,15 +943,18 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 static void qcom_glink_rx_close_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
+	unsigned long flags;
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	channel = idr_find(&glink->lcids, lcid);
-	if (WARN(!channel, "close ack on unknown channel\n"))
+	if (WARN(!channel, "close ack on unknown channel\n")) {
+		spin_unlock_irqrestore(&glink->idr_lock, flags);
 		return;
+	}
 
-	mutex_lock(&glink->idr_lock);
 	idr_remove(&glink->lcids, channel->lcid);
 	channel->lcid = 0;
-	mutex_unlock(&glink->idr_lock);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 
 	kref_put(&channel->refcount, qcom_glink_channel_release);
 }
@@ -1016,7 +1035,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 	INIT_LIST_HEAD(&glink->rx_queue);
 	INIT_WORK(&glink->rx_work, qcom_glink_work);
 
-	mutex_init(&glink->idr_lock);
+	spin_lock_init(&glink->idr_lock);
 	idr_init(&glink->lcids);
 	idr_init(&glink->rcids);
 
@@ -1057,6 +1076,7 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
 	struct glink_channel *channel;
 	int cid;
 	int ret;
+	unsigned long flags;
 
 	disable_irq(glink->irq);
 	cancel_work_sync(&glink->rx_work);
@@ -1065,10 +1085,12 @@ void qcom_glink_native_remove(struct qcom_glink *glink)
 	if (ret)
 		dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret);
 
+	spin_lock_irqsave(&glink->idr_lock, flags);
 	/* Release any defunct local channels, waiting for close-ack */
 	idr_for_each_entry(&glink->lcids, channel, cid)
 		kref_put(&channel->refcount, qcom_glink_channel_release);
 
 	idr_destroy(&glink->lcids);
 	idr_destroy(&glink->rcids);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
 }
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 10/18] rpmsg: glink: Add support for TX intents
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

Intents are nothing but pre-allocated buffers of
appropriate size that are allocated on the local
side and communicated to the remote side and the
remote stores the list of intent ids that it is
informed.

Later when remote side is intenting to send data,
it picks up a right intent (based on the size) and
sends the data buffer and the intent id. Local side
receives the data and copies it to the local intent
buffer.

The whole idea is to avoid stalls on the transport
for allocating memory, used for copy based transports.

When the remote request to allocate buffers using
CMD_RX_INTENT_REQ, we allocate buffers of requested
size, store the buffer id locally and also communicate
the intent id to the remote.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 161 +++++++++++++++++++++++++++++++++++++-
 drivers/rpmsg/qcom_glink_native.h |   3 +-
 drivers/rpmsg/qcom_glink_rpm.c    |   3 +-
 drivers/rpmsg/qcom_glink_smem.c   |   5 +-
 4 files changed, 167 insertions(+), 5 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index acf5558..cbc9f9e 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -60,6 +60,25 @@ struct glink_defer_cmd {
 };
 
 /**
+ * RX intent
+ *
+ * data: pointer to the data (may be NULL for zero-copy)
+ * id: remote or local intent ID
+ * size: size of the original intent (do not modify)
+ * reuse: To mark if the intent can be reused after first use
+ * in_use: To mark if intent is already in use for the channel
+ * offset: next write offset (initially 0)
+ */
+struct glink_core_rx_intent {
+	void *data;
+	u32 id;
+	size_t size;
+	bool reuse;
+	bool in_use;
+	u32 offset;
+};
+
+/**
  * struct glink_rpm - driver context, relates to one remote subsystem
  * @dev:	reference to the associated struct device
  * @doorbell:	"rpm_hlos" ipc doorbell
@@ -116,6 +135,8 @@ enum {
  * @name:	unique channel name/identifier
  * @lcid:	channel id, in local space
  * @rcid:	channel id, in remote space
+ * @intent_lock: lock for protection of @liids
+ * @liids:	idr of all local intents
  * @buf:	receive buffer, for gathering fragments
  * @buf_offset:	write offset in @buf
  * @buf_size:	size of current @buf
@@ -136,6 +157,9 @@ struct glink_channel {
 	unsigned int lcid;
 	unsigned int rcid;
 
+	spinlock_t intent_lock;
+	struct idr liids;
+
 	void *buf;
 	int buf_offset;
 	int buf_size;
@@ -153,6 +177,9 @@ struct glink_channel {
 #define RPM_CMD_OPEN			2
 #define RPM_CMD_CLOSE			3
 #define RPM_CMD_OPEN_ACK		4
+#define RPM_CMD_INTENT			5
+#define RPM_CMD_RX_INTENT_REQ		7
+#define RPM_CMD_RX_INTENT_REQ_ACK	8
 #define RPM_CMD_TX_DATA			9
 #define RPM_CMD_CLOSE_ACK		11
 #define RPM_CMD_TX_DATA_CONT		12
@@ -177,6 +204,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
 	init_completion(&channel->open_req);
 	init_completion(&channel->open_ack);
 
+	idr_init(&channel->liids);
 	kref_init(&channel->refcount);
 
 	return channel;
@@ -187,6 +215,7 @@ static void qcom_glink_channel_release(struct kref *ref)
 	struct glink_channel *channel = container_of(ref, struct glink_channel,
 						     refcount);
 
+	idr_destroy(&channel->liids);
 	kfree(channel->name);
 	kfree(channel);
 }
@@ -423,6 +452,130 @@ static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
 	}
 }
 
+/**
+ * qcom_glink_send_intent_req_ack() - convert an rx intent request ack cmd to
+				      wire format and transmit
+ * @glink:	The transport to transmit on.
+ * @channel:	The glink channel
+ * @granted:	The request response to encode.
+ *
+ * Return: 0 on success or standard Linux error code.
+ */
+static int qcom_glink_send_intent_req_ack(struct qcom_glink *glink,
+					  struct glink_channel *channel,
+					  bool granted)
+{
+	struct glink_msg msg;
+
+	msg.cmd = cpu_to_le16(RPM_CMD_RX_INTENT_REQ_ACK);
+	msg.param1 = cpu_to_le16(channel->lcid);
+	msg.param2 = cpu_to_le32(granted);
+
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+
+	return 0;
+}
+
+/**
+ * tx_cmd_local_rx_intent() - convert an rx intent cmd to wire format and
+ *			   transmit
+ * @glink:	The transport to transmit on.
+ * @channel:	The local channel
+ * @size:	The intent to pass on to remote.
+ *
+ * Return: 0 on success or standard Linux error code.
+ */
+static int qcom_glink_advertise_intent(struct qcom_glink *glink,
+				       struct glink_channel *channel,
+				       struct glink_core_rx_intent *intent)
+{
+	struct command {
+		u16 id;
+		u16 lcid;
+		u32 count;
+		u32 size;
+		u32 liid;
+	} __packed;
+	struct command cmd;
+
+	cmd.id = cpu_to_le16(RPM_CMD_INTENT);
+	cmd.lcid = cpu_to_le16(channel->lcid);
+	cmd.count = cpu_to_le32(1);
+	cmd.size = cpu_to_le32(intent->size);
+	cmd.liid = cpu_to_le32(intent->id);
+
+	qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
+
+	return 0;
+}
+
+static struct glink_core_rx_intent *
+qcom_glink_alloc_intent(struct qcom_glink *glink,
+			struct glink_channel *channel,
+			size_t size,
+			bool reuseable)
+{
+	struct glink_core_rx_intent *intent;
+	int ret;
+	unsigned long flags;
+
+	intent = kzalloc(sizeof(*intent), GFP_KERNEL);
+
+	if (!intent)
+		return NULL;
+
+	intent->data = kzalloc(size, GFP_KERNEL);
+	if (!intent->data)
+		return NULL;
+
+	spin_lock_irqsave(&channel->intent_lock, flags);
+	ret = idr_alloc_cyclic(&channel->liids, intent, 1, -1, GFP_ATOMIC);
+	if (ret < 0) {
+		spin_unlock_irqrestore(&channel->intent_lock, flags);
+		return NULL;
+	}
+	spin_unlock_irqrestore(&channel->intent_lock, flags);
+
+	intent->id = ret;
+	intent->size = size;
+	intent->reuse = reuseable;
+
+	return intent;
+}
+
+/**
+ * glink_core_rx_cmd_remote_rx_intent_req() - Receive a request for rx_intent
+ *					    from remote side
+ * if_ptr:      Pointer to the transport interface
+ * rcid:	Remote channel ID
+ * size:	size of the intent
+ *
+ * The function searches for the local channel to which the request for
+ * rx_intent has arrived and allocates and notifies the remote back
+ */
+static void qcom_glink_handle_intent_req(struct qcom_glink *glink,
+					 u32 cid, size_t size)
+{
+	struct glink_core_rx_intent *intent;
+	struct glink_channel *channel;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glink->idr_lock, flags);
+	channel = idr_find(&glink->rcids, cid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
+
+	if (!channel) {
+		pr_err("%s channel not found for cid %d\n", __func__, cid);
+		return;
+	}
+
+	intent = qcom_glink_alloc_intent(glink, channel, size, false);
+	if (intent)
+		qcom_glink_advertise_intent(glink, channel, intent);
+
+	qcom_glink_send_intent_req_ack(glink, channel, !!intent);
+}
+
 static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 {
 	struct glink_defer_cmd *dcmd;
@@ -585,6 +738,7 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 		case RPM_CMD_VERSION_ACK:
 		case RPM_CMD_CLOSE:
 		case RPM_CMD_CLOSE_ACK:
+		case RPM_CMD_RX_INTENT_REQ:
 			ret = qcom_glink_rx_defer(glink, 0);
 			break;
 		case RPM_CMD_OPEN_ACK:
@@ -1002,6 +1156,9 @@ static void qcom_glink_work(struct work_struct *work)
 		case RPM_CMD_CLOSE_ACK:
 			qcom_glink_rx_close_ack(glink, param1);
 			break;
+		case RPM_CMD_RX_INTENT_REQ:
+			qcom_glink_handle_intent_req(glink, param1, param2);
+			break;
 		default:
 			WARN(1, "Unknown defer object %d\n", cmd);
 			break;
@@ -1014,7 +1171,8 @@ static void qcom_glink_work(struct work_struct *work)
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 					   unsigned long features,
 					   struct qcom_glink_pipe *rx,
-					   struct qcom_glink_pipe *tx)
+					   struct qcom_glink_pipe *tx,
+					   bool intentless)
 {
 	int irq;
 	int ret;
@@ -1029,6 +1187,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 	glink->rx_pipe = rx;
 
 	glink->features = features;
+	glink->intentless = intentless;
 
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
index f418787..d7538c3 100644
--- a/drivers/rpmsg/qcom_glink_native.h
+++ b/drivers/rpmsg/qcom_glink_native.h
@@ -37,7 +37,8 @@ struct qcom_glink_pipe {
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 					   unsigned long features,
 					   struct qcom_glink_pipe *rx,
-					   struct qcom_glink_pipe *tx);
+					   struct qcom_glink_pipe *tx,
+					   bool intentless);
 void qcom_glink_native_remove(struct qcom_glink *glink);
 
 #endif
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 7d039cd..5a86e08 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -305,7 +305,8 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	glink = qcom_glink_native_probe(&pdev->dev,
 					0,
 					&rx_pipe->native,
-					&tx_pipe->native);
+					&tx_pipe->native,
+					true);
 	if (IS_ERR(glink))
 		return PTR_ERR(glink);
 
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
index 496a5e3..e792895 100644
--- a/drivers/rpmsg/qcom_glink_smem.c
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -278,8 +278,9 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
 	*tx_pipe->head = 0;
 
 	glink = qcom_glink_native_probe(dev,
-					GLINK_FEATURE_TRACER_PKT,
-					&rx_pipe->native, &tx_pipe->native);
+					GLINK_FEATURE_INTENT_REUSE,
+					&rx_pipe->native, &tx_pipe->native,
+					false);
 	if (IS_ERR(glink)) {
 		ret = PTR_ERR(glink);
 		goto err_put_dev;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 10/18] rpmsg: glink: Add support for TX intents
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

Intents are nothing but pre-allocated buffers of
appropriate size that are allocated on the local
side and communicated to the remote side and the
remote stores the list of intent ids that it is
informed.

Later when remote side is intenting to send data,
it picks up a right intent (based on the size) and
sends the data buffer and the intent id. Local side
receives the data and copies it to the local intent
buffer.

The whole idea is to avoid stalls on the transport
for allocating memory, used for copy based transports.

When the remote request to allocate buffers using
CMD_RX_INTENT_REQ, we allocate buffers of requested
size, store the buffer id locally and also communicate
the intent id to the remote.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 161 +++++++++++++++++++++++++++++++++++++-
 drivers/rpmsg/qcom_glink_native.h |   3 +-
 drivers/rpmsg/qcom_glink_rpm.c    |   3 +-
 drivers/rpmsg/qcom_glink_smem.c   |   5 +-
 4 files changed, 167 insertions(+), 5 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index acf5558..cbc9f9e 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -60,6 +60,25 @@ struct glink_defer_cmd {
 };
 
 /**
+ * RX intent
+ *
+ * data: pointer to the data (may be NULL for zero-copy)
+ * id: remote or local intent ID
+ * size: size of the original intent (do not modify)
+ * reuse: To mark if the intent can be reused after first use
+ * in_use: To mark if intent is already in use for the channel
+ * offset: next write offset (initially 0)
+ */
+struct glink_core_rx_intent {
+	void *data;
+	u32 id;
+	size_t size;
+	bool reuse;
+	bool in_use;
+	u32 offset;
+};
+
+/**
  * struct glink_rpm - driver context, relates to one remote subsystem
  * @dev:	reference to the associated struct device
  * @doorbell:	"rpm_hlos" ipc doorbell
@@ -116,6 +135,8 @@ enum {
  * @name:	unique channel name/identifier
  * @lcid:	channel id, in local space
  * @rcid:	channel id, in remote space
+ * @intent_lock: lock for protection of @liids
+ * @liids:	idr of all local intents
  * @buf:	receive buffer, for gathering fragments
  * @buf_offset:	write offset in @buf
  * @buf_size:	size of current @buf
@@ -136,6 +157,9 @@ struct glink_channel {
 	unsigned int lcid;
 	unsigned int rcid;
 
+	spinlock_t intent_lock;
+	struct idr liids;
+
 	void *buf;
 	int buf_offset;
 	int buf_size;
@@ -153,6 +177,9 @@ struct glink_channel {
 #define RPM_CMD_OPEN			2
 #define RPM_CMD_CLOSE			3
 #define RPM_CMD_OPEN_ACK		4
+#define RPM_CMD_INTENT			5
+#define RPM_CMD_RX_INTENT_REQ		7
+#define RPM_CMD_RX_INTENT_REQ_ACK	8
 #define RPM_CMD_TX_DATA			9
 #define RPM_CMD_CLOSE_ACK		11
 #define RPM_CMD_TX_DATA_CONT		12
@@ -177,6 +204,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
 	init_completion(&channel->open_req);
 	init_completion(&channel->open_ack);
 
+	idr_init(&channel->liids);
 	kref_init(&channel->refcount);
 
 	return channel;
@@ -187,6 +215,7 @@ static void qcom_glink_channel_release(struct kref *ref)
 	struct glink_channel *channel = container_of(ref, struct glink_channel,
 						     refcount);
 
+	idr_destroy(&channel->liids);
 	kfree(channel->name);
 	kfree(channel);
 }
@@ -423,6 +452,130 @@ static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
 	}
 }
 
+/**
+ * qcom_glink_send_intent_req_ack() - convert an rx intent request ack cmd to
+				      wire format and transmit
+ * @glink:	The transport to transmit on.
+ * @channel:	The glink channel
+ * @granted:	The request response to encode.
+ *
+ * Return: 0 on success or standard Linux error code.
+ */
+static int qcom_glink_send_intent_req_ack(struct qcom_glink *glink,
+					  struct glink_channel *channel,
+					  bool granted)
+{
+	struct glink_msg msg;
+
+	msg.cmd = cpu_to_le16(RPM_CMD_RX_INTENT_REQ_ACK);
+	msg.param1 = cpu_to_le16(channel->lcid);
+	msg.param2 = cpu_to_le32(granted);
+
+	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
+
+	return 0;
+}
+
+/**
+ * tx_cmd_local_rx_intent() - convert an rx intent cmd to wire format and
+ *			   transmit
+ * @glink:	The transport to transmit on.
+ * @channel:	The local channel
+ * @size:	The intent to pass on to remote.
+ *
+ * Return: 0 on success or standard Linux error code.
+ */
+static int qcom_glink_advertise_intent(struct qcom_glink *glink,
+				       struct glink_channel *channel,
+				       struct glink_core_rx_intent *intent)
+{
+	struct command {
+		u16 id;
+		u16 lcid;
+		u32 count;
+		u32 size;
+		u32 liid;
+	} __packed;
+	struct command cmd;
+
+	cmd.id = cpu_to_le16(RPM_CMD_INTENT);
+	cmd.lcid = cpu_to_le16(channel->lcid);
+	cmd.count = cpu_to_le32(1);
+	cmd.size = cpu_to_le32(intent->size);
+	cmd.liid = cpu_to_le32(intent->id);
+
+	qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
+
+	return 0;
+}
+
+static struct glink_core_rx_intent *
+qcom_glink_alloc_intent(struct qcom_glink *glink,
+			struct glink_channel *channel,
+			size_t size,
+			bool reuseable)
+{
+	struct glink_core_rx_intent *intent;
+	int ret;
+	unsigned long flags;
+
+	intent = kzalloc(sizeof(*intent), GFP_KERNEL);
+
+	if (!intent)
+		return NULL;
+
+	intent->data = kzalloc(size, GFP_KERNEL);
+	if (!intent->data)
+		return NULL;
+
+	spin_lock_irqsave(&channel->intent_lock, flags);
+	ret = idr_alloc_cyclic(&channel->liids, intent, 1, -1, GFP_ATOMIC);
+	if (ret < 0) {
+		spin_unlock_irqrestore(&channel->intent_lock, flags);
+		return NULL;
+	}
+	spin_unlock_irqrestore(&channel->intent_lock, flags);
+
+	intent->id = ret;
+	intent->size = size;
+	intent->reuse = reuseable;
+
+	return intent;
+}
+
+/**
+ * glink_core_rx_cmd_remote_rx_intent_req() - Receive a request for rx_intent
+ *					    from remote side
+ * if_ptr:      Pointer to the transport interface
+ * rcid:	Remote channel ID
+ * size:	size of the intent
+ *
+ * The function searches for the local channel to which the request for
+ * rx_intent has arrived and allocates and notifies the remote back
+ */
+static void qcom_glink_handle_intent_req(struct qcom_glink *glink,
+					 u32 cid, size_t size)
+{
+	struct glink_core_rx_intent *intent;
+	struct glink_channel *channel;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glink->idr_lock, flags);
+	channel = idr_find(&glink->rcids, cid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
+
+	if (!channel) {
+		pr_err("%s channel not found for cid %d\n", __func__, cid);
+		return;
+	}
+
+	intent = qcom_glink_alloc_intent(glink, channel, size, false);
+	if (intent)
+		qcom_glink_advertise_intent(glink, channel, intent);
+
+	qcom_glink_send_intent_req_ack(glink, channel, !!intent);
+}
+
 static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 {
 	struct glink_defer_cmd *dcmd;
@@ -585,6 +738,7 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 		case RPM_CMD_VERSION_ACK:
 		case RPM_CMD_CLOSE:
 		case RPM_CMD_CLOSE_ACK:
+		case RPM_CMD_RX_INTENT_REQ:
 			ret = qcom_glink_rx_defer(glink, 0);
 			break;
 		case RPM_CMD_OPEN_ACK:
@@ -1002,6 +1156,9 @@ static void qcom_glink_work(struct work_struct *work)
 		case RPM_CMD_CLOSE_ACK:
 			qcom_glink_rx_close_ack(glink, param1);
 			break;
+		case RPM_CMD_RX_INTENT_REQ:
+			qcom_glink_handle_intent_req(glink, param1, param2);
+			break;
 		default:
 			WARN(1, "Unknown defer object %d\n", cmd);
 			break;
@@ -1014,7 +1171,8 @@ static void qcom_glink_work(struct work_struct *work)
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 					   unsigned long features,
 					   struct qcom_glink_pipe *rx,
-					   struct qcom_glink_pipe *tx)
+					   struct qcom_glink_pipe *tx,
+					   bool intentless)
 {
 	int irq;
 	int ret;
@@ -1029,6 +1187,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 	glink->rx_pipe = rx;
 
 	glink->features = features;
+	glink->intentless = intentless;
 
 	mutex_init(&glink->tx_lock);
 	spin_lock_init(&glink->rx_lock);
diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
index f418787..d7538c3 100644
--- a/drivers/rpmsg/qcom_glink_native.h
+++ b/drivers/rpmsg/qcom_glink_native.h
@@ -37,7 +37,8 @@ struct qcom_glink_pipe {
 struct qcom_glink *qcom_glink_native_probe(struct device *dev,
 					   unsigned long features,
 					   struct qcom_glink_pipe *rx,
-					   struct qcom_glink_pipe *tx);
+					   struct qcom_glink_pipe *tx,
+					   bool intentless);
 void qcom_glink_native_remove(struct qcom_glink *glink);
 
 #endif
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 7d039cd..5a86e08 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -305,7 +305,8 @@ static int glink_rpm_probe(struct platform_device *pdev)
 	glink = qcom_glink_native_probe(&pdev->dev,
 					0,
 					&rx_pipe->native,
-					&tx_pipe->native);
+					&tx_pipe->native,
+					true);
 	if (IS_ERR(glink))
 		return PTR_ERR(glink);
 
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
index 496a5e3..e792895 100644
--- a/drivers/rpmsg/qcom_glink_smem.c
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -278,8 +278,9 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
 	*tx_pipe->head = 0;
 
 	glink = qcom_glink_native_probe(dev,
-					GLINK_FEATURE_TRACER_PKT,
-					&rx_pipe->native, &tx_pipe->native);
+					GLINK_FEATURE_INTENT_REUSE,
+					&rx_pipe->native, &tx_pipe->native,
+					false);
 	if (IS_ERR(glink)) {
 		ret = PTR_ERR(glink);
 		goto err_put_dev;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 11/18] rpmsg: glink: Use the local intents when receiving data
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

So previously on request from remote side, we allocated local
intent buffers and passed the ids to the remote. Now when
we receive data buffers from remote directed to that intent
id, copy the data to the corresponding preallocated intent
buffer.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 75 ++++++++++++++++++++++++++-------------
 1 file changed, 50 insertions(+), 25 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index cbc9f9e..d6aa589 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -160,7 +160,7 @@ struct glink_channel {
 	spinlock_t intent_lock;
 	struct idr liids;
 
-	void *buf;
+	struct glink_core_rx_intent *buf;
 	int buf_offset;
 	int buf_size;
 
@@ -607,6 +607,7 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 
 static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 {
+	struct glink_core_rx_intent *intent;
 	struct glink_channel *channel;
 	struct {
 		struct glink_msg msg;
@@ -616,6 +617,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 	unsigned int chunk_size;
 	unsigned int left_size;
 	unsigned int rcid;
+	unsigned int liid;
+	int ret = 0;
 	unsigned long flags;
 
 	if (avail < sizeof(hdr)) {
@@ -643,56 +646,78 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 		dev_dbg(glink->dev, "Data on non-existing channel\n");
 
 		/* Drop the message */
-		qcom_glink_rx_advance(glink,
-				      ALIGN(sizeof(hdr) + chunk_size, 8));
-		return 0;
+		goto advance_rx;
 	}
 
-	/* Might have an ongoing, fragmented, message to append */
-	if (!channel->buf) {
-		channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
-		if (!channel->buf)
-			return -ENOMEM;
+	if (glink->intentless) {
+		/* Might have an ongoing, fragmented, message to append */
+		if (!channel->buf) {
+			intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
+			if (!intent)
+				return -ENOMEM;
+
+			intent->data = kmalloc(chunk_size + left_size,
+					       GFP_ATOMIC);
+			if (!intent->data) {
+				kfree(intent);
+				return -ENOMEM;
+			}
+
+			intent->id = 0xbabababa;
+			intent->size = chunk_size + left_size;
+			intent->offset = 0;
+
+			channel->buf = intent;
+		} else {
+			intent = channel->buf;
+		}
+	} else {
+		liid = le32_to_cpu(hdr.msg.param2);
 
-		channel->buf_size = chunk_size + left_size;
-		channel->buf_offset = 0;
-	}
+		spin_lock_irqsave(&channel->intent_lock, flags);
+		intent = idr_find(&channel->liids, liid);
+		spin_unlock_irqrestore(&channel->intent_lock, flags);
 
-	qcom_glink_rx_advance(glink, sizeof(hdr));
+		if (!intent) {
+			dev_err(glink->dev,
+				"no intent found for channel %s intent %d",
+				channel->name, liid);
+			goto advance_rx;
+		}
+	}
 
-	if (channel->buf_size - channel->buf_offset < chunk_size) {
-		dev_err(glink->dev, "Insufficient space in input buffer\n");
+	if (intent->size - intent->offset < chunk_size) {
+		dev_err(glink->dev, "Insufficient space in intent\n");
 
 		/* The packet header lied, drop payload */
-		qcom_glink_rx_advance(glink, chunk_size);
-		return -ENOMEM;
+		goto advance_rx;
 	}
 
-	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
+	qcom_glink_rx_advance(glink, ALIGN(sizeof(hdr), 8));
+	qcom_glink_rx_peak(glink, intent->data + intent->offset,
 			   chunk_size);
-	channel->buf_offset += chunk_size;
+	intent->offset += chunk_size;
 
 	/* Handle message when no fragments remain to be received */
 	if (!left_size) {
 		spin_lock(&channel->recv_lock);
 		if (channel->ept.cb) {
 			channel->ept.cb(channel->ept.rpdev,
-					channel->buf,
-					channel->buf_offset,
+					intent->data,
+					intent->offset,
 					channel->ept.priv,
 					RPMSG_ADDR_ANY);
 		}
 		spin_unlock(&channel->recv_lock);
 
-		kfree(channel->buf);
+		intent->offset = 0;
 		channel->buf = NULL;
-		channel->buf_size = 0;
 	}
 
-	/* Each message starts at 8 byte aligned address */
+advance_rx:
 	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
 
-	return 0;
+	return ret;
 }
 
 static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 11/18] rpmsg: glink: Use the local intents when receiving data
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

So previously on request from remote side, we allocated local
intent buffers and passed the ids to the remote. Now when
we receive data buffers from remote directed to that intent
id, copy the data to the corresponding preallocated intent
buffer.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 75 ++++++++++++++++++++++++++-------------
 1 file changed, 50 insertions(+), 25 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index cbc9f9e..d6aa589 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -160,7 +160,7 @@ struct glink_channel {
 	spinlock_t intent_lock;
 	struct idr liids;
 
-	void *buf;
+	struct glink_core_rx_intent *buf;
 	int buf_offset;
 	int buf_size;
 
@@ -607,6 +607,7 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 
 static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 {
+	struct glink_core_rx_intent *intent;
 	struct glink_channel *channel;
 	struct {
 		struct glink_msg msg;
@@ -616,6 +617,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 	unsigned int chunk_size;
 	unsigned int left_size;
 	unsigned int rcid;
+	unsigned int liid;
+	int ret = 0;
 	unsigned long flags;
 
 	if (avail < sizeof(hdr)) {
@@ -643,56 +646,78 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 		dev_dbg(glink->dev, "Data on non-existing channel\n");
 
 		/* Drop the message */
-		qcom_glink_rx_advance(glink,
-				      ALIGN(sizeof(hdr) + chunk_size, 8));
-		return 0;
+		goto advance_rx;
 	}
 
-	/* Might have an ongoing, fragmented, message to append */
-	if (!channel->buf) {
-		channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
-		if (!channel->buf)
-			return -ENOMEM;
+	if (glink->intentless) {
+		/* Might have an ongoing, fragmented, message to append */
+		if (!channel->buf) {
+			intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
+			if (!intent)
+				return -ENOMEM;
+
+			intent->data = kmalloc(chunk_size + left_size,
+					       GFP_ATOMIC);
+			if (!intent->data) {
+				kfree(intent);
+				return -ENOMEM;
+			}
+
+			intent->id = 0xbabababa;
+			intent->size = chunk_size + left_size;
+			intent->offset = 0;
+
+			channel->buf = intent;
+		} else {
+			intent = channel->buf;
+		}
+	} else {
+		liid = le32_to_cpu(hdr.msg.param2);
 
-		channel->buf_size = chunk_size + left_size;
-		channel->buf_offset = 0;
-	}
+		spin_lock_irqsave(&channel->intent_lock, flags);
+		intent = idr_find(&channel->liids, liid);
+		spin_unlock_irqrestore(&channel->intent_lock, flags);
 
-	qcom_glink_rx_advance(glink, sizeof(hdr));
+		if (!intent) {
+			dev_err(glink->dev,
+				"no intent found for channel %s intent %d",
+				channel->name, liid);
+			goto advance_rx;
+		}
+	}
 
-	if (channel->buf_size - channel->buf_offset < chunk_size) {
-		dev_err(glink->dev, "Insufficient space in input buffer\n");
+	if (intent->size - intent->offset < chunk_size) {
+		dev_err(glink->dev, "Insufficient space in intent\n");
 
 		/* The packet header lied, drop payload */
-		qcom_glink_rx_advance(glink, chunk_size);
-		return -ENOMEM;
+		goto advance_rx;
 	}
 
-	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
+	qcom_glink_rx_advance(glink, ALIGN(sizeof(hdr), 8));
+	qcom_glink_rx_peak(glink, intent->data + intent->offset,
 			   chunk_size);
-	channel->buf_offset += chunk_size;
+	intent->offset += chunk_size;
 
 	/* Handle message when no fragments remain to be received */
 	if (!left_size) {
 		spin_lock(&channel->recv_lock);
 		if (channel->ept.cb) {
 			channel->ept.cb(channel->ept.rpdev,
-					channel->buf,
-					channel->buf_offset,
+					intent->data,
+					intent->offset,
 					channel->ept.priv,
 					RPMSG_ADDR_ANY);
 		}
 		spin_unlock(&channel->recv_lock);
 
-		kfree(channel->buf);
+		intent->offset = 0;
 		channel->buf = NULL;
-		channel->buf_size = 0;
 	}
 
-	/* Each message starts at 8 byte aligned address */
+advance_rx:
 	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
 
-	return 0;
+	return ret;
 }
 
 static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 12/18] rpmsg: glink: Make RX FIFO peak accessor to take an offset
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

From: Bjorn Andersson <bjorn.andersson@linaro.org>

To fully read the received rx data from FIFO both the
command and data has to be read. Currently we read
command, data separately and process them. By adding
an offset parameter to RX FIFO peak accessor, command
and data can be read together, simplifying things.
So introduce this.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_native.c | 15 +++++++--------
 drivers/rpmsg/qcom_glink_native.h |  2 +-
 drivers/rpmsg/qcom_glink_rpm.c    |  5 ++++-
 drivers/rpmsg/qcom_glink_smem.c   |  5 ++++-
 4 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index d6aa589..b2a583a 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -226,9 +226,9 @@ static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
 }
 
 static void qcom_glink_rx_peak(struct qcom_glink *glink,
-			       void *data, size_t count)
+			       void *data, unsigned int offset, size_t count)
 {
-	glink->rx_pipe->peak(glink->rx_pipe, data, count);
+	glink->rx_pipe->peak(glink->rx_pipe, data, offset, count);
 }
 
 static void qcom_glink_rx_advance(struct qcom_glink *glink, size_t count)
@@ -593,7 +593,7 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 
 	INIT_LIST_HEAD(&dcmd->node);
 
-	qcom_glink_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
+	qcom_glink_rx_peak(glink, &dcmd->msg, 0, sizeof(dcmd->msg) + extra);
 
 	spin_lock(&glink->rx_lock);
 	list_add_tail(&dcmd->node, &glink->rx_queue);
@@ -626,7 +626,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 		return -EAGAIN;
 	}
 
-	qcom_glink_rx_peak(glink, &hdr, sizeof(hdr));
+	qcom_glink_rx_peak(glink, &hdr, 0, sizeof(hdr));
 	chunk_size = le32_to_cpu(hdr.chunk_size);
 	left_size = le32_to_cpu(hdr.left_size);
 
@@ -693,9 +693,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 		goto advance_rx;
 	}
 
-	qcom_glink_rx_advance(glink, ALIGN(sizeof(hdr), 8));
 	qcom_glink_rx_peak(glink, intent->data + intent->offset,
-			   chunk_size);
+			   sizeof(hdr), chunk_size);
 	intent->offset += chunk_size;
 
 	/* Handle message when no fragments remain to be received */
@@ -715,7 +714,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 	}
 
 advance_rx:
-	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
+	qcom_glink_rx_advance(glink, ALIGN(sizeof(hdr) + chunk_size, 8));
 
 	return ret;
 }
@@ -752,7 +751,7 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 		if (avail < sizeof(msg))
 			break;
 
-		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
+		qcom_glink_rx_peak(glink, &msg, 0, sizeof(msg));
 
 		cmd = le16_to_cpu(msg.cmd);
 		param1 = le16_to_cpu(msg.param1);
diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
index d7538c3..0e1e420 100644
--- a/drivers/rpmsg/qcom_glink_native.h
+++ b/drivers/rpmsg/qcom_glink_native.h
@@ -24,7 +24,7 @@ struct qcom_glink_pipe {
 	size_t (*avail)(struct qcom_glink_pipe *glink_pipe);
 
 	void (*peak)(struct qcom_glink_pipe *glink_pipe, void *data,
-		     size_t count);
+		     unsigned int offset, size_t count);
 	void (*advance)(struct qcom_glink_pipe *glink_pipe, size_t count);
 
 	void (*write)(struct qcom_glink_pipe *glink_pipe,
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 5a86e08..69b25d1 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -77,13 +77,16 @@ static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
 }
 
 static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
-			      void *data, size_t count)
+			      void *data, unsigned int offset, size_t count)
 {
 	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int tail;
 	size_t len;
 
 	tail = readl(pipe->tail);
+	tail += offset;
+	if (tail >= pipe->native.length)
+		tail -= pipe->native.length;
 
 	len = min_t(size_t, count, pipe->native.length - tail);
 	if (len) {
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
index e792895..6d8f41f 100644
--- a/drivers/rpmsg/qcom_glink_smem.c
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -87,13 +87,16 @@ static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
 }
 
 static void glink_smem_rx_peak(struct qcom_glink_pipe *np,
-			       void *data, size_t count)
+			       void *data, unsigned int offset, size_t count)
 {
 	struct glink_smem_pipe *pipe = to_smem_pipe(np);
 	size_t len;
 	u32 tail;
 
 	tail = le32_to_cpu(*pipe->tail);
+	tail += offset;
+	if (tail >= pipe->native.length)
+		tail -= pipe->native.length;
 
 	len = min_t(size_t, count, pipe->native.length - tail);
 	if (len) {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 12/18] rpmsg: glink: Make RX FIFO peak accessor to take an offset
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Bjorn Andersson <bjorn.andersson@linaro.org>

To fully read the received rx data from FIFO both the
command and data has to be read. Currently we read
command, data separately and process them. By adding
an offset parameter to RX FIFO peak accessor, command
and data can be read together, simplifying things.
So introduce this.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
---
 drivers/rpmsg/qcom_glink_native.c | 15 +++++++--------
 drivers/rpmsg/qcom_glink_native.h |  2 +-
 drivers/rpmsg/qcom_glink_rpm.c    |  5 ++++-
 drivers/rpmsg/qcom_glink_smem.c   |  5 ++++-
 4 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index d6aa589..b2a583a 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -226,9 +226,9 @@ static size_t qcom_glink_rx_avail(struct qcom_glink *glink)
 }
 
 static void qcom_glink_rx_peak(struct qcom_glink *glink,
-			       void *data, size_t count)
+			       void *data, unsigned int offset, size_t count)
 {
-	glink->rx_pipe->peak(glink->rx_pipe, data, count);
+	glink->rx_pipe->peak(glink->rx_pipe, data, offset, count);
 }
 
 static void qcom_glink_rx_advance(struct qcom_glink *glink, size_t count)
@@ -593,7 +593,7 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
 
 	INIT_LIST_HEAD(&dcmd->node);
 
-	qcom_glink_rx_peak(glink, &dcmd->msg, sizeof(dcmd->msg) + extra);
+	qcom_glink_rx_peak(glink, &dcmd->msg, 0, sizeof(dcmd->msg) + extra);
 
 	spin_lock(&glink->rx_lock);
 	list_add_tail(&dcmd->node, &glink->rx_queue);
@@ -626,7 +626,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 		return -EAGAIN;
 	}
 
-	qcom_glink_rx_peak(glink, &hdr, sizeof(hdr));
+	qcom_glink_rx_peak(glink, &hdr, 0, sizeof(hdr));
 	chunk_size = le32_to_cpu(hdr.chunk_size);
 	left_size = le32_to_cpu(hdr.left_size);
 
@@ -693,9 +693,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 		goto advance_rx;
 	}
 
-	qcom_glink_rx_advance(glink, ALIGN(sizeof(hdr), 8));
 	qcom_glink_rx_peak(glink, intent->data + intent->offset,
-			   chunk_size);
+			   sizeof(hdr), chunk_size);
 	intent->offset += chunk_size;
 
 	/* Handle message when no fragments remain to be received */
@@ -715,7 +714,7 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 	}
 
 advance_rx:
-	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
+	qcom_glink_rx_advance(glink, ALIGN(sizeof(hdr) + chunk_size, 8));
 
 	return ret;
 }
@@ -752,7 +751,7 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 		if (avail < sizeof(msg))
 			break;
 
-		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
+		qcom_glink_rx_peak(glink, &msg, 0, sizeof(msg));
 
 		cmd = le16_to_cpu(msg.cmd);
 		param1 = le16_to_cpu(msg.param1);
diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
index d7538c3..0e1e420 100644
--- a/drivers/rpmsg/qcom_glink_native.h
+++ b/drivers/rpmsg/qcom_glink_native.h
@@ -24,7 +24,7 @@ struct qcom_glink_pipe {
 	size_t (*avail)(struct qcom_glink_pipe *glink_pipe);
 
 	void (*peak)(struct qcom_glink_pipe *glink_pipe, void *data,
-		     size_t count);
+		     unsigned int offset, size_t count);
 	void (*advance)(struct qcom_glink_pipe *glink_pipe, size_t count);
 
 	void (*write)(struct qcom_glink_pipe *glink_pipe,
diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
index 5a86e08..69b25d1 100644
--- a/drivers/rpmsg/qcom_glink_rpm.c
+++ b/drivers/rpmsg/qcom_glink_rpm.c
@@ -77,13 +77,16 @@ static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
 }
 
 static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
-			      void *data, size_t count)
+			      void *data, unsigned int offset, size_t count)
 {
 	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
 	unsigned int tail;
 	size_t len;
 
 	tail = readl(pipe->tail);
+	tail += offset;
+	if (tail >= pipe->native.length)
+		tail -= pipe->native.length;
 
 	len = min_t(size_t, count, pipe->native.length - tail);
 	if (len) {
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
index e792895..6d8f41f 100644
--- a/drivers/rpmsg/qcom_glink_smem.c
+++ b/drivers/rpmsg/qcom_glink_smem.c
@@ -87,13 +87,16 @@ static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
 }
 
 static void glink_smem_rx_peak(struct qcom_glink_pipe *np,
-			       void *data, size_t count)
+			       void *data, unsigned int offset, size_t count)
 {
 	struct glink_smem_pipe *pipe = to_smem_pipe(np);
 	size_t len;
 	u32 tail;
 
 	tail = le32_to_cpu(*pipe->tail);
+	tail += offset;
+	if (tail >= pipe->native.length)
+		tail -= pipe->native.length;
 
 	len = min_t(size_t, count, pipe->native.length - tail);
 	if (len) {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 13/18] rpmsg: glink: Add rx done command
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

Send RX data receive ack to remote and also inform
that local intent buffer is used and freed. This
informs the remote to request for next set of
intent buffers before doing a send operation.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 83 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index b2a583a..b8db74a 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -76,6 +76,8 @@ struct glink_core_rx_intent {
 	bool reuse;
 	bool in_use;
 	u32 offset;
+
+	struct list_head node;
 };
 
 /**
@@ -137,6 +139,8 @@ enum {
  * @rcid:	channel id, in remote space
  * @intent_lock: lock for protection of @liids
  * @liids:	idr of all local intents
+ * @intent_work: worker responsible for transmitting rx_done packets
+ * @done_intents: list of intents that needs to be announced rx_done
  * @buf:	receive buffer, for gathering fragments
  * @buf_offset:	write offset in @buf
  * @buf_size:	size of current @buf
@@ -159,6 +163,8 @@ struct glink_channel {
 
 	spinlock_t intent_lock;
 	struct idr liids;
+	struct work_struct intent_work;
+	struct list_head done_intents;
 
 	struct glink_core_rx_intent *buf;
 	int buf_offset;
@@ -178,15 +184,19 @@ struct glink_channel {
 #define RPM_CMD_CLOSE			3
 #define RPM_CMD_OPEN_ACK		4
 #define RPM_CMD_INTENT			5
+#define RPM_CMD_RX_DONE			6
 #define RPM_CMD_RX_INTENT_REQ		7
 #define RPM_CMD_RX_INTENT_REQ_ACK	8
 #define RPM_CMD_TX_DATA			9
 #define RPM_CMD_CLOSE_ACK		11
 #define RPM_CMD_TX_DATA_CONT		12
 #define RPM_CMD_READ_NOTIF		13
+#define RPM_CMD_RX_DONE_W_REUSE		14
 
 #define GLINK_FEATURE_INTENTLESS	BIT(1)
 
+static void qcom_glink_rx_done_work(struct work_struct *work);
+
 static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
 						      const char *name)
 {
@@ -198,12 +208,16 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
 
 	/* Setup glink internal glink_channel data */
 	spin_lock_init(&channel->recv_lock);
+
 	channel->glink = glink;
 	channel->name = kstrdup(name, GFP_KERNEL);
 
 	init_completion(&channel->open_req);
 	init_completion(&channel->open_ack);
 
+	INIT_LIST_HEAD(&channel->done_intents);
+	INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work);
+
 	idr_init(&channel->liids);
 	kref_init(&channel->refcount);
 
@@ -395,6 +409,70 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink,
 	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
 }
 
+static void qcom_glink_rx_done_work(struct work_struct *work)
+{
+	struct glink_channel *channel = container_of(work, struct glink_channel,
+						     intent_work);
+	struct qcom_glink *glink = channel->glink;
+	struct glink_core_rx_intent *intent, *tmp;
+	struct {
+		u16 id;
+		u16 lcid;
+		u32 liid;
+	} __packed cmd;
+
+	unsigned int cid = 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 ? RPM_CMD_RX_DONE_W_REUSE : RPM_CMD_RX_DONE;
+		cmd.lcid = cid;
+		cmd.liid = iid;
+
+		qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
+		if (!reuse) {
+			kfree(intent->data);
+			kfree(intent);
+		}
+		spin_lock_irqsave(&channel->intent_lock, flags);
+	}
+	spin_unlock_irqrestore(&channel->intent_lock, flags);
+}
+
+static void qcom_glink_rx_done(struct qcom_glink *glink,
+			       struct glink_channel *channel,
+			       struct glink_core_rx_intent *intent)
+{
+	/* 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(&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);
+}
+
 /**
  * qcom_glink_receive_version() - receive version/features from remote system
  *
@@ -711,6 +789,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 
 		intent->offset = 0;
 		channel->buf = NULL;
+
+		qcom_glink_rx_done(glink, channel, intent);
 	}
 
 advance_rx:
@@ -1100,6 +1180,9 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 	if (WARN(!channel, "close request on unknown channel\n"))
 		return;
 
+	/* cancel pending rx_done work */
+	cancel_work_sync(&channel->intent_work);
+
 	if (channel->rpdev) {
 		strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
 		chinfo.src = RPMSG_ADDR_ANY;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 13/18] rpmsg: glink: Add rx done command
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

Send RX data receive ack to remote and also inform
that local intent buffer is used and freed. This
informs the remote to request for next set of
intent buffers before doing a send operation.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 83 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index b2a583a..b8db74a 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -76,6 +76,8 @@ struct glink_core_rx_intent {
 	bool reuse;
 	bool in_use;
 	u32 offset;
+
+	struct list_head node;
 };
 
 /**
@@ -137,6 +139,8 @@ enum {
  * @rcid:	channel id, in remote space
  * @intent_lock: lock for protection of @liids
  * @liids:	idr of all local intents
+ * @intent_work: worker responsible for transmitting rx_done packets
+ * @done_intents: list of intents that needs to be announced rx_done
  * @buf:	receive buffer, for gathering fragments
  * @buf_offset:	write offset in @buf
  * @buf_size:	size of current @buf
@@ -159,6 +163,8 @@ struct glink_channel {
 
 	spinlock_t intent_lock;
 	struct idr liids;
+	struct work_struct intent_work;
+	struct list_head done_intents;
 
 	struct glink_core_rx_intent *buf;
 	int buf_offset;
@@ -178,15 +184,19 @@ struct glink_channel {
 #define RPM_CMD_CLOSE			3
 #define RPM_CMD_OPEN_ACK		4
 #define RPM_CMD_INTENT			5
+#define RPM_CMD_RX_DONE			6
 #define RPM_CMD_RX_INTENT_REQ		7
 #define RPM_CMD_RX_INTENT_REQ_ACK	8
 #define RPM_CMD_TX_DATA			9
 #define RPM_CMD_CLOSE_ACK		11
 #define RPM_CMD_TX_DATA_CONT		12
 #define RPM_CMD_READ_NOTIF		13
+#define RPM_CMD_RX_DONE_W_REUSE		14
 
 #define GLINK_FEATURE_INTENTLESS	BIT(1)
 
+static void qcom_glink_rx_done_work(struct work_struct *work);
+
 static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
 						      const char *name)
 {
@@ -198,12 +208,16 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
 
 	/* Setup glink internal glink_channel data */
 	spin_lock_init(&channel->recv_lock);
+
 	channel->glink = glink;
 	channel->name = kstrdup(name, GFP_KERNEL);
 
 	init_completion(&channel->open_req);
 	init_completion(&channel->open_ack);
 
+	INIT_LIST_HEAD(&channel->done_intents);
+	INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work);
+
 	idr_init(&channel->liids);
 	kref_init(&channel->refcount);
 
@@ -395,6 +409,70 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink,
 	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
 }
 
+static void qcom_glink_rx_done_work(struct work_struct *work)
+{
+	struct glink_channel *channel = container_of(work, struct glink_channel,
+						     intent_work);
+	struct qcom_glink *glink = channel->glink;
+	struct glink_core_rx_intent *intent, *tmp;
+	struct {
+		u16 id;
+		u16 lcid;
+		u32 liid;
+	} __packed cmd;
+
+	unsigned int cid = 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 ? RPM_CMD_RX_DONE_W_REUSE : RPM_CMD_RX_DONE;
+		cmd.lcid = cid;
+		cmd.liid = iid;
+
+		qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
+		if (!reuse) {
+			kfree(intent->data);
+			kfree(intent);
+		}
+		spin_lock_irqsave(&channel->intent_lock, flags);
+	}
+	spin_unlock_irqrestore(&channel->intent_lock, flags);
+}
+
+static void qcom_glink_rx_done(struct qcom_glink *glink,
+			       struct glink_channel *channel,
+			       struct glink_core_rx_intent *intent)
+{
+	/* 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(&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);
+}
+
 /**
  * qcom_glink_receive_version() - receive version/features from remote system
  *
@@ -711,6 +789,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 
 		intent->offset = 0;
 		channel->buf = NULL;
+
+		qcom_glink_rx_done(glink, channel, intent);
 	}
 
 advance_rx:
@@ -1100,6 +1180,9 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
 	if (WARN(!channel, "close request on unknown channel\n"))
 		return;
 
+	/* cancel pending rx_done work */
+	cancel_work_sync(&channel->intent_work);
+
 	if (channel->rpdev) {
 		strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
 		chinfo.src = RPMSG_ADDR_ANY;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 14/18] rpmsg: glink: Add announce_create ops and preallocate intents
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

Preallocate local intent buffers and pass the intent ids
to the remote. This way there are some default intents
available  for the remote to start sending data without
having to wait by sending intent requests. Do this by
adding the rpmsg announce_create ops, which gets called
right after the rpmsg device gets probed.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index b8db74a..c111046 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -995,6 +995,25 @@ static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
 	return ept;
 }
 
+static int qcom_glink_announce_create(struct rpmsg_device *rpdev)
+{
+	struct glink_channel *channel = to_glink_channel(rpdev->ept);
+	struct glink_core_rx_intent *intent;
+	struct qcom_glink *glink = channel->glink;
+	int num_intents = glink->intentless ? 0 : 5;
+
+	/* Channel is now open, advertise base set of intents */
+	while (num_intents--) {
+		intent = qcom_glink_alloc_intent(glink, channel, SZ_1K, true);
+		if (!intent)
+			break;
+
+		qcom_glink_advertise_intent(glink, channel, intent);
+	}
+
+	return 0;
+}
+
 static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
 {
 	struct glink_channel *channel = to_glink_channel(ept);
@@ -1070,6 +1089,7 @@ static struct device_node *qcom_glink_match_channel(struct device_node *node,
 
 static const struct rpmsg_device_ops glink_device_ops = {
 	.create_ept = qcom_glink_create_ept,
+	.announce_create = qcom_glink_announce_create,
 };
 
 static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 14/18] rpmsg: glink: Add announce_create ops and preallocate intents
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

Preallocate local intent buffers and pass the intent ids
to the remote. This way there are some default intents
available  for the remote to start sending data without
having to wait by sending intent requests. Do this by
adding the rpmsg announce_create ops, which gets called
right after the rpmsg device gets probed.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index b8db74a..c111046 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -995,6 +995,25 @@ static struct rpmsg_endpoint *qcom_glink_create_ept(struct rpmsg_device *rpdev,
 	return ept;
 }
 
+static int qcom_glink_announce_create(struct rpmsg_device *rpdev)
+{
+	struct glink_channel *channel = to_glink_channel(rpdev->ept);
+	struct glink_core_rx_intent *intent;
+	struct qcom_glink *glink = channel->glink;
+	int num_intents = glink->intentless ? 0 : 5;
+
+	/* Channel is now open, advertise base set of intents */
+	while (num_intents--) {
+		intent = qcom_glink_alloc_intent(glink, channel, SZ_1K, true);
+		if (!intent)
+			break;
+
+		qcom_glink_advertise_intent(glink, channel, intent);
+	}
+
+	return 0;
+}
+
 static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
 {
 	struct glink_channel *channel = to_glink_channel(ept);
@@ -1070,6 +1089,7 @@ static struct device_node *qcom_glink_match_channel(struct device_node *node,
 
 static const struct rpmsg_device_ops glink_device_ops = {
 	.create_ept = qcom_glink_create_ept,
+	.announce_create = qcom_glink_announce_create,
 };
 
 static const struct rpmsg_endpoint_ops glink_endpoint_ops = {
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 15/18] rpmsg: glink: Receive and store the remote intent buffers
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

Just like we allocating and sending intent ids to remote,
remote side allocates and sends us the intents as well.
So save the intent ids and use it later while sending
data targeting the appropriate intents based on the size.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 69 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index c111046..738303e 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -139,6 +139,7 @@ enum {
  * @rcid:	channel id, in remote space
  * @intent_lock: lock for protection of @liids
  * @liids:	idr of all local intents
+ * @riids:	idr of all remote intents
  * @intent_work: worker responsible for transmitting rx_done packets
  * @done_intents: list of intents that needs to be announced rx_done
  * @buf:	receive buffer, for gathering fragments
@@ -163,6 +164,7 @@ struct glink_channel {
 
 	spinlock_t intent_lock;
 	struct idr liids;
+	struct idr riids;
 	struct work_struct intent_work;
 	struct list_head done_intents;
 
@@ -219,6 +221,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
 	INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work);
 
 	idr_init(&channel->liids);
+	idr_init(&channel->riids);
 	kref_init(&channel->refcount);
 
 	return channel;
@@ -230,6 +233,7 @@ static void qcom_glink_channel_release(struct kref *ref)
 						     refcount);
 
 	idr_destroy(&channel->liids);
+	idr_destroy(&channel->riids);
 	kfree(channel->name);
 	kfree(channel);
 }
@@ -799,6 +803,68 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 	return ret;
 }
 
+static void qcom_glink_handle_intent(struct qcom_glink *glink,
+				     unsigned int cid,
+				     unsigned int count,
+				     size_t avail)
+{
+	struct glink_core_rx_intent *intent;
+	struct glink_channel *channel;
+	struct intent_pair {
+		__le32 size;
+		__le32 iid;
+	};
+
+	struct {
+		struct glink_msg msg;
+		struct intent_pair intents[];
+	} __packed *msg;
+
+	const size_t msglen = sizeof(*msg) + sizeof(struct intent_pair) * count;
+	int ret;
+	int i;
+	unsigned long flags;
+
+	if (avail < msglen) {
+		dev_dbg(glink->dev, "Not enough data in fifo\n");
+		return;
+	}
+
+	spin_lock_irqsave(&glink->idr_lock, flags);
+	channel = idr_find(&glink->rcids, cid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
+	if (!channel) {
+		dev_err(glink->dev, "intents for non-existing channel\n");
+		return;
+	}
+
+	msg = kmalloc(msglen, GFP_ATOMIC);
+	if (!msg)
+		return;
+
+	qcom_glink_rx_peak(glink, msg, 0, msglen);
+
+	for (i = 0; i < count; ++i) {
+		intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
+		if (!intent)
+			break;
+
+		intent->id = le32_to_cpu(msg->intents[i].iid);
+		intent->size = le32_to_cpu(msg->intents[i].size);
+
+		spin_lock_irqsave(&channel->intent_lock, flags);
+		ret = idr_alloc(&channel->riids, intent,
+				intent->id, intent->id + 1, GFP_ATOMIC);
+		spin_unlock_irqrestore(&channel->intent_lock, flags);
+
+		if (ret < 0)
+			dev_err(glink->dev, "failed to store remote intent\n");
+	}
+
+	kfree(msg);
+	qcom_glink_rx_advance(glink, ALIGN(msglen, 8));
+}
+
 static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
@@ -864,6 +930,9 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 
 			ret = 0;
 			break;
+		case RPM_CMD_INTENT:
+			qcom_glink_handle_intent(glink, param1, param2, avail);
+			break;
 		default:
 			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 15/18] rpmsg: glink: Receive and store the remote intent buffers
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

Just like we allocating and sending intent ids to remote,
remote side allocates and sends us the intents as well.
So save the intent ids and use it later while sending
data targeting the appropriate intents based on the size.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 69 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index c111046..738303e 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -139,6 +139,7 @@ enum {
  * @rcid:	channel id, in remote space
  * @intent_lock: lock for protection of @liids
  * @liids:	idr of all local intents
+ * @riids:	idr of all remote intents
  * @intent_work: worker responsible for transmitting rx_done packets
  * @done_intents: list of intents that needs to be announced rx_done
  * @buf:	receive buffer, for gathering fragments
@@ -163,6 +164,7 @@ struct glink_channel {
 
 	spinlock_t intent_lock;
 	struct idr liids;
+	struct idr riids;
 	struct work_struct intent_work;
 	struct list_head done_intents;
 
@@ -219,6 +221,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
 	INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work);
 
 	idr_init(&channel->liids);
+	idr_init(&channel->riids);
 	kref_init(&channel->refcount);
 
 	return channel;
@@ -230,6 +233,7 @@ static void qcom_glink_channel_release(struct kref *ref)
 						     refcount);
 
 	idr_destroy(&channel->liids);
+	idr_destroy(&channel->riids);
 	kfree(channel->name);
 	kfree(channel);
 }
@@ -799,6 +803,68 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
 	return ret;
 }
 
+static void qcom_glink_handle_intent(struct qcom_glink *glink,
+				     unsigned int cid,
+				     unsigned int count,
+				     size_t avail)
+{
+	struct glink_core_rx_intent *intent;
+	struct glink_channel *channel;
+	struct intent_pair {
+		__le32 size;
+		__le32 iid;
+	};
+
+	struct {
+		struct glink_msg msg;
+		struct intent_pair intents[];
+	} __packed *msg;
+
+	const size_t msglen = sizeof(*msg) + sizeof(struct intent_pair) * count;
+	int ret;
+	int i;
+	unsigned long flags;
+
+	if (avail < msglen) {
+		dev_dbg(glink->dev, "Not enough data in fifo\n");
+		return;
+	}
+
+	spin_lock_irqsave(&glink->idr_lock, flags);
+	channel = idr_find(&glink->rcids, cid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
+	if (!channel) {
+		dev_err(glink->dev, "intents for non-existing channel\n");
+		return;
+	}
+
+	msg = kmalloc(msglen, GFP_ATOMIC);
+	if (!msg)
+		return;
+
+	qcom_glink_rx_peak(glink, msg, 0, msglen);
+
+	for (i = 0; i < count; ++i) {
+		intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
+		if (!intent)
+			break;
+
+		intent->id = le32_to_cpu(msg->intents[i].iid);
+		intent->size = le32_to_cpu(msg->intents[i].size);
+
+		spin_lock_irqsave(&channel->intent_lock, flags);
+		ret = idr_alloc(&channel->riids, intent,
+				intent->id, intent->id + 1, GFP_ATOMIC);
+		spin_unlock_irqrestore(&channel->intent_lock, flags);
+
+		if (ret < 0)
+			dev_err(glink->dev, "failed to store remote intent\n");
+	}
+
+	kfree(msg);
+	qcom_glink_rx_advance(glink, ALIGN(msglen, 8));
+}
+
 static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
 {
 	struct glink_channel *channel;
@@ -864,6 +930,9 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 
 			ret = 0;
 			break;
+		case RPM_CMD_INTENT:
+			qcom_glink_handle_intent(glink, param1, param2, avail);
+			break;
 		default:
 			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 16/18] rpmsg: glink: Use the intents passed by remote
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

While sending data, use the remote intent id buffer
of suitable size that was passed by remote previously.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 738303e..7b43adc 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -1103,19 +1103,50 @@ static int __qcom_glink_send(struct glink_channel *channel,
 			     void *data, int len, bool wait)
 {
 	struct qcom_glink *glink = channel->glink;
+	struct glink_core_rx_intent *intent = NULL;
+	struct glink_core_rx_intent *tmp;
+	int iid = 0;
 	struct {
 		struct glink_msg msg;
 		__le32 chunk_size;
 		__le32 left_size;
 	} __packed req;
+	int ret;
+	unsigned long flags;
+
+	if (!glink->intentless) {
+		if (!intent) {
+			spin_lock_irqsave(&channel->intent_lock, flags);
+			idr_for_each_entry(&channel->riids, tmp, iid) {
+				if (tmp->size >= len && !tmp->in_use) {
+					tmp->in_use = true;
+					intent = tmp;
+					break;
+				}
+			}
+			spin_unlock_irqrestore(&channel->intent_lock, flags);
+
+			/* We found an available intent */
+			if (!intent)
+				return -EBUSY;
+		}
+
+		iid = intent->id;
+	}
 
 	req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
 	req.msg.param1 = cpu_to_le16(channel->lcid);
-	req.msg.param2 = cpu_to_le32(channel->rcid);
+	req.msg.param2 = cpu_to_le32(iid);
 	req.chunk_size = cpu_to_le32(len);
 	req.left_size = cpu_to_le32(0);
 
-	return qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
+	ret = qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
+
+	/* Mark intent available if we failed */
+	if (ret)
+		intent->in_use = false;
+
+	return ret;
 }
 
 static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len)
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 16/18] rpmsg: glink: Use the intents passed by remote
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

While sending data, use the remote intent id buffer
of suitable size that was passed by remote previously.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 738303e..7b43adc 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -1103,19 +1103,50 @@ static int __qcom_glink_send(struct glink_channel *channel,
 			     void *data, int len, bool wait)
 {
 	struct qcom_glink *glink = channel->glink;
+	struct glink_core_rx_intent *intent = NULL;
+	struct glink_core_rx_intent *tmp;
+	int iid = 0;
 	struct {
 		struct glink_msg msg;
 		__le32 chunk_size;
 		__le32 left_size;
 	} __packed req;
+	int ret;
+	unsigned long flags;
+
+	if (!glink->intentless) {
+		if (!intent) {
+			spin_lock_irqsave(&channel->intent_lock, flags);
+			idr_for_each_entry(&channel->riids, tmp, iid) {
+				if (tmp->size >= len && !tmp->in_use) {
+					tmp->in_use = true;
+					intent = tmp;
+					break;
+				}
+			}
+			spin_unlock_irqrestore(&channel->intent_lock, flags);
+
+			/* We found an available intent */
+			if (!intent)
+				return -EBUSY;
+		}
+
+		iid = intent->id;
+	}
 
 	req.msg.cmd = cpu_to_le16(RPM_CMD_TX_DATA);
 	req.msg.param1 = cpu_to_le16(channel->lcid);
-	req.msg.param2 = cpu_to_le32(channel->rcid);
+	req.msg.param2 = cpu_to_le32(iid);
 	req.chunk_size = cpu_to_le32(len);
 	req.left_size = cpu_to_le32(0);
 
-	return qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
+	ret = qcom_glink_tx(glink, &req, sizeof(req), data, len, wait);
+
+	/* Mark intent available if we failed */
+	if (ret)
+		intent->in_use = false;
+
+	return ret;
 }
 
 static int qcom_glink_send(struct rpmsg_endpoint *ept, void *data, int len)
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 17/18] rpmsg: glink: Request for intents when unavailable
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

While sending data, we search for suitable sized
intent to map and simply fail if a intent is not
found. Instead request for a intent of required
size and wait till one is alloted.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 73 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 2 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 7b43adc..cfacf4d 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -174,6 +174,10 @@ struct glink_channel {
 
 	struct completion open_ack;
 	struct completion open_req;
+
+	struct mutex intent_req_lock;
+	bool intent_req_result;
+	struct completion intent_req_comp;
 };
 
 #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept)
@@ -335,6 +339,24 @@ static void qcom_glink_send_open_ack(struct qcom_glink *glink,
 	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
 
+static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink,
+					     unsigned int cid, bool granted)
+{
+	struct glink_channel *channel;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glink->idr_lock, flags);
+	channel = idr_find(&glink->rcids, cid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
+	if (!channel) {
+		dev_err(glink->dev, "unable to find channel\n");
+		return;
+	}
+
+	channel->intent_req_result = granted;
+	complete(&channel->intent_req_comp);
+}
+
 /**
  * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
  * @glink:
@@ -933,6 +955,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 		case RPM_CMD_INTENT:
 			qcom_glink_handle_intent(glink, param1, param2, avail);
 			break;
+		case RPM_CMD_RX_INTENT_REQ_ACK:
+			qcom_glink_handle_intent_req_ack(glink, param1, param2);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			break;
 		default:
 			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
@@ -1099,6 +1125,42 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
 	qcom_glink_send_close_req(glink, channel);
 }
 
+static int qcom_glink_request_intent(struct qcom_glink *glink,
+				     struct glink_channel *channel,
+				     size_t size)
+{
+	struct {
+		u16 id;
+		u16 cid;
+		u32 size;
+	} __packed cmd;
+
+	int ret;
+
+	mutex_lock(&channel->intent_req_lock);
+
+	reinit_completion(&channel->intent_req_comp);
+
+	cmd.id = RPM_CMD_RX_INTENT_REQ;
+	cmd.cid = channel->lcid;
+	cmd.size = size;
+
+	ret = qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
+	if (ret)
+		return ret;
+
+	ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ);
+	if (!ret) {
+		dev_err(glink->dev, "intent request timed out\n");
+		ret = -ETIMEDOUT;
+	} else {
+		ret = channel->intent_req_result ? 0 : -ECANCELED;
+	}
+
+	mutex_unlock(&channel->intent_req_lock);
+	return ret;
+}
+
 static int __qcom_glink_send(struct glink_channel *channel,
 			     void *data, int len, bool wait)
 {
@@ -1115,7 +1177,7 @@ static int __qcom_glink_send(struct glink_channel *channel,
 	unsigned long flags;
 
 	if (!glink->intentless) {
-		if (!intent) {
+		while (!intent) {
 			spin_lock_irqsave(&channel->intent_lock, flags);
 			idr_for_each_entry(&channel->riids, tmp, iid) {
 				if (tmp->size >= len && !tmp->in_use) {
@@ -1127,8 +1189,15 @@ static int __qcom_glink_send(struct glink_channel *channel,
 			spin_unlock_irqrestore(&channel->intent_lock, flags);
 
 			/* We found an available intent */
-			if (!intent)
+			if (intent)
+				break;
+
+			if (!wait)
 				return -EBUSY;
+
+			ret = qcom_glink_request_intent(glink, channel, len);
+			if (ret < 0)
+				return ret;
 		}
 
 		iid = intent->id;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 17/18] rpmsg: glink: Request for intents when unavailable
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

While sending data, we search for suitable sized
intent to map and simply fail if a intent is not
found. Instead request for a intent of required
size and wait till one is alloted.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 73 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 2 deletions(-)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index 7b43adc..cfacf4d 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -174,6 +174,10 @@ struct glink_channel {
 
 	struct completion open_ack;
 	struct completion open_req;
+
+	struct mutex intent_req_lock;
+	bool intent_req_result;
+	struct completion intent_req_comp;
 };
 
 #define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept)
@@ -335,6 +339,24 @@ static void qcom_glink_send_open_ack(struct qcom_glink *glink,
 	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
 }
 
+static void qcom_glink_handle_intent_req_ack(struct qcom_glink *glink,
+					     unsigned int cid, bool granted)
+{
+	struct glink_channel *channel;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glink->idr_lock, flags);
+	channel = idr_find(&glink->rcids, cid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
+	if (!channel) {
+		dev_err(glink->dev, "unable to find channel\n");
+		return;
+	}
+
+	channel->intent_req_result = granted;
+	complete(&channel->intent_req_comp);
+}
+
 /**
  * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
  * @glink:
@@ -933,6 +955,10 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 		case RPM_CMD_INTENT:
 			qcom_glink_handle_intent(glink, param1, param2, avail);
 			break;
+		case RPM_CMD_RX_INTENT_REQ_ACK:
+			qcom_glink_handle_intent_req_ack(glink, param1, param2);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			break;
 		default:
 			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
 			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
@@ -1099,6 +1125,42 @@ static void qcom_glink_destroy_ept(struct rpmsg_endpoint *ept)
 	qcom_glink_send_close_req(glink, channel);
 }
 
+static int qcom_glink_request_intent(struct qcom_glink *glink,
+				     struct glink_channel *channel,
+				     size_t size)
+{
+	struct {
+		u16 id;
+		u16 cid;
+		u32 size;
+	} __packed cmd;
+
+	int ret;
+
+	mutex_lock(&channel->intent_req_lock);
+
+	reinit_completion(&channel->intent_req_comp);
+
+	cmd.id = RPM_CMD_RX_INTENT_REQ;
+	cmd.cid = channel->lcid;
+	cmd.size = size;
+
+	ret = qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
+	if (ret)
+		return ret;
+
+	ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ);
+	if (!ret) {
+		dev_err(glink->dev, "intent request timed out\n");
+		ret = -ETIMEDOUT;
+	} else {
+		ret = channel->intent_req_result ? 0 : -ECANCELED;
+	}
+
+	mutex_unlock(&channel->intent_req_lock);
+	return ret;
+}
+
 static int __qcom_glink_send(struct glink_channel *channel,
 			     void *data, int len, bool wait)
 {
@@ -1115,7 +1177,7 @@ static int __qcom_glink_send(struct glink_channel *channel,
 	unsigned long flags;
 
 	if (!glink->intentless) {
-		if (!intent) {
+		while (!intent) {
 			spin_lock_irqsave(&channel->intent_lock, flags);
 			idr_for_each_entry(&channel->riids, tmp, iid) {
 				if (tmp->size >= len && !tmp->in_use) {
@@ -1127,8 +1189,15 @@ static int __qcom_glink_send(struct glink_channel *channel,
 			spin_unlock_irqrestore(&channel->intent_lock, flags);
 
 			/* We found an available intent */
-			if (!intent)
+			if (intent)
+				break;
+
+			if (!wait)
 				return -EBUSY;
+
+			ret = qcom_glink_request_intent(glink, channel, len);
+			if (ret < 0)
+				return ret;
 		}
 
 		iid = intent->id;
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 18/18] rpmsg: glink: Handle remote rx done command
  2017-08-16 17:18 ` Sricharan R
@ 2017-08-16 17:19   ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: ohad, bjorn.andersson, linux-remoteproc, linux-kernel,
	linux-arm-msm, linux-arm-kernel
  Cc: sricharan

Once the remote side sends a rx done ack, check
for the intent reuse information from it and
suitably discard or reuse the remote passed
intent buffers.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 42 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index cfacf4d..870bff6 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -647,6 +647,40 @@ static int qcom_glink_advertise_intent(struct qcom_glink *glink,
 	return intent;
 }
 
+static void qcom_glink_handle_rx_done(struct qcom_glink *glink,
+				      u32 cid, uint32_t iid,
+				      bool reuse)
+{
+	struct glink_core_rx_intent *intent;
+	struct glink_channel *channel;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glink->idr_lock, flags);
+	channel = idr_find(&glink->rcids, cid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
+	if (!channel) {
+		dev_err(glink->dev, "invalid channel id received\n");
+		return;
+	}
+
+	spin_lock_irqsave(&channel->intent_lock, flags);
+	intent = idr_find(&channel->riids, iid);
+
+	if (!intent) {
+		spin_unlock_irqrestore(&channel->intent_lock, flags);
+		dev_err(glink->dev, "invalid intent id received\n");
+		return;
+	}
+
+	intent->in_use = false;
+
+	if (!reuse) {
+		idr_remove(&channel->riids, intent->id);
+		kfree(intent);
+	}
+	spin_unlock_irqrestore(&channel->intent_lock, flags);
+}
+
 /**
  * glink_core_rx_cmd_remote_rx_intent_req() - Receive a request for rx_intent
  *					    from remote side
@@ -955,6 +989,14 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 		case RPM_CMD_INTENT:
 			qcom_glink_handle_intent(glink, param1, param2, avail);
 			break;
+		case RPM_CMD_RX_DONE:
+			qcom_glink_handle_rx_done(glink, param1, param2, false);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			break;
+		case RPM_CMD_RX_DONE_W_REUSE:
+			qcom_glink_handle_rx_done(glink, param1, param2, true);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			break;
 		case RPM_CMD_RX_INTENT_REQ_ACK:
 			qcom_glink_handle_intent_req_ack(glink, param1, param2);
 			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH 18/18] rpmsg: glink: Handle remote rx done command
@ 2017-08-16 17:19   ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-16 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

Once the remote side sends a rx done ack, check
for the intent reuse information from it and
suitably discard or reuse the remote passed
intent buffers.

Signed-off-by: Sricharan R <sricharan@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 drivers/rpmsg/qcom_glink_native.c | 42 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
index cfacf4d..870bff6 100644
--- a/drivers/rpmsg/qcom_glink_native.c
+++ b/drivers/rpmsg/qcom_glink_native.c
@@ -647,6 +647,40 @@ static int qcom_glink_advertise_intent(struct qcom_glink *glink,
 	return intent;
 }
 
+static void qcom_glink_handle_rx_done(struct qcom_glink *glink,
+				      u32 cid, uint32_t iid,
+				      bool reuse)
+{
+	struct glink_core_rx_intent *intent;
+	struct glink_channel *channel;
+	unsigned long flags;
+
+	spin_lock_irqsave(&glink->idr_lock, flags);
+	channel = idr_find(&glink->rcids, cid);
+	spin_unlock_irqrestore(&glink->idr_lock, flags);
+	if (!channel) {
+		dev_err(glink->dev, "invalid channel id received\n");
+		return;
+	}
+
+	spin_lock_irqsave(&channel->intent_lock, flags);
+	intent = idr_find(&channel->riids, iid);
+
+	if (!intent) {
+		spin_unlock_irqrestore(&channel->intent_lock, flags);
+		dev_err(glink->dev, "invalid intent id received\n");
+		return;
+	}
+
+	intent->in_use = false;
+
+	if (!reuse) {
+		idr_remove(&channel->riids, intent->id);
+		kfree(intent);
+	}
+	spin_unlock_irqrestore(&channel->intent_lock, flags);
+}
+
 /**
  * glink_core_rx_cmd_remote_rx_intent_req() - Receive a request for rx_intent
  *					    from remote side
@@ -955,6 +989,14 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
 		case RPM_CMD_INTENT:
 			qcom_glink_handle_intent(glink, param1, param2, avail);
 			break;
+		case RPM_CMD_RX_DONE:
+			qcom_glink_handle_rx_done(glink, param1, param2, false);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			break;
+		case RPM_CMD_RX_DONE_W_REUSE:
+			qcom_glink_handle_rx_done(glink, param1, param2, true);
+			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
+			break;
 		case RPM_CMD_RX_INTENT_REQ_ACK:
 			qcom_glink_handle_intent_req_ack(glink, param1, param2);
 			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [PATCH 04/18] rpmsg: glink: Move the common glink protocol implementation to glink_native.c
  2017-08-16 17:18   ` Sricharan R
@ 2017-08-22  5:58     ` Arun Kumar Neelakantam
  -1 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22  5:58 UTC (permalink / raw)
  To: Sricharan R, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel



On 8/16/2017 10:48 PM, Sricharan R wrote:
> +
> +struct glink_msg {
> +	__le16 cmd;
> +	__le16 param1;
> +	__le32 param2;
> +	u8 data[];
> +} __packed;

why we are using extra u8 data[] member here ?

> +
> +/**
> + * struct glink_defer_cmd - deferred incoming control message
> + * @node:	list node
> + * @msg:	message header
> + * data:	payload of the message
> + *
> + * Copy of a received control message, to be added to @rx_queue and processed
> + * by @rx_work of @glink_rpm.
> + */
> +struct glink_defer_cmd {
> +	struct list_head node;
> +
> +	struct glink_msg msg;
> +	u8 data[];
> +};
> +
> +/**
> + * struct glink_rpm - driver context, relates to one remote subsystem

glink_rpm to qcom_glink

> +static int qcom_glink_tx(struct qcom_glink *glink,
> +			 const void *hdr, size_t hlen,
> +			 const void *data, size_t dlen, bool wait)
> +{
> +	unsigned int tlen = hlen + dlen;
> +	int ret;
> +
> +	/* Reject packets that are too big */
> +	if (tlen >= glink->tx_pipe->length)
> +		return -EINVAL;

we need to add support for split packets, in some cases packets may be 
greater than 16K.
> +
> +	if (WARN(tlen % 8, "Unaligned TX request"))
> +		return -EINVAL;
> +
> +	ret = mutex_lock_interruptible(&glink->tx_lock);
> +	if (ret)
> +		return ret;
> +
> +	while (qcom_glink_tx_avail(glink) < tlen) {
> +		if (!wait) {
> +			ret = -ENOMEM;

This condition is either reader is slow or not reading data, should we 
return -EAGAIN here instead of -ENOMEM?
> +			goto out;
> +		}
> +
> +		msleep(10);
> +	}
> +
> +	qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
> +
> +	mbox_send_message(glink->mbox_chan, NULL);
> +	mbox_client_txdone(glink->mbox_chan, 0);
> +
> +out:
> +	mutex_unlock(&glink->tx_lock);
> +
> +	return ret;
> +}
> +


> +/**
> + * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
> + * @glink:
> + * @channel:

Missed information for @ glink and @channel
> + *
> + * Allocates a local channel id and sends a RPM_CMD_OPEN message to the remote.
> + * Will return with refcount held, regardless of outcome.
> + *
> + * Returns 0 on success, negative errno otherwise.
> + */
> +static int qcom_glink_send_open_req(struct qcom_glink *glink,
> +				    struct glink_channel *channel)


> +static irqreturn_t qcom_glink_native_intr(int irq, void *data)
> +{
> +	struct qcom_glink *glink = data;
> +	struct glink_msg msg;
> +	unsigned int param1;
> +	unsigned int param2;
> +	unsigned int avail;
> +	unsigned int cmd;
> +	int ret;
> +
> +	for (;;) {
> +		avail = qcom_glink_rx_avail(glink);
> +		if (avail < sizeof(msg))
> +			break;
> +
> +		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
> +
> +		cmd = le16_to_cpu(msg.cmd);
> +		param1 = le16_to_cpu(msg.param1);
> +		param2 = le32_to_cpu(msg.param2);
> +
> +		switch (cmd) {
> +		case RPM_CMD_VERSION:
> +		case RPM_CMD_VERSION_ACK:
> +		case RPM_CMD_CLOSE:
> +		case RPM_CMD_CLOSE_ACK:
> +			ret = qcom_glink_rx_defer(glink, 0);
> +			break;
> +		case RPM_CMD_OPEN_ACK:
> +			ret = qcom_glink_rx_open_ack(glink, param1);
> +			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
> +			break;
> +		case RPM_CMD_OPEN:
> +			ret = qcom_glink_rx_defer(glink, param2);
> +			break;
> +		case RPM_CMD_TX_DATA:
> +		case RPM_CMD_TX_DATA_CONT:
> +			ret = qcom_glink_rx_data(glink, avail);
> +			break;
> +		case RPM_CMD_READ_NOTIF:
> +			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
> +
> +			mbox_send_message(glink->mbox_chan, NULL);
> +			mbox_client_txdone(glink->mbox_chan, 0);
> +
> +			ret = 0;
> +			break;
> +		default:
> +			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);

please add more information in error log to find the remote peripheral 
also other wise after adding SMEM transport it will be difficult to find 
for which peripheral the error came.
> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		if (ret)
> +			break;
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +

> +struct qcom_glink *qcom_glink_native_probe(struct device *dev,
> +					   struct qcom_glink_pipe *rx,
> +					   struct qcom_glink_pipe *tx)
> +{
> +	int irq;
> +	int ret;
> +	struct qcom_glink *glink;
> +
> +	glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
> +	if (!glink)
> +		return ERR_PTR(-ENOMEM);
> +
> +	glink->dev = dev;
> +	glink->tx_pipe = tx;
> +	glink->rx_pipe = rx;
> +
> +	mutex_init(&glink->tx_lock);
> +	spin_lock_init(&glink->rx_lock);
> +	INIT_LIST_HEAD(&glink->rx_queue);
> +	INIT_WORK(&glink->rx_work, qcom_glink_work);
> +
> +	mutex_init(&glink->idr_lock);
> +	idr_init(&glink->lcids);
> +	idr_init(&glink->rcids);
> +
> +	glink->mbox_client.dev = dev;
> +	glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
> +	if (IS_ERR(glink->mbox_chan)) {
> +		if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to acquire IPC channel\n");
> +		return ERR_CAST(glink->mbox_chan);
> +	}
> +
> +	irq = of_irq_get(dev->of_node, 0);
> +	ret = devm_request_irq(dev, irq,
> +			       qcom_glink_native_intr,
> +			       IRQF_NO_SUSPEND | IRQF_SHARED,
> +			       "glink-native", glink);
> +	if (ret) {
> +		dev_err(dev, "failed to request IRQ\n");
> +		return ERR_PTR(ret);
> +	}

These IRQs are wake-up-capable, please use enable_irq_wale() also
> +
> +	ret = qcom_glink_send_version(glink);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return glink;
> +}
> +

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 04/18] rpmsg: glink: Move the common glink protocol implementation to glink_native.c
@ 2017-08-22  5:58     ` Arun Kumar Neelakantam
  0 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22  5:58 UTC (permalink / raw)
  To: linux-arm-kernel



On 8/16/2017 10:48 PM, Sricharan R wrote:
> +
> +struct glink_msg {
> +	__le16 cmd;
> +	__le16 param1;
> +	__le32 param2;
> +	u8 data[];
> +} __packed;

why we are using extra u8 data[] member here ?

> +
> +/**
> + * struct glink_defer_cmd - deferred incoming control message
> + * @node:	list node
> + * @msg:	message header
> + * data:	payload of the message
> + *
> + * Copy of a received control message, to be added to @rx_queue and processed
> + * by @rx_work of @glink_rpm.
> + */
> +struct glink_defer_cmd {
> +	struct list_head node;
> +
> +	struct glink_msg msg;
> +	u8 data[];
> +};
> +
> +/**
> + * struct glink_rpm - driver context, relates to one remote subsystem

glink_rpm to qcom_glink

> +static int qcom_glink_tx(struct qcom_glink *glink,
> +			 const void *hdr, size_t hlen,
> +			 const void *data, size_t dlen, bool wait)
> +{
> +	unsigned int tlen = hlen + dlen;
> +	int ret;
> +
> +	/* Reject packets that are too big */
> +	if (tlen >= glink->tx_pipe->length)
> +		return -EINVAL;

we need to add support for split packets, in some cases packets may be 
greater than 16K.
> +
> +	if (WARN(tlen % 8, "Unaligned TX request"))
> +		return -EINVAL;
> +
> +	ret = mutex_lock_interruptible(&glink->tx_lock);
> +	if (ret)
> +		return ret;
> +
> +	while (qcom_glink_tx_avail(glink) < tlen) {
> +		if (!wait) {
> +			ret = -ENOMEM;

This condition is either reader is slow or not reading data, should we 
return -EAGAIN here instead of -ENOMEM?
> +			goto out;
> +		}
> +
> +		msleep(10);
> +	}
> +
> +	qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
> +
> +	mbox_send_message(glink->mbox_chan, NULL);
> +	mbox_client_txdone(glink->mbox_chan, 0);
> +
> +out:
> +	mutex_unlock(&glink->tx_lock);
> +
> +	return ret;
> +}
> +


> +/**
> + * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
> + * @glink:
> + * @channel:

Missed information for @ glink and @channel
> + *
> + * Allocates a local channel id and sends a RPM_CMD_OPEN message to the remote.
> + * Will return with refcount held, regardless of outcome.
> + *
> + * Returns 0 on success, negative errno otherwise.
> + */
> +static int qcom_glink_send_open_req(struct qcom_glink *glink,
> +				    struct glink_channel *channel)


> +static irqreturn_t qcom_glink_native_intr(int irq, void *data)
> +{
> +	struct qcom_glink *glink = data;
> +	struct glink_msg msg;
> +	unsigned int param1;
> +	unsigned int param2;
> +	unsigned int avail;
> +	unsigned int cmd;
> +	int ret;
> +
> +	for (;;) {
> +		avail = qcom_glink_rx_avail(glink);
> +		if (avail < sizeof(msg))
> +			break;
> +
> +		qcom_glink_rx_peak(glink, &msg, sizeof(msg));
> +
> +		cmd = le16_to_cpu(msg.cmd);
> +		param1 = le16_to_cpu(msg.param1);
> +		param2 = le32_to_cpu(msg.param2);
> +
> +		switch (cmd) {
> +		case RPM_CMD_VERSION:
> +		case RPM_CMD_VERSION_ACK:
> +		case RPM_CMD_CLOSE:
> +		case RPM_CMD_CLOSE_ACK:
> +			ret = qcom_glink_rx_defer(glink, 0);
> +			break;
> +		case RPM_CMD_OPEN_ACK:
> +			ret = qcom_glink_rx_open_ack(glink, param1);
> +			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
> +			break;
> +		case RPM_CMD_OPEN:
> +			ret = qcom_glink_rx_defer(glink, param2);
> +			break;
> +		case RPM_CMD_TX_DATA:
> +		case RPM_CMD_TX_DATA_CONT:
> +			ret = qcom_glink_rx_data(glink, avail);
> +			break;
> +		case RPM_CMD_READ_NOTIF:
> +			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
> +
> +			mbox_send_message(glink->mbox_chan, NULL);
> +			mbox_client_txdone(glink->mbox_chan, 0);
> +
> +			ret = 0;
> +			break;
> +		default:
> +			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);

please add more information in error log to find the remote peripheral 
also other wise after adding SMEM transport it will be difficult to find 
for which peripheral the error came.
> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		if (ret)
> +			break;
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +

> +struct qcom_glink *qcom_glink_native_probe(struct device *dev,
> +					   struct qcom_glink_pipe *rx,
> +					   struct qcom_glink_pipe *tx)
> +{
> +	int irq;
> +	int ret;
> +	struct qcom_glink *glink;
> +
> +	glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
> +	if (!glink)
> +		return ERR_PTR(-ENOMEM);
> +
> +	glink->dev = dev;
> +	glink->tx_pipe = tx;
> +	glink->rx_pipe = rx;
> +
> +	mutex_init(&glink->tx_lock);
> +	spin_lock_init(&glink->rx_lock);
> +	INIT_LIST_HEAD(&glink->rx_queue);
> +	INIT_WORK(&glink->rx_work, qcom_glink_work);
> +
> +	mutex_init(&glink->idr_lock);
> +	idr_init(&glink->lcids);
> +	idr_init(&glink->rcids);
> +
> +	glink->mbox_client.dev = dev;
> +	glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
> +	if (IS_ERR(glink->mbox_chan)) {
> +		if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
> +			dev_err(dev, "failed to acquire IPC channel\n");
> +		return ERR_CAST(glink->mbox_chan);
> +	}
> +
> +	irq = of_irq_get(dev->of_node, 0);
> +	ret = devm_request_irq(dev, irq,
> +			       qcom_glink_native_intr,
> +			       IRQF_NO_SUSPEND | IRQF_SHARED,
> +			       "glink-native", glink);
> +	if (ret) {
> +		dev_err(dev, "failed to request IRQ\n");
> +		return ERR_PTR(ret);
> +	}

These IRQs are wake-up-capable, please use enable_irq_wale() also
> +
> +	ret = qcom_glink_send_version(glink);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return glink;
> +}
> +

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 10/18] rpmsg: glink: Add support for TX intents
  2017-08-16 17:19   ` Sricharan R
@ 2017-08-22  9:12     ` Arun Kumar Neelakantam
  -1 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22  9:12 UTC (permalink / raw)
  To: Sricharan R, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel



On 8/16/2017 10:49 PM, Sricharan R wrote:
> Intents are nothing but pre-allocated buffers of
> appropriate size that are allocated on the local
> side and communicated to the remote side and the
> remote stores the list of intent ids that it is
> informed.
>
> Later when remote side is intenting to send data,
> it picks up a right intent (based on the size) and
> sends the data buffer and the intent id. Local side
> receives the data and copies it to the local intent
> buffer.
>
> The whole idea is to avoid stalls on the transport
> for allocating memory, used for copy based transports.
>
> When the remote request to allocate buffers using
> CMD_RX_INTENT_REQ, we allocate buffers of requested
> size, store the buffer id locally and also communicate
> the intent id to the remote.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>   drivers/rpmsg/qcom_glink_native.c | 161 +++++++++++++++++++++++++++++++++++++-
>   drivers/rpmsg/qcom_glink_native.h |   3 +-
>   drivers/rpmsg/qcom_glink_rpm.c    |   3 +-
>   drivers/rpmsg/qcom_glink_smem.c   |   5 +-
>   4 files changed, 167 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
> index acf5558..cbc9f9e 100644
> --- a/drivers/rpmsg/qcom_glink_native.c
> +++ b/drivers/rpmsg/qcom_glink_native.c
> @@ -60,6 +60,25 @@ struct glink_defer_cmd {
>   };
>   
>   /**
> + * RX intent
> + *
> + * data: pointer to the data (may be NULL for zero-copy)
> + * id: remote or local intent ID
> + * size: size of the original intent (do not modify)
> + * reuse: To mark if the intent can be reused after first use
> + * in_use: To mark if intent is already in use for the channel
> + * offset: next write offset (initially 0)
> + */
> +struct glink_core_rx_intent {
> +	void *data;
> +	u32 id;
> +	size_t size;
> +	bool reuse;
> +	bool in_use;
> +	u32 offset;
> +};
> +
> +/**
>    * struct glink_rpm - driver context, relates to one remote subsystem
>    * @dev:	reference to the associated struct device
>    * @doorbell:	"rpm_hlos" ipc doorbell
> @@ -116,6 +135,8 @@ enum {
>    * @name:	unique channel name/identifier
>    * @lcid:	channel id, in local space
>    * @rcid:	channel id, in remote space
> + * @intent_lock: lock for protection of @liids
> + * @liids:	idr of all local intents
>    * @buf:	receive buffer, for gathering fragments
>    * @buf_offset:	write offset in @buf
>    * @buf_size:	size of current @buf
> @@ -136,6 +157,9 @@ struct glink_channel {
>   	unsigned int lcid;
>   	unsigned int rcid;
>   
> +	spinlock_t intent_lock;
> +	struct idr liids;
> +
>   	void *buf;
>   	int buf_offset;
>   	int buf_size;
> @@ -153,6 +177,9 @@ struct glink_channel {
>   #define RPM_CMD_OPEN			2
>   #define RPM_CMD_CLOSE			3
>   #define RPM_CMD_OPEN_ACK		4
> +#define RPM_CMD_INTENT			5
> +#define RPM_CMD_RX_INTENT_REQ		7
> +#define RPM_CMD_RX_INTENT_REQ_ACK	8
>   #define RPM_CMD_TX_DATA			9
>   #define RPM_CMD_CLOSE_ACK		11
>   #define RPM_CMD_TX_DATA_CONT		12
> @@ -177,6 +204,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
>   	init_completion(&channel->open_req);
>   	init_completion(&channel->open_ack);
>   
> +	idr_init(&channel->liids);

spinlock intent_lock initialization is missed ?
>   	kref_init(&channel->refcount);
>   
>   	return channel;
> @@ -187,6 +215,7 @@ static void qcom_glink_channel_release(struct kref *ref)
>   	struct glink_channel *channel = container_of(ref, struct glink_channel,
>   						     refcount);
>   
> +	idr_destroy(&channel->liids);

idr_destroy shouldn`t be covered by intent_lock ?

>   	kfree(channel->name);
>   	kfree(channel);
>   }
> @@ -423,6 +452,130 @@ static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
>   	}
>   }
>   
> +/**
> + * qcom_glink_send_intent_req_ack() - convert an rx intent request ack cmd to
> +				      wire format and transmit
> + * @glink:	The transport to transmit on.
> + * @channel:	The glink channel
> + * @granted:	The request response to encode.
> + *
> + * Return: 0 on success or standard Linux error code.
> + */
> +static int qcom_glink_send_intent_req_ack(struct qcom_glink *glink,
> +					  struct glink_channel *channel,
> +					  bool granted)
> +{
> +	struct glink_msg msg;
> +
> +	msg.cmd = cpu_to_le16(RPM_CMD_RX_INTENT_REQ_ACK);
> +	msg.param1 = cpu_to_le16(channel->lcid);
> +	msg.param2 = cpu_to_le32(granted);
> +
> +	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
> +
> +	return 0;
> +}
> +
> +/**
> + * tx_cmd_local_rx_intent() - convert an rx intent cmd to wire format and
> + *			   transmit

copy-paste mistake
> + * @glink:	The transport to transmit on.
> + * @channel:	The local channel
> + * @size:	The intent to pass on to remote.
> + *
> + * Return: 0 on success or standard Linux error code.
> + */
> +static int qcom_glink_advertise_intent(struct qcom_glink *glink,
> +				       struct glink_channel *channel,
> +				       struct glink_core_rx_intent *intent)
> +{
> +	struct command {
> +		u16 id;
> +		u16 lcid;
> +		u32 count;
> +		u32 size;
> +		u32 liid;
> +	} __packed;
> +	struct command cmd;
> +
> +	cmd.id = cpu_to_le16(RPM_CMD_INTENT);
> +	cmd.lcid = cpu_to_le16(channel->lcid);
> +	cmd.count = cpu_to_le32(1);
> +	cmd.size = cpu_to_le32(intent->size);
> +	cmd.liid = cpu_to_le32(intent->id);
> +
> +	qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
> +
> +	return 0;
> +}
> +
> +static struct glink_core_rx_intent *
> +qcom_glink_alloc_intent(struct qcom_glink *glink,
> +			struct glink_channel *channel,
> +			size_t size,
> +			bool reuseable)
> +{
> +	struct glink_core_rx_intent *intent;
> +	int ret;
> +	unsigned long flags;
> +
> +	intent = kzalloc(sizeof(*intent), GFP_KERNEL);
> +
> +	if (!intent)
> +		return NULL;
> +
> +	intent->data = kzalloc(size, GFP_KERNEL);
> +	if (!intent->data)
> +		return NULL;
> +
> +	spin_lock_irqsave(&channel->intent_lock, flags);
> +	ret = idr_alloc_cyclic(&channel->liids, intent, 1, -1, GFP_ATOMIC);
> +	if (ret < 0) {
> +		spin_unlock_irqrestore(&channel->intent_lock, flags);
> +		return NULL;
> +	}
> +	spin_unlock_irqrestore(&channel->intent_lock, flags);
> +
> +	intent->id = ret;
> +	intent->size = size;
> +	intent->reuse = reuseable;
> +
> +	return intent;
> +}
> +
> +/**
> + * glink_core_rx_cmd_remote_rx_intent_req() - Receive a request for rx_intent
> + *					    from remote side

copy-paste mistake
> + * if_ptr:      Pointer to the transport interface
> + * rcid:	Remote channel ID
> + * size:	size of the intent
> + *
> + * The function searches for the local channel to which the request for
> + * rx_intent has arrived and allocates and notifies the remote back
> + */
> +static void qcom_glink_handle_intent_req(struct qcom_glink *glink,
> +					 u32 cid, size_t size)
> +{
> +	struct glink_core_rx_intent *intent;
> +	struct glink_channel *channel;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&glink->idr_lock, flags);
> +	channel = idr_find(&glink->rcids, cid);
> +	spin_unlock_irqrestore(&glink->idr_lock, flags);
> +
> +	if (!channel) {
> +		pr_err("%s channel not found for cid %d\n", __func__, cid);
> +		return;
> +	}
> +
> +	intent = qcom_glink_alloc_intent(glink, channel, size, false);
> +	if (intent)
> +		qcom_glink_advertise_intent(glink, channel, intent);
> +
> +	qcom_glink_send_intent_req_ack(glink, channel, !!intent);
> +}
> +
>   static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
>   {
>   	struct glink_defer_cmd *dcmd;
> @@ -585,6 +738,7 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
>   		case RPM_CMD_VERSION_ACK:
>   		case RPM_CMD_CLOSE:
>   		case RPM_CMD_CLOSE_ACK:
> +		case RPM_CMD_RX_INTENT_REQ:
>   			ret = qcom_glink_rx_defer(glink, 0);
>   			break;
>   		case RPM_CMD_OPEN_ACK:
> @@ -1002,6 +1156,9 @@ static void qcom_glink_work(struct work_struct *work)
>   		case RPM_CMD_CLOSE_ACK:
>   			qcom_glink_rx_close_ack(glink, param1);
>   			break;
> +		case RPM_CMD_RX_INTENT_REQ:
> +			qcom_glink_handle_intent_req(glink, param1, param2);
> +			break;
>   		default:
>   			WARN(1, "Unknown defer object %d\n", cmd);
>   			break;
> @@ -1014,7 +1171,8 @@ static void qcom_glink_work(struct work_struct *work)
>   struct qcom_glink *qcom_glink_native_probe(struct device *dev,
>   					   unsigned long features,
>   					   struct qcom_glink_pipe *rx,
> -					   struct qcom_glink_pipe *tx)
> +					   struct qcom_glink_pipe *tx,
> +					   bool intentless)
>   {
>   	int irq;
>   	int ret;
> @@ -1029,6 +1187,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
>   	glink->rx_pipe = rx;
>   
>   	glink->features = features;
> +	glink->intentless = intentless;
>   
>   	mutex_init(&glink->tx_lock);
>   	spin_lock_init(&glink->rx_lock);
> diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
> index f418787..d7538c3 100644
> --- a/drivers/rpmsg/qcom_glink_native.h
> +++ b/drivers/rpmsg/qcom_glink_native.h
> @@ -37,7 +37,8 @@ struct qcom_glink_pipe {
>   struct qcom_glink *qcom_glink_native_probe(struct device *dev,
>   					   unsigned long features,
>   					   struct qcom_glink_pipe *rx,
> -					   struct qcom_glink_pipe *tx);
> +					   struct qcom_glink_pipe *tx,
> +					   bool intentless);
>   void qcom_glink_native_remove(struct qcom_glink *glink);
>   
>   #endif
> diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
> index 7d039cd..5a86e08 100644
> --- a/drivers/rpmsg/qcom_glink_rpm.c
> +++ b/drivers/rpmsg/qcom_glink_rpm.c
> @@ -305,7 +305,8 @@ static int glink_rpm_probe(struct platform_device *pdev)
>   	glink = qcom_glink_native_probe(&pdev->dev,
>   					0,
>   					&rx_pipe->native,
> -					&tx_pipe->native);
> +					&tx_pipe->native,
> +					true);
>   	if (IS_ERR(glink))
>   		return PTR_ERR(glink);
>   
> diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
> index 496a5e3..e792895 100644
> --- a/drivers/rpmsg/qcom_glink_smem.c
> +++ b/drivers/rpmsg/qcom_glink_smem.c
> @@ -278,8 +278,9 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
>   	*tx_pipe->head = 0;
>   
>   	glink = qcom_glink_native_probe(dev,
> -					GLINK_FEATURE_TRACER_PKT,
> -					&rx_pipe->native, &tx_pipe->native);
> +					GLINK_FEATURE_INTENT_REUSE,
> +					&rx_pipe->native, &tx_pipe->native,
> +					false);
>   	if (IS_ERR(glink)) {
>   		ret = PTR_ERR(glink);
>   		goto err_put_dev;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 10/18] rpmsg: glink: Add support for TX intents
@ 2017-08-22  9:12     ` Arun Kumar Neelakantam
  0 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22  9:12 UTC (permalink / raw)
  To: linux-arm-kernel



On 8/16/2017 10:49 PM, Sricharan R wrote:
> Intents are nothing but pre-allocated buffers of
> appropriate size that are allocated on the local
> side and communicated to the remote side and the
> remote stores the list of intent ids that it is
> informed.
>
> Later when remote side is intenting to send data,
> it picks up a right intent (based on the size) and
> sends the data buffer and the intent id. Local side
> receives the data and copies it to the local intent
> buffer.
>
> The whole idea is to avoid stalls on the transport
> for allocating memory, used for copy based transports.
>
> When the remote request to allocate buffers using
> CMD_RX_INTENT_REQ, we allocate buffers of requested
> size, store the buffer id locally and also communicate
> the intent id to the remote.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>   drivers/rpmsg/qcom_glink_native.c | 161 +++++++++++++++++++++++++++++++++++++-
>   drivers/rpmsg/qcom_glink_native.h |   3 +-
>   drivers/rpmsg/qcom_glink_rpm.c    |   3 +-
>   drivers/rpmsg/qcom_glink_smem.c   |   5 +-
>   4 files changed, 167 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
> index acf5558..cbc9f9e 100644
> --- a/drivers/rpmsg/qcom_glink_native.c
> +++ b/drivers/rpmsg/qcom_glink_native.c
> @@ -60,6 +60,25 @@ struct glink_defer_cmd {
>   };
>   
>   /**
> + * RX intent
> + *
> + * data: pointer to the data (may be NULL for zero-copy)
> + * id: remote or local intent ID
> + * size: size of the original intent (do not modify)
> + * reuse: To mark if the intent can be reused after first use
> + * in_use: To mark if intent is already in use for the channel
> + * offset: next write offset (initially 0)
> + */
> +struct glink_core_rx_intent {
> +	void *data;
> +	u32 id;
> +	size_t size;
> +	bool reuse;
> +	bool in_use;
> +	u32 offset;
> +};
> +
> +/**
>    * struct glink_rpm - driver context, relates to one remote subsystem
>    * @dev:	reference to the associated struct device
>    * @doorbell:	"rpm_hlos" ipc doorbell
> @@ -116,6 +135,8 @@ enum {
>    * @name:	unique channel name/identifier
>    * @lcid:	channel id, in local space
>    * @rcid:	channel id, in remote space
> + * @intent_lock: lock for protection of @liids
> + * @liids:	idr of all local intents
>    * @buf:	receive buffer, for gathering fragments
>    * @buf_offset:	write offset in @buf
>    * @buf_size:	size of current @buf
> @@ -136,6 +157,9 @@ struct glink_channel {
>   	unsigned int lcid;
>   	unsigned int rcid;
>   
> +	spinlock_t intent_lock;
> +	struct idr liids;
> +
>   	void *buf;
>   	int buf_offset;
>   	int buf_size;
> @@ -153,6 +177,9 @@ struct glink_channel {
>   #define RPM_CMD_OPEN			2
>   #define RPM_CMD_CLOSE			3
>   #define RPM_CMD_OPEN_ACK		4
> +#define RPM_CMD_INTENT			5
> +#define RPM_CMD_RX_INTENT_REQ		7
> +#define RPM_CMD_RX_INTENT_REQ_ACK	8
>   #define RPM_CMD_TX_DATA			9
>   #define RPM_CMD_CLOSE_ACK		11
>   #define RPM_CMD_TX_DATA_CONT		12
> @@ -177,6 +204,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
>   	init_completion(&channel->open_req);
>   	init_completion(&channel->open_ack);
>   
> +	idr_init(&channel->liids);

spinlock intent_lock initialization is missed ?
>   	kref_init(&channel->refcount);
>   
>   	return channel;
> @@ -187,6 +215,7 @@ static void qcom_glink_channel_release(struct kref *ref)
>   	struct glink_channel *channel = container_of(ref, struct glink_channel,
>   						     refcount);
>   
> +	idr_destroy(&channel->liids);

idr_destroy shouldn`t be covered by intent_lock ?

>   	kfree(channel->name);
>   	kfree(channel);
>   }
> @@ -423,6 +452,130 @@ static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
>   	}
>   }
>   
> +/**
> + * qcom_glink_send_intent_req_ack() - convert an rx intent request ack cmd to
> +				      wire format and transmit
> + * @glink:	The transport to transmit on.
> + * @channel:	The glink channel
> + * @granted:	The request response to encode.
> + *
> + * Return: 0 on success or standard Linux error code.
> + */
> +static int qcom_glink_send_intent_req_ack(struct qcom_glink *glink,
> +					  struct glink_channel *channel,
> +					  bool granted)
> +{
> +	struct glink_msg msg;
> +
> +	msg.cmd = cpu_to_le16(RPM_CMD_RX_INTENT_REQ_ACK);
> +	msg.param1 = cpu_to_le16(channel->lcid);
> +	msg.param2 = cpu_to_le32(granted);
> +
> +	qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
> +
> +	return 0;
> +}
> +
> +/**
> + * tx_cmd_local_rx_intent() - convert an rx intent cmd to wire format and
> + *			   transmit

copy-paste mistake
> + * @glink:	The transport to transmit on.
> + * @channel:	The local channel
> + * @size:	The intent to pass on to remote.
> + *
> + * Return: 0 on success or standard Linux error code.
> + */
> +static int qcom_glink_advertise_intent(struct qcom_glink *glink,
> +				       struct glink_channel *channel,
> +				       struct glink_core_rx_intent *intent)
> +{
> +	struct command {
> +		u16 id;
> +		u16 lcid;
> +		u32 count;
> +		u32 size;
> +		u32 liid;
> +	} __packed;
> +	struct command cmd;
> +
> +	cmd.id = cpu_to_le16(RPM_CMD_INTENT);
> +	cmd.lcid = cpu_to_le16(channel->lcid);
> +	cmd.count = cpu_to_le32(1);
> +	cmd.size = cpu_to_le32(intent->size);
> +	cmd.liid = cpu_to_le32(intent->id);
> +
> +	qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
> +
> +	return 0;
> +}
> +
> +static struct glink_core_rx_intent *
> +qcom_glink_alloc_intent(struct qcom_glink *glink,
> +			struct glink_channel *channel,
> +			size_t size,
> +			bool reuseable)
> +{
> +	struct glink_core_rx_intent *intent;
> +	int ret;
> +	unsigned long flags;
> +
> +	intent = kzalloc(sizeof(*intent), GFP_KERNEL);
> +
> +	if (!intent)
> +		return NULL;
> +
> +	intent->data = kzalloc(size, GFP_KERNEL);
> +	if (!intent->data)
> +		return NULL;
> +
> +	spin_lock_irqsave(&channel->intent_lock, flags);
> +	ret = idr_alloc_cyclic(&channel->liids, intent, 1, -1, GFP_ATOMIC);
> +	if (ret < 0) {
> +		spin_unlock_irqrestore(&channel->intent_lock, flags);
> +		return NULL;
> +	}
> +	spin_unlock_irqrestore(&channel->intent_lock, flags);
> +
> +	intent->id = ret;
> +	intent->size = size;
> +	intent->reuse = reuseable;
> +
> +	return intent;
> +}
> +
> +/**
> + * glink_core_rx_cmd_remote_rx_intent_req() - Receive a request for rx_intent
> + *					    from remote side

copy-paste mistake
> + * if_ptr:      Pointer to the transport interface
> + * rcid:	Remote channel ID
> + * size:	size of the intent
> + *
> + * The function searches for the local channel to which the request for
> + * rx_intent has arrived and allocates and notifies the remote back
> + */
> +static void qcom_glink_handle_intent_req(struct qcom_glink *glink,
> +					 u32 cid, size_t size)
> +{
> +	struct glink_core_rx_intent *intent;
> +	struct glink_channel *channel;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&glink->idr_lock, flags);
> +	channel = idr_find(&glink->rcids, cid);
> +	spin_unlock_irqrestore(&glink->idr_lock, flags);
> +
> +	if (!channel) {
> +		pr_err("%s channel not found for cid %d\n", __func__, cid);
> +		return;
> +	}
> +
> +	intent = qcom_glink_alloc_intent(glink, channel, size, false);
> +	if (intent)
> +		qcom_glink_advertise_intent(glink, channel, intent);
> +
> +	qcom_glink_send_intent_req_ack(glink, channel, !!intent);
> +}
> +
>   static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
>   {
>   	struct glink_defer_cmd *dcmd;
> @@ -585,6 +738,7 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
>   		case RPM_CMD_VERSION_ACK:
>   		case RPM_CMD_CLOSE:
>   		case RPM_CMD_CLOSE_ACK:
> +		case RPM_CMD_RX_INTENT_REQ:
>   			ret = qcom_glink_rx_defer(glink, 0);
>   			break;
>   		case RPM_CMD_OPEN_ACK:
> @@ -1002,6 +1156,9 @@ static void qcom_glink_work(struct work_struct *work)
>   		case RPM_CMD_CLOSE_ACK:
>   			qcom_glink_rx_close_ack(glink, param1);
>   			break;
> +		case RPM_CMD_RX_INTENT_REQ:
> +			qcom_glink_handle_intent_req(glink, param1, param2);
> +			break;
>   		default:
>   			WARN(1, "Unknown defer object %d\n", cmd);
>   			break;
> @@ -1014,7 +1171,8 @@ static void qcom_glink_work(struct work_struct *work)
>   struct qcom_glink *qcom_glink_native_probe(struct device *dev,
>   					   unsigned long features,
>   					   struct qcom_glink_pipe *rx,
> -					   struct qcom_glink_pipe *tx)
> +					   struct qcom_glink_pipe *tx,
> +					   bool intentless)
>   {
>   	int irq;
>   	int ret;
> @@ -1029,6 +1187,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev,
>   	glink->rx_pipe = rx;
>   
>   	glink->features = features;
> +	glink->intentless = intentless;
>   
>   	mutex_init(&glink->tx_lock);
>   	spin_lock_init(&glink->rx_lock);
> diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h
> index f418787..d7538c3 100644
> --- a/drivers/rpmsg/qcom_glink_native.h
> +++ b/drivers/rpmsg/qcom_glink_native.h
> @@ -37,7 +37,8 @@ struct qcom_glink_pipe {
>   struct qcom_glink *qcom_glink_native_probe(struct device *dev,
>   					   unsigned long features,
>   					   struct qcom_glink_pipe *rx,
> -					   struct qcom_glink_pipe *tx);
> +					   struct qcom_glink_pipe *tx,
> +					   bool intentless);
>   void qcom_glink_native_remove(struct qcom_glink *glink);
>   
>   #endif
> diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c
> index 7d039cd..5a86e08 100644
> --- a/drivers/rpmsg/qcom_glink_rpm.c
> +++ b/drivers/rpmsg/qcom_glink_rpm.c
> @@ -305,7 +305,8 @@ static int glink_rpm_probe(struct platform_device *pdev)
>   	glink = qcom_glink_native_probe(&pdev->dev,
>   					0,
>   					&rx_pipe->native,
> -					&tx_pipe->native);
> +					&tx_pipe->native,
> +					true);
>   	if (IS_ERR(glink))
>   		return PTR_ERR(glink);
>   
> diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c
> index 496a5e3..e792895 100644
> --- a/drivers/rpmsg/qcom_glink_smem.c
> +++ b/drivers/rpmsg/qcom_glink_smem.c
> @@ -278,8 +278,9 @@ struct qcom_glink *qcom_glink_smem_register(struct device *parent,
>   	*tx_pipe->head = 0;
>   
>   	glink = qcom_glink_native_probe(dev,
> -					GLINK_FEATURE_TRACER_PKT,
> -					&rx_pipe->native, &tx_pipe->native);
> +					GLINK_FEATURE_INTENT_REUSE,
> +					&rx_pipe->native, &tx_pipe->native,
> +					false);
>   	if (IS_ERR(glink)) {
>   		ret = PTR_ERR(glink);
>   		goto err_put_dev;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 11/18] rpmsg: glink: Use the local intents when receiving data
  2017-08-16 17:19   ` Sricharan R
@ 2017-08-22  9:26     ` Arun Kumar Neelakantam
  -1 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22  9:26 UTC (permalink / raw)
  To: Sricharan R, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel



On 8/16/2017 10:49 PM, Sricharan R wrote:
> So previously on request from remote side, we allocated local
> intent buffers and passed the ids to the remote. Now when
> we receive data buffers from remote directed to that intent
> id, copy the data to the corresponding preallocated intent
> buffer.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>   drivers/rpmsg/qcom_glink_native.c | 75 ++++++++++++++++++++++++++-------------
>   1 file changed, 50 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
> index cbc9f9e..d6aa589 100644
> --- a/drivers/rpmsg/qcom_glink_native.c
> +++ b/drivers/rpmsg/qcom_glink_native.c
> @@ -160,7 +160,7 @@ struct glink_channel {
>   	spinlock_t intent_lock;
>   	struct idr liids;
>   
> -	void *buf;
> +	struct glink_core_rx_intent *buf;
>   	int buf_offset;
>   	int buf_size;
>   
> @@ -607,6 +607,7 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
>   
>   static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   {
> +	struct glink_core_rx_intent *intent;
>   	struct glink_channel *channel;
>   	struct {
>   		struct glink_msg msg;
> @@ -616,6 +617,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   	unsigned int chunk_size;
>   	unsigned int left_size;
>   	unsigned int rcid;
> +	unsigned int liid;
> +	int ret = 0;
>   	unsigned long flags;
>   
>   	if (avail < sizeof(hdr)) {
> @@ -643,56 +646,78 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   		dev_dbg(glink->dev, "Data on non-existing channel\n");
>   
>   		/* Drop the message */
> -		qcom_glink_rx_advance(glink,
> -				      ALIGN(sizeof(hdr) + chunk_size, 8));
> -		return 0;
> +		goto advance_rx;
>   	}
>   
> -	/* Might have an ongoing, fragmented, message to append */
> -	if (!channel->buf) {
> -		channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
> -		if (!channel->buf)
> -			return -ENOMEM;
> +	if (glink->intentless) {
> +		/* Might have an ongoing, fragmented, message to append */
> +		if (!channel->buf) {
> +			intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
> +			if (!intent)
> +				return -ENOMEM;
> +
> +			intent->data = kmalloc(chunk_size + left_size,
> +					       GFP_ATOMIC);

Who is supposed to free the intent and intent->data memory ?
> +			if (!intent->data) {
> +				kfree(intent);
> +				return -ENOMEM;
> +			}
> +
> +			intent->id = 0xbabababa;
> +			intent->size = chunk_size + left_size;
> +			intent->offset = 0;
> +
> +			channel->buf = intent;
> +		} else {
> +			intent = channel->buf;
> +		}
> +	} else {
> +		liid = le32_to_cpu(hdr.msg.param2);
>   
> -		channel->buf_size = chunk_size + left_size;
> -		channel->buf_offset = 0;
> -	}
> +		spin_lock_irqsave(&channel->intent_lock, flags);
> +		intent = idr_find(&channel->liids, liid);
> +		spin_unlock_irqrestore(&channel->intent_lock, flags);
>   
> -	qcom_glink_rx_advance(glink, sizeof(hdr));
> +		if (!intent) {
> +			dev_err(glink->dev,
> +				"no intent found for channel %s intent %d",
> +				channel->name, liid);
> +			goto advance_rx;
> +		}
> +	}
>   
> -	if (channel->buf_size - channel->buf_offset < chunk_size) {
> -		dev_err(glink->dev, "Insufficient space in input buffer\n");
> +	if (intent->size - intent->offset < chunk_size) {
> +		dev_err(glink->dev, "Insufficient space in intent\n");
>   
>   		/* The packet header lied, drop payload */
> -		qcom_glink_rx_advance(glink, chunk_size);
> -		return -ENOMEM;
> +		goto advance_rx;
>   	}
>   
> -	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
> +	qcom_glink_rx_advance(glink, ALIGN(sizeof(hdr), 8));
> +	qcom_glink_rx_peak(glink, intent->data + intent->offset,
>   			   chunk_size);
> -	channel->buf_offset += chunk_size;
> +	intent->offset += chunk_size;
>   
>   	/* Handle message when no fragments remain to be received */
>   	if (!left_size) {
>   		spin_lock(&channel->recv_lock);
>   		if (channel->ept.cb) {
>   			channel->ept.cb(channel->ept.rpdev,
> -					channel->buf,
> -					channel->buf_offset,
> +					intent->data,
> +					intent->offset,
>   					channel->ept.priv,
>   					RPMSG_ADDR_ANY);
>   		}
>   		spin_unlock(&channel->recv_lock);
>   
> -		kfree(channel->buf);
> +		intent->offset = 0;
>   		channel->buf = NULL;
> -		channel->buf_size = 0;
>   	}
>   
> -	/* Each message starts at 8 byte aligned address */
> +advance_rx:
>   	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
>   
> -	return 0;
> +	return ret;
>   }
>   
>   static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 11/18] rpmsg: glink: Use the local intents when receiving data
@ 2017-08-22  9:26     ` Arun Kumar Neelakantam
  0 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22  9:26 UTC (permalink / raw)
  To: linux-arm-kernel



On 8/16/2017 10:49 PM, Sricharan R wrote:
> So previously on request from remote side, we allocated local
> intent buffers and passed the ids to the remote. Now when
> we receive data buffers from remote directed to that intent
> id, copy the data to the corresponding preallocated intent
> buffer.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>   drivers/rpmsg/qcom_glink_native.c | 75 ++++++++++++++++++++++++++-------------
>   1 file changed, 50 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
> index cbc9f9e..d6aa589 100644
> --- a/drivers/rpmsg/qcom_glink_native.c
> +++ b/drivers/rpmsg/qcom_glink_native.c
> @@ -160,7 +160,7 @@ struct glink_channel {
>   	spinlock_t intent_lock;
>   	struct idr liids;
>   
> -	void *buf;
> +	struct glink_core_rx_intent *buf;
>   	int buf_offset;
>   	int buf_size;
>   
> @@ -607,6 +607,7 @@ static int qcom_glink_rx_defer(struct qcom_glink *glink, size_t extra)
>   
>   static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   {
> +	struct glink_core_rx_intent *intent;
>   	struct glink_channel *channel;
>   	struct {
>   		struct glink_msg msg;
> @@ -616,6 +617,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   	unsigned int chunk_size;
>   	unsigned int left_size;
>   	unsigned int rcid;
> +	unsigned int liid;
> +	int ret = 0;
>   	unsigned long flags;
>   
>   	if (avail < sizeof(hdr)) {
> @@ -643,56 +646,78 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   		dev_dbg(glink->dev, "Data on non-existing channel\n");
>   
>   		/* Drop the message */
> -		qcom_glink_rx_advance(glink,
> -				      ALIGN(sizeof(hdr) + chunk_size, 8));
> -		return 0;
> +		goto advance_rx;
>   	}
>   
> -	/* Might have an ongoing, fragmented, message to append */
> -	if (!channel->buf) {
> -		channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
> -		if (!channel->buf)
> -			return -ENOMEM;
> +	if (glink->intentless) {
> +		/* Might have an ongoing, fragmented, message to append */
> +		if (!channel->buf) {
> +			intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
> +			if (!intent)
> +				return -ENOMEM;
> +
> +			intent->data = kmalloc(chunk_size + left_size,
> +					       GFP_ATOMIC);

Who is supposed to free the intent and intent->data memory ?
> +			if (!intent->data) {
> +				kfree(intent);
> +				return -ENOMEM;
> +			}
> +
> +			intent->id = 0xbabababa;
> +			intent->size = chunk_size + left_size;
> +			intent->offset = 0;
> +
> +			channel->buf = intent;
> +		} else {
> +			intent = channel->buf;
> +		}
> +	} else {
> +		liid = le32_to_cpu(hdr.msg.param2);
>   
> -		channel->buf_size = chunk_size + left_size;
> -		channel->buf_offset = 0;
> -	}
> +		spin_lock_irqsave(&channel->intent_lock, flags);
> +		intent = idr_find(&channel->liids, liid);
> +		spin_unlock_irqrestore(&channel->intent_lock, flags);
>   
> -	qcom_glink_rx_advance(glink, sizeof(hdr));
> +		if (!intent) {
> +			dev_err(glink->dev,
> +				"no intent found for channel %s intent %d",
> +				channel->name, liid);
> +			goto advance_rx;
> +		}
> +	}
>   
> -	if (channel->buf_size - channel->buf_offset < chunk_size) {
> -		dev_err(glink->dev, "Insufficient space in input buffer\n");
> +	if (intent->size - intent->offset < chunk_size) {
> +		dev_err(glink->dev, "Insufficient space in intent\n");
>   
>   		/* The packet header lied, drop payload */
> -		qcom_glink_rx_advance(glink, chunk_size);
> -		return -ENOMEM;
> +		goto advance_rx;
>   	}
>   
> -	qcom_glink_rx_peak(glink, channel->buf + channel->buf_offset,
> +	qcom_glink_rx_advance(glink, ALIGN(sizeof(hdr), 8));
> +	qcom_glink_rx_peak(glink, intent->data + intent->offset,
>   			   chunk_size);
> -	channel->buf_offset += chunk_size;
> +	intent->offset += chunk_size;
>   
>   	/* Handle message when no fragments remain to be received */
>   	if (!left_size) {
>   		spin_lock(&channel->recv_lock);
>   		if (channel->ept.cb) {
>   			channel->ept.cb(channel->ept.rpdev,
> -					channel->buf,
> -					channel->buf_offset,
> +					intent->data,
> +					intent->offset,
>   					channel->ept.priv,
>   					RPMSG_ADDR_ANY);
>   		}
>   		spin_unlock(&channel->recv_lock);
>   
> -		kfree(channel->buf);
> +		intent->offset = 0;
>   		channel->buf = NULL;
> -		channel->buf_size = 0;
>   	}
>   
> -	/* Each message starts at 8 byte aligned address */
> +advance_rx:
>   	qcom_glink_rx_advance(glink, ALIGN(chunk_size, 8));
>   
> -	return 0;
> +	return ret;
>   }
>   
>   static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 13/18] rpmsg: glink: Add rx done command
  2017-08-16 17:19   ` Sricharan R
@ 2017-08-22 10:25     ` Arun Kumar Neelakantam
  -1 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22 10:25 UTC (permalink / raw)
  To: Sricharan R, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel



On 8/16/2017 10:49 PM, Sricharan R wrote:
> Send RX data receive ack to remote and also inform
> that local intent buffer is used and freed. This
> informs the remote to request for next set of
> intent buffers before doing a send operation.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>   drivers/rpmsg/qcom_glink_native.c | 83 +++++++++++++++++++++++++++++++++++++++
>   1 file changed, 83 insertions(+)
>
> diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
> index b2a583a..b8db74a 100644
> --- a/drivers/rpmsg/qcom_glink_native.c
> +++ b/drivers/rpmsg/qcom_glink_native.c
> @@ -76,6 +76,8 @@ struct glink_core_rx_intent {
>   	bool reuse;
>   	bool in_use;
>   	u32 offset;
> +
> +	struct list_head node;
>   };
>   
>   /**
> @@ -137,6 +139,8 @@ enum {
>    * @rcid:	channel id, in remote space
>    * @intent_lock: lock for protection of @liids
>    * @liids:	idr of all local intents
> + * @intent_work: worker responsible for transmitting rx_done packets
> + * @done_intents: list of intents that needs to be announced rx_done
>    * @buf:	receive buffer, for gathering fragments
>    * @buf_offset:	write offset in @buf
>    * @buf_size:	size of current @buf
> @@ -159,6 +163,8 @@ struct glink_channel {
>   
>   	spinlock_t intent_lock;
>   	struct idr liids;
> +	struct work_struct intent_work;
> +	struct list_head done_intents;
>   
>   	struct glink_core_rx_intent *buf;
>   	int buf_offset;
> @@ -178,15 +184,19 @@ struct glink_channel {
>   #define RPM_CMD_CLOSE			3
>   #define RPM_CMD_OPEN_ACK		4
>   #define RPM_CMD_INTENT			5
> +#define RPM_CMD_RX_DONE			6
>   #define RPM_CMD_RX_INTENT_REQ		7
>   #define RPM_CMD_RX_INTENT_REQ_ACK	8
>   #define RPM_CMD_TX_DATA			9
>   #define RPM_CMD_CLOSE_ACK		11
>   #define RPM_CMD_TX_DATA_CONT		12
>   #define RPM_CMD_READ_NOTIF		13
> +#define RPM_CMD_RX_DONE_W_REUSE		14
>   
>   #define GLINK_FEATURE_INTENTLESS	BIT(1)
>   
> +static void qcom_glink_rx_done_work(struct work_struct *work);
> +
>   static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
>   						      const char *name)
>   {
> @@ -198,12 +208,16 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
>   
>   	/* Setup glink internal glink_channel data */
>   	spin_lock_init(&channel->recv_lock);
> +
>   	channel->glink = glink;
>   	channel->name = kstrdup(name, GFP_KERNEL);
>   
>   	init_completion(&channel->open_req);
>   	init_completion(&channel->open_ack);
>   
> +	INIT_LIST_HEAD(&channel->done_intents);
> +	INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work);
> +
>   	idr_init(&channel->liids);
>   	kref_init(&channel->refcount);
>   
> @@ -395,6 +409,70 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink,
>   	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
>   }
>   
> +static void qcom_glink_rx_done_work(struct work_struct *work)
> +{
> +	struct glink_channel *channel = container_of(work, struct glink_channel,
> +						     intent_work);
> +	struct qcom_glink *glink = channel->glink;
> +	struct glink_core_rx_intent *intent, *tmp;
> +	struct {
> +		u16 id;
> +		u16 lcid;
> +		u32 liid;
> +	} __packed cmd;
> +
> +	unsigned int cid = 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 ? RPM_CMD_RX_DONE_W_REUSE : RPM_CMD_RX_DONE;
> +		cmd.lcid = cid;
> +		cmd.liid = iid;
> +
> +		qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
> +		if (!reuse) {
> +			kfree(intent->data);
> +			kfree(intent);
> +		}
> +		spin_lock_irqsave(&channel->intent_lock, flags);
> +	}
> +	spin_unlock_irqrestore(&channel->intent_lock, flags);
> +}
> +
> +static void qcom_glink_rx_done(struct qcom_glink *glink,
> +			       struct glink_channel *channel,
> +			       struct glink_core_rx_intent *intent)
> +{
> +	/* 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(&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);

Adding one more parallel path will hit performance, if this worker could 
not get CPU cycles
or blocked by other RT or HIGH_PRIO worker on global worker pool.

> +}
> +
>   /**
>    * qcom_glink_receive_version() - receive version/features from remote system
>    *
> @@ -711,6 +789,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   
>   		intent->offset = 0;
>   		channel->buf = NULL;
> +
> +		qcom_glink_rx_done(glink, channel, intent);
>   	}
>   
>   advance_rx:
> @@ -1100,6 +1180,9 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
>   	if (WARN(!channel, "close request on unknown channel\n"))
>   		return;
>   
> +	/* cancel pending rx_done work */
> +	cancel_work_sync(&channel->intent_work);
> +
>   	if (channel->rpdev) {
>   		strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
>   		chinfo.src = RPMSG_ADDR_ANY;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 13/18] rpmsg: glink: Add rx done command
@ 2017-08-22 10:25     ` Arun Kumar Neelakantam
  0 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22 10:25 UTC (permalink / raw)
  To: linux-arm-kernel



On 8/16/2017 10:49 PM, Sricharan R wrote:
> Send RX data receive ack to remote and also inform
> that local intent buffer is used and freed. This
> informs the remote to request for next set of
> intent buffers before doing a send operation.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>   drivers/rpmsg/qcom_glink_native.c | 83 +++++++++++++++++++++++++++++++++++++++
>   1 file changed, 83 insertions(+)
>
> diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
> index b2a583a..b8db74a 100644
> --- a/drivers/rpmsg/qcom_glink_native.c
> +++ b/drivers/rpmsg/qcom_glink_native.c
> @@ -76,6 +76,8 @@ struct glink_core_rx_intent {
>   	bool reuse;
>   	bool in_use;
>   	u32 offset;
> +
> +	struct list_head node;
>   };
>   
>   /**
> @@ -137,6 +139,8 @@ enum {
>    * @rcid:	channel id, in remote space
>    * @intent_lock: lock for protection of @liids
>    * @liids:	idr of all local intents
> + * @intent_work: worker responsible for transmitting rx_done packets
> + * @done_intents: list of intents that needs to be announced rx_done
>    * @buf:	receive buffer, for gathering fragments
>    * @buf_offset:	write offset in @buf
>    * @buf_size:	size of current @buf
> @@ -159,6 +163,8 @@ struct glink_channel {
>   
>   	spinlock_t intent_lock;
>   	struct idr liids;
> +	struct work_struct intent_work;
> +	struct list_head done_intents;
>   
>   	struct glink_core_rx_intent *buf;
>   	int buf_offset;
> @@ -178,15 +184,19 @@ struct glink_channel {
>   #define RPM_CMD_CLOSE			3
>   #define RPM_CMD_OPEN_ACK		4
>   #define RPM_CMD_INTENT			5
> +#define RPM_CMD_RX_DONE			6
>   #define RPM_CMD_RX_INTENT_REQ		7
>   #define RPM_CMD_RX_INTENT_REQ_ACK	8
>   #define RPM_CMD_TX_DATA			9
>   #define RPM_CMD_CLOSE_ACK		11
>   #define RPM_CMD_TX_DATA_CONT		12
>   #define RPM_CMD_READ_NOTIF		13
> +#define RPM_CMD_RX_DONE_W_REUSE		14
>   
>   #define GLINK_FEATURE_INTENTLESS	BIT(1)
>   
> +static void qcom_glink_rx_done_work(struct work_struct *work);
> +
>   static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
>   						      const char *name)
>   {
> @@ -198,12 +208,16 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
>   
>   	/* Setup glink internal glink_channel data */
>   	spin_lock_init(&channel->recv_lock);
> +
>   	channel->glink = glink;
>   	channel->name = kstrdup(name, GFP_KERNEL);
>   
>   	init_completion(&channel->open_req);
>   	init_completion(&channel->open_ack);
>   
> +	INIT_LIST_HEAD(&channel->done_intents);
> +	INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work);
> +
>   	idr_init(&channel->liids);
>   	kref_init(&channel->refcount);
>   
> @@ -395,6 +409,70 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink,
>   	qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true);
>   }
>   
> +static void qcom_glink_rx_done_work(struct work_struct *work)
> +{
> +	struct glink_channel *channel = container_of(work, struct glink_channel,
> +						     intent_work);
> +	struct qcom_glink *glink = channel->glink;
> +	struct glink_core_rx_intent *intent, *tmp;
> +	struct {
> +		u16 id;
> +		u16 lcid;
> +		u32 liid;
> +	} __packed cmd;
> +
> +	unsigned int cid = 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 ? RPM_CMD_RX_DONE_W_REUSE : RPM_CMD_RX_DONE;
> +		cmd.lcid = cid;
> +		cmd.liid = iid;
> +
> +		qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
> +		if (!reuse) {
> +			kfree(intent->data);
> +			kfree(intent);
> +		}
> +		spin_lock_irqsave(&channel->intent_lock, flags);
> +	}
> +	spin_unlock_irqrestore(&channel->intent_lock, flags);
> +}
> +
> +static void qcom_glink_rx_done(struct qcom_glink *glink,
> +			       struct glink_channel *channel,
> +			       struct glink_core_rx_intent *intent)
> +{
> +	/* 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(&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);

Adding one more parallel path will hit performance, if this worker could 
not get CPU cycles
or blocked by other RT or HIGH_PRIO worker on global worker pool.

> +}
> +
>   /**
>    * qcom_glink_receive_version() - receive version/features from remote system
>    *
> @@ -711,6 +789,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   
>   		intent->offset = 0;
>   		channel->buf = NULL;
> +
> +		qcom_glink_rx_done(glink, channel, intent);
>   	}
>   
>   advance_rx:
> @@ -1100,6 +1180,9 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
>   	if (WARN(!channel, "close request on unknown channel\n"))
>   		return;
>   
> +	/* cancel pending rx_done work */
> +	cancel_work_sync(&channel->intent_work);
> +
>   	if (channel->rpdev) {
>   		strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
>   		chinfo.src = RPMSG_ADDR_ANY;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 15/18] rpmsg: glink: Receive and store the remote intent buffers
  2017-08-16 17:19   ` Sricharan R
@ 2017-08-22 10:41     ` Arun Kumar Neelakantam
  -1 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22 10:41 UTC (permalink / raw)
  To: Sricharan R, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel



On 8/16/2017 10:49 PM, Sricharan R wrote:
> Just like we allocating and sending intent ids to remote,
> remote side allocates and sends us the intents as well.
> So save the intent ids and use it later while sending
> data targeting the appropriate intents based on the size.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>   drivers/rpmsg/qcom_glink_native.c | 69 +++++++++++++++++++++++++++++++++++++++
>   1 file changed, 69 insertions(+)
>
> diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
> index c111046..738303e 100644
> --- a/drivers/rpmsg/qcom_glink_native.c
> +++ b/drivers/rpmsg/qcom_glink_native.c
> @@ -139,6 +139,7 @@ enum {
>    * @rcid:	channel id, in remote space
>    * @intent_lock: lock for protection of @liids
>    * @liids:	idr of all local intents
> + * @riids:	idr of all remote intents
>    * @intent_work: worker responsible for transmitting rx_done packets
>    * @done_intents: list of intents that needs to be announced rx_done
>    * @buf:	receive buffer, for gathering fragments
> @@ -163,6 +164,7 @@ struct glink_channel {
>   
>   	spinlock_t intent_lock;
>   	struct idr liids;
> +	struct idr riids;
>   	struct work_struct intent_work;
>   	struct list_head done_intents;
>   
> @@ -219,6 +221,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
>   	INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work);
>   
>   	idr_init(&channel->liids);
> +	idr_init(&channel->riids);
>   	kref_init(&channel->refcount);
>   
>   	return channel;
> @@ -230,6 +233,7 @@ static void qcom_glink_channel_release(struct kref *ref)
>   						     refcount);
>   
>   	idr_destroy(&channel->liids);
> +	idr_destroy(&channel->riids);
>   	kfree(channel->name);
>   	kfree(channel);
>   }
> @@ -799,6 +803,68 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   	return ret;
>   }
>   
> +static void qcom_glink_handle_intent(struct qcom_glink *glink,
> +				     unsigned int cid,
> +				     unsigned int count,
> +				     size_t avail)
> +{
> +	struct glink_core_rx_intent *intent;
> +	struct glink_channel *channel;
> +	struct intent_pair {
> +		__le32 size;
> +		__le32 iid;
> +	};
> +
> +	struct {
> +		struct glink_msg msg;
> +		struct intent_pair intents[];
> +	} __packed *msg;
> +
> +	const size_t msglen = sizeof(*msg) + sizeof(struct intent_pair) * count;
> +	int ret;
> +	int i;
> +	unsigned long flags;
> +
> +	if (avail < msglen) {
> +		dev_dbg(glink->dev, "Not enough data in fifo\n");
> +		return;
> +	}
> +
> +	spin_lock_irqsave(&glink->idr_lock, flags);
> +	channel = idr_find(&glink->rcids, cid);
> +	spin_unlock_irqrestore(&glink->idr_lock, flags);
> +	if (!channel) {
> +		dev_err(glink->dev, "intents for non-existing channel\n");
> +		return;
> +	}
> +
> +	msg = kmalloc(msglen, GFP_ATOMIC);

Why kmalloc() instead of kzalloc() ?
> +	if (!msg)
> +		return;
> +
> +	qcom_glink_rx_peak(glink, msg, 0, msglen);
> +
> +	for (i = 0; i < count; ++i) {
> +		intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
> +		if (!intent)
> +			break;
> +
> +		intent->id = le32_to_cpu(msg->intents[i].iid);
> +		intent->size = le32_to_cpu(msg->intents[i].size);
> +
> +		spin_lock_irqsave(&channel->intent_lock, flags);
> +		ret = idr_alloc(&channel->riids, intent,
> +				intent->id, intent->id + 1, GFP_ATOMIC);
> +		spin_unlock_irqrestore(&channel->intent_lock, flags);
> +
> +		if (ret < 0)
> +			dev_err(glink->dev, "failed to store remote intent\n");
> +	}
> +
> +	kfree(msg);
> +	qcom_glink_rx_advance(glink, ALIGN(msglen, 8));
> +}
> +
>   static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
>   {
>   	struct glink_channel *channel;
> @@ -864,6 +930,9 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
>   
>   			ret = 0;
>   			break;
> +		case RPM_CMD_INTENT:
> +			qcom_glink_handle_intent(glink, param1, param2, avail);
> +			break;
>   		default:
>   			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
>   			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 15/18] rpmsg: glink: Receive and store the remote intent buffers
@ 2017-08-22 10:41     ` Arun Kumar Neelakantam
  0 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-22 10:41 UTC (permalink / raw)
  To: linux-arm-kernel



On 8/16/2017 10:49 PM, Sricharan R wrote:
> Just like we allocating and sending intent ids to remote,
> remote side allocates and sends us the intents as well.
> So save the intent ids and use it later while sending
> data targeting the appropriate intents based on the size.
>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
>   drivers/rpmsg/qcom_glink_native.c | 69 +++++++++++++++++++++++++++++++++++++++
>   1 file changed, 69 insertions(+)
>
> diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c
> index c111046..738303e 100644
> --- a/drivers/rpmsg/qcom_glink_native.c
> +++ b/drivers/rpmsg/qcom_glink_native.c
> @@ -139,6 +139,7 @@ enum {
>    * @rcid:	channel id, in remote space
>    * @intent_lock: lock for protection of @liids
>    * @liids:	idr of all local intents
> + * @riids:	idr of all remote intents
>    * @intent_work: worker responsible for transmitting rx_done packets
>    * @done_intents: list of intents that needs to be announced rx_done
>    * @buf:	receive buffer, for gathering fragments
> @@ -163,6 +164,7 @@ struct glink_channel {
>   
>   	spinlock_t intent_lock;
>   	struct idr liids;
> +	struct idr riids;
>   	struct work_struct intent_work;
>   	struct list_head done_intents;
>   
> @@ -219,6 +221,7 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
>   	INIT_WORK(&channel->intent_work, qcom_glink_rx_done_work);
>   
>   	idr_init(&channel->liids);
> +	idr_init(&channel->riids);
>   	kref_init(&channel->refcount);
>   
>   	return channel;
> @@ -230,6 +233,7 @@ static void qcom_glink_channel_release(struct kref *ref)
>   						     refcount);
>   
>   	idr_destroy(&channel->liids);
> +	idr_destroy(&channel->riids);
>   	kfree(channel->name);
>   	kfree(channel);
>   }
> @@ -799,6 +803,68 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
>   	return ret;
>   }
>   
> +static void qcom_glink_handle_intent(struct qcom_glink *glink,
> +				     unsigned int cid,
> +				     unsigned int count,
> +				     size_t avail)
> +{
> +	struct glink_core_rx_intent *intent;
> +	struct glink_channel *channel;
> +	struct intent_pair {
> +		__le32 size;
> +		__le32 iid;
> +	};
> +
> +	struct {
> +		struct glink_msg msg;
> +		struct intent_pair intents[];
> +	} __packed *msg;
> +
> +	const size_t msglen = sizeof(*msg) + sizeof(struct intent_pair) * count;
> +	int ret;
> +	int i;
> +	unsigned long flags;
> +
> +	if (avail < msglen) {
> +		dev_dbg(glink->dev, "Not enough data in fifo\n");
> +		return;
> +	}
> +
> +	spin_lock_irqsave(&glink->idr_lock, flags);
> +	channel = idr_find(&glink->rcids, cid);
> +	spin_unlock_irqrestore(&glink->idr_lock, flags);
> +	if (!channel) {
> +		dev_err(glink->dev, "intents for non-existing channel\n");
> +		return;
> +	}
> +
> +	msg = kmalloc(msglen, GFP_ATOMIC);

Why kmalloc() instead of kzalloc() ?
> +	if (!msg)
> +		return;
> +
> +	qcom_glink_rx_peak(glink, msg, 0, msglen);
> +
> +	for (i = 0; i < count; ++i) {
> +		intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
> +		if (!intent)
> +			break;
> +
> +		intent->id = le32_to_cpu(msg->intents[i].iid);
> +		intent->size = le32_to_cpu(msg->intents[i].size);
> +
> +		spin_lock_irqsave(&channel->intent_lock, flags);
> +		ret = idr_alloc(&channel->riids, intent,
> +				intent->id, intent->id + 1, GFP_ATOMIC);
> +		spin_unlock_irqrestore(&channel->intent_lock, flags);
> +
> +		if (ret < 0)
> +			dev_err(glink->dev, "failed to store remote intent\n");
> +	}
> +
> +	kfree(msg);
> +	qcom_glink_rx_advance(glink, ALIGN(msglen, 8));
> +}
> +
>   static int qcom_glink_rx_open_ack(struct qcom_glink *glink, unsigned int lcid)
>   {
>   	struct glink_channel *channel;
> @@ -864,6 +930,9 @@ static irqreturn_t qcom_glink_native_intr(int irq, void *data)
>   
>   			ret = 0;
>   			break;
> +		case RPM_CMD_INTENT:
> +			qcom_glink_handle_intent(glink, param1, param2, avail);
> +			break;
>   		default:
>   			qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
>   			dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 04/18] rpmsg: glink: Move the common glink protocol implementation to glink_native.c
  2017-08-22  5:58     ` Arun Kumar Neelakantam
@ 2017-08-22 12:27       ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-22 12:27 UTC (permalink / raw)
  To: Arun Kumar Neelakantam, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel

Hi Arun,
  Thanks for the review.

On 8/22/2017 11:28 AM, Arun Kumar Neelakantam wrote:
> 
> 
> On 8/16/2017 10:48 PM, Sricharan R wrote:
>> +
>> +struct glink_msg {
>> +    __le16 cmd;
>> +    __le16 param1;
>> +    __le32 param2;
>> +    u8 data[];
>> +} __packed;
> 
> why we are using extra u8 data[] member here ?
> 
 Just as a zero-sized placeholder, to read a variable length header if required.

>> +
>> +/**
>> + * struct glink_defer_cmd - deferred incoming control message
>> + * @node:    list node
>> + * @msg:    message header
>> + * data:    payload of the message
>> + *
>> + * Copy of a received control message, to be added to @rx_queue and processed
>> + * by @rx_work of @glink_rpm.
>> + */
>> +struct glink_defer_cmd {
>> +    struct list_head node;
>> +
>> +    struct glink_msg msg;
>> +    u8 data[];
>> +};
>> +
>> +/**
>> + * struct glink_rpm - driver context, relates to one remote subsystem
> 
> glink_rpm to qcom_glink
> 
 ok, will change.

>> +static int qcom_glink_tx(struct qcom_glink *glink,
>> +             const void *hdr, size_t hlen,
>> +             const void *data, size_t dlen, bool wait)
>> +{
>> +    unsigned int tlen = hlen + dlen;
>> +    int ret;
>> +
>> +    /* Reject packets that are too big */
>> +    if (tlen >= glink->tx_pipe->length)
>> +        return -EINVAL;
> 
> we need to add support for split packets, in some cases packets may be greater than 16K.

 ok, the plan was to add that in next set of patches and keep this series to a minimum.

>> +
>> +    if (WARN(tlen % 8, "Unaligned TX request"))
>> +        return -EINVAL;
>> +
>> +    ret = mutex_lock_interruptible(&glink->tx_lock);
>> +    if (ret)
>> +        return ret;
>> +
>> +    while (qcom_glink_tx_avail(glink) < tlen) {
>> +        if (!wait) {
>> +            ret = -ENOMEM;
> 
> This condition is either reader is slow or not reading data, should we return -EAGAIN here instead of -ENOMEM?

 ok, will change.

>> +            goto out;
>> +        }
>> +
>> +        msleep(10);
>> +    }
>> +
>> +    qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
>> +
>> +    mbox_send_message(glink->mbox_chan, NULL);
>> +    mbox_client_txdone(glink->mbox_chan, 0);
>> +
>> +out:
>> +    mutex_unlock(&glink->tx_lock);
>> +
>> +    return ret;
>> +}
>> +
> 
> 
>> +/**
>> + * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
>> + * @glink:
>> + * @channel:
> 
> Missed information for @ glink and @channel

 ok, will add.

>> + *
>> + * Allocates a local channel id and sends a RPM_CMD_OPEN message to the remote.
>> + * Will return with refcount held, regardless of outcome.
>> + *
>> + * Returns 0 on success, negative errno otherwise.
>> + */
>> +static int qcom_glink_send_open_req(struct qcom_glink *glink,
>> +                    struct glink_channel *channel)
> 
> 
>> +static irqreturn_t qcom_glink_native_intr(int irq, void *data)
>> +{
>> +    struct qcom_glink *glink = data;
>> +    struct glink_msg msg;
>> +    unsigned int param1;
>> +    unsigned int param2;
>> +    unsigned int avail;
>> +    unsigned int cmd;
>> +    int ret;
>> +
>> +    for (;;) {
>> +        avail = qcom_glink_rx_avail(glink);
>> +        if (avail < sizeof(msg))
>> +            break;
>> +
>> +        qcom_glink_rx_peak(glink, &msg, sizeof(msg));
>> +
>> +        cmd = le16_to_cpu(msg.cmd);
>> +        param1 = le16_to_cpu(msg.param1);
>> +        param2 = le32_to_cpu(msg.param2);
>> +
>> +        switch (cmd) {
>> +        case RPM_CMD_VERSION:
>> +        case RPM_CMD_VERSION_ACK:
>> +        case RPM_CMD_CLOSE:
>> +        case RPM_CMD_CLOSE_ACK:
>> +            ret = qcom_glink_rx_defer(glink, 0);
>> +            break;
>> +        case RPM_CMD_OPEN_ACK:
>> +            ret = qcom_glink_rx_open_ack(glink, param1);
>> +            qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
>> +            break;
>> +        case RPM_CMD_OPEN:
>> +            ret = qcom_glink_rx_defer(glink, param2);
>> +            break;
>> +        case RPM_CMD_TX_DATA:
>> +        case RPM_CMD_TX_DATA_CONT:
>> +            ret = qcom_glink_rx_data(glink, avail);
>> +            break;
>> +        case RPM_CMD_READ_NOTIF:
>> +            qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
>> +
>> +            mbox_send_message(glink->mbox_chan, NULL);
>> +            mbox_client_txdone(glink->mbox_chan, 0);
>> +
>> +            ret = 0;
>> +            break;
>> +        default:
>> +            dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
> 
> please add more information in error log to find the remote peripheral also other wise after adding SMEM transport it will be difficult to find for which peripheral the error came.

 ok, you refer to logging the "edge" name, that should be taken care by the dev_err print ?
 That said, i think the dev name in glink smem can be modified to reflect the edge name
 instead of simply printing the remoteproc name. Will change that.

>> +            ret = -EINVAL;
>> +            break;
>> +        }
>> +
>> +        if (ret)
>> +            break;
>> +    }
>> +
>> +    return IRQ_HANDLED;
>> +}
>> +
> 
>> +struct qcom_glink *qcom_glink_native_probe(struct device *dev,
>> +                       struct qcom_glink_pipe *rx,
>> +                       struct qcom_glink_pipe *tx)
>> +{
>> +    int irq;
>> +    int ret;
>> +    struct qcom_glink *glink;
>> +
>> +    glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
>> +    if (!glink)
>> +        return ERR_PTR(-ENOMEM);
>> +
>> +    glink->dev = dev;
>> +    glink->tx_pipe = tx;
>> +    glink->rx_pipe = rx;
>> +
>> +    mutex_init(&glink->tx_lock);
>> +    spin_lock_init(&glink->rx_lock);
>> +    INIT_LIST_HEAD(&glink->rx_queue);
>> +    INIT_WORK(&glink->rx_work, qcom_glink_work);
>> +
>> +    mutex_init(&glink->idr_lock);
>> +    idr_init(&glink->lcids);
>> +    idr_init(&glink->rcids);
>> +
>> +    glink->mbox_client.dev = dev;
>> +    glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
>> +    if (IS_ERR(glink->mbox_chan)) {
>> +        if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
>> +            dev_err(dev, "failed to acquire IPC channel\n");
>> +        return ERR_CAST(glink->mbox_chan);
>> +    }
>> +
>> +    irq = of_irq_get(dev->of_node, 0);
>> +    ret = devm_request_irq(dev, irq,
>> +                   qcom_glink_native_intr,
>> +                   IRQF_NO_SUSPEND | IRQF_SHARED,
>> +                   "glink-native", glink);
>> +    if (ret) {
>> +        dev_err(dev, "failed to request IRQ\n");
>> +        return ERR_PTR(ret);
>> +    }
> 
> These IRQs are wake-up-capable, please use enable_irq_wale() also

 ok.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 04/18] rpmsg: glink: Move the common glink protocol implementation to glink_native.c
@ 2017-08-22 12:27       ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-22 12:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arun,
  Thanks for the review.

On 8/22/2017 11:28 AM, Arun Kumar Neelakantam wrote:
> 
> 
> On 8/16/2017 10:48 PM, Sricharan R wrote:
>> +
>> +struct glink_msg {
>> +??? __le16 cmd;
>> +??? __le16 param1;
>> +??? __le32 param2;
>> +??? u8 data[];
>> +} __packed;
> 
> why we are using extra u8 data[] member here ?
> 
 Just as a zero-sized placeholder, to read a variable length header if required.

>> +
>> +/**
>> + * struct glink_defer_cmd - deferred incoming control message
>> + * @node:??? list node
>> + * @msg:??? message header
>> + * data:??? payload of the message
>> + *
>> + * Copy of a received control message, to be added to @rx_queue and processed
>> + * by @rx_work of @glink_rpm.
>> + */
>> +struct glink_defer_cmd {
>> +??? struct list_head node;
>> +
>> +??? struct glink_msg msg;
>> +??? u8 data[];
>> +};
>> +
>> +/**
>> + * struct glink_rpm - driver context, relates to one remote subsystem
> 
> glink_rpm to qcom_glink
> 
 ok, will change.

>> +static int qcom_glink_tx(struct qcom_glink *glink,
>> +???????????? const void *hdr, size_t hlen,
>> +???????????? const void *data, size_t dlen, bool wait)
>> +{
>> +??? unsigned int tlen = hlen + dlen;
>> +??? int ret;
>> +
>> +??? /* Reject packets that are too big */
>> +??? if (tlen >= glink->tx_pipe->length)
>> +??????? return -EINVAL;
> 
> we need to add support for split packets, in some cases packets may be greater than 16K.

 ok, the plan was to add that in next set of patches and keep this series to a minimum.

>> +
>> +??? if (WARN(tlen % 8, "Unaligned TX request"))
>> +??????? return -EINVAL;
>> +
>> +??? ret = mutex_lock_interruptible(&glink->tx_lock);
>> +??? if (ret)
>> +??????? return ret;
>> +
>> +??? while (qcom_glink_tx_avail(glink) < tlen) {
>> +??????? if (!wait) {
>> +??????????? ret = -ENOMEM;
> 
> This condition is either reader is slow or not reading data, should we return -EAGAIN here instead of -ENOMEM?

 ok, will change.

>> +??????????? goto out;
>> +??????? }
>> +
>> +??????? msleep(10);
>> +??? }
>> +
>> +??? qcom_glink_tx_write(glink, hdr, hlen, data, dlen);
>> +
>> +??? mbox_send_message(glink->mbox_chan, NULL);
>> +??? mbox_client_txdone(glink->mbox_chan, 0);
>> +
>> +out:
>> +??? mutex_unlock(&glink->tx_lock);
>> +
>> +??? return ret;
>> +}
>> +
> 
> 
>> +/**
>> + * qcom_glink_send_open_req() - send a RPM_CMD_OPEN request to the remote
>> + * @glink:
>> + * @channel:
> 
> Missed information for @ glink and @channel

 ok, will add.

>> + *
>> + * Allocates a local channel id and sends a RPM_CMD_OPEN message to the remote.
>> + * Will return with refcount held, regardless of outcome.
>> + *
>> + * Returns 0 on success, negative errno otherwise.
>> + */
>> +static int qcom_glink_send_open_req(struct qcom_glink *glink,
>> +??????????????????? struct glink_channel *channel)
> 
> 
>> +static irqreturn_t qcom_glink_native_intr(int irq, void *data)
>> +{
>> +??? struct qcom_glink *glink = data;
>> +??? struct glink_msg msg;
>> +??? unsigned int param1;
>> +??? unsigned int param2;
>> +??? unsigned int avail;
>> +??? unsigned int cmd;
>> +??? int ret;
>> +
>> +??? for (;;) {
>> +??????? avail = qcom_glink_rx_avail(glink);
>> +??????? if (avail < sizeof(msg))
>> +??????????? break;
>> +
>> +??????? qcom_glink_rx_peak(glink, &msg, sizeof(msg));
>> +
>> +??????? cmd = le16_to_cpu(msg.cmd);
>> +??????? param1 = le16_to_cpu(msg.param1);
>> +??????? param2 = le32_to_cpu(msg.param2);
>> +
>> +??????? switch (cmd) {
>> +??????? case RPM_CMD_VERSION:
>> +??????? case RPM_CMD_VERSION_ACK:
>> +??????? case RPM_CMD_CLOSE:
>> +??????? case RPM_CMD_CLOSE_ACK:
>> +??????????? ret = qcom_glink_rx_defer(glink, 0);
>> +??????????? break;
>> +??????? case RPM_CMD_OPEN_ACK:
>> +??????????? ret = qcom_glink_rx_open_ack(glink, param1);
>> +??????????? qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
>> +??????????? break;
>> +??????? case RPM_CMD_OPEN:
>> +??????????? ret = qcom_glink_rx_defer(glink, param2);
>> +??????????? break;
>> +??????? case RPM_CMD_TX_DATA:
>> +??????? case RPM_CMD_TX_DATA_CONT:
>> +??????????? ret = qcom_glink_rx_data(glink, avail);
>> +??????????? break;
>> +??????? case RPM_CMD_READ_NOTIF:
>> +??????????? qcom_glink_rx_advance(glink, ALIGN(sizeof(msg), 8));
>> +
>> +??????????? mbox_send_message(glink->mbox_chan, NULL);
>> +??????????? mbox_client_txdone(glink->mbox_chan, 0);
>> +
>> +??????????? ret = 0;
>> +??????????? break;
>> +??????? default:
>> +??????????? dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd);
> 
> please add more information in error log to find the remote peripheral also other wise after adding SMEM transport it will be difficult to find for which peripheral the error came.

 ok, you refer to logging the "edge" name, that should be taken care by the dev_err print ?
 That said, i think the dev name in glink smem can be modified to reflect the edge name
 instead of simply printing the remoteproc name. Will change that.

>> +??????????? ret = -EINVAL;
>> +??????????? break;
>> +??????? }
>> +
>> +??????? if (ret)
>> +??????????? break;
>> +??? }
>> +
>> +??? return IRQ_HANDLED;
>> +}
>> +
> 
>> +struct qcom_glink *qcom_glink_native_probe(struct device *dev,
>> +?????????????????????? struct qcom_glink_pipe *rx,
>> +?????????????????????? struct qcom_glink_pipe *tx)
>> +{
>> +??? int irq;
>> +??? int ret;
>> +??? struct qcom_glink *glink;
>> +
>> +??? glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL);
>> +??? if (!glink)
>> +??????? return ERR_PTR(-ENOMEM);
>> +
>> +??? glink->dev = dev;
>> +??? glink->tx_pipe = tx;
>> +??? glink->rx_pipe = rx;
>> +
>> +??? mutex_init(&glink->tx_lock);
>> +??? spin_lock_init(&glink->rx_lock);
>> +??? INIT_LIST_HEAD(&glink->rx_queue);
>> +??? INIT_WORK(&glink->rx_work, qcom_glink_work);
>> +
>> +??? mutex_init(&glink->idr_lock);
>> +??? idr_init(&glink->lcids);
>> +??? idr_init(&glink->rcids);
>> +
>> +??? glink->mbox_client.dev = dev;
>> +??? glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0);
>> +??? if (IS_ERR(glink->mbox_chan)) {
>> +??????? if (PTR_ERR(glink->mbox_chan) != -EPROBE_DEFER)
>> +??????????? dev_err(dev, "failed to acquire IPC channel\n");
>> +??????? return ERR_CAST(glink->mbox_chan);
>> +??? }
>> +
>> +??? irq = of_irq_get(dev->of_node, 0);
>> +??? ret = devm_request_irq(dev, irq,
>> +?????????????????? qcom_glink_native_intr,
>> +?????????????????? IRQF_NO_SUSPEND | IRQF_SHARED,
>> +?????????????????? "glink-native", glink);
>> +??? if (ret) {
>> +??????? dev_err(dev, "failed to request IRQ\n");
>> +??????? return ERR_PTR(ret);
>> +??? }
> 
> These IRQs are wake-up-capable, please use enable_irq_wale() also

 ok.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 10/18] rpmsg: glink: Add support for TX intents
  2017-08-22  9:12     ` Arun Kumar Neelakantam
@ 2017-08-22 12:35       ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-22 12:35 UTC (permalink / raw)
  To: Arun Kumar Neelakantam, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel

Hi,

<snip>

> 
> spinlock intent_lock initialization is missed ?

 right, should add that.

>>       kref_init(&channel->refcount);
>>         return channel;
>> @@ -187,6 +215,7 @@ static void qcom_glink_channel_release(struct kref *ref)
>>       struct glink_channel *channel = container_of(ref, struct glink_channel,
>>                                refcount);
>>   +    idr_destroy(&channel->liids);
> 
> idr_destroy shouldn`t be covered by intent_lock ?
> 

 hmm, will fix this.

>>       kfree(channel->name);
>>       kfree(channel);
>>   }
>> @@ -423,6 +452,130 @@ static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
>>       }
>>   }
>>   +/**
>> + * qcom_glink_send_intent_req_ack() - convert an rx intent request ack cmd to
>> +                      wire format and transmit
>> + * @glink:    The transport to transmit on.
>> + * @channel:    The glink channel
>> + * @granted:    The request response to encode.
>> + *
>> + * Return: 0 on success or standard Linux error code.
>> + */
>> +static int qcom_glink_send_intent_req_ack(struct qcom_glink *glink,
>> +                      struct glink_channel *channel,
>> +                      bool granted)
>> +{
>> +    struct glink_msg msg;
>> +
>> +    msg.cmd = cpu_to_le16(RPM_CMD_RX_INTENT_REQ_ACK);
>> +    msg.param1 = cpu_to_le16(channel->lcid);
>> +    msg.param2 = cpu_to_le32(granted);
>> +
>> +    qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
>> +
>> +    return 0;
>> +}
>> +
>> +/**
>> + * tx_cmd_local_rx_intent() - convert an rx intent cmd to wire format and
>> + *               transmit
> 
> copy-paste mistake

 ok.

>> + * @glink:    The transport to transmit on.
>> + * @channel:    The local channel
>> + * @size:    The intent to pass on to remote.
>> + *
>> + * Return: 0 on success or standard Linux error code.
>> + */
>> +static int qcom_glink_advertise_intent(struct qcom_glink *glink,
>> +                       struct glink_channel *channel,
>> +                       struct glink_core_rx_intent *intent)
>> +{
>> +    struct command {
>> +        u16 id;
>> +        u16 lcid;
>> +        u32 count;
>> +        u32 size;
>> +        u32 liid;
>> +    } __packed;
>> +    struct command cmd;
>> +
>> +    cmd.id = cpu_to_le16(RPM_CMD_INTENT);
>> +    cmd.lcid = cpu_to_le16(channel->lcid);
>> +    cmd.count = cpu_to_le32(1);
>> +    cmd.size = cpu_to_le32(intent->size);
>> +    cmd.liid = cpu_to_le32(intent->id);
>> +
>> +    qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
>> +
>> +    return 0;
>> +}
>> +
>> +static struct glink_core_rx_intent *
>> +qcom_glink_alloc_intent(struct qcom_glink *glink,
>> +            struct glink_channel *channel,
>> +            size_t size,
>> +            bool reuseable)
>> +{
>> +    struct glink_core_rx_intent *intent;
>> +    int ret;
>> +    unsigned long flags;
>> +
>> +    intent = kzalloc(sizeof(*intent), GFP_KERNEL);
>> +
>> +    if (!intent)
>> +        return NULL;
>> +
>> +    intent->data = kzalloc(size, GFP_KERNEL);
>> +    if (!intent->data)
>> +        return NULL;
>> +
>> +    spin_lock_irqsave(&channel->intent_lock, flags);
>> +    ret = idr_alloc_cyclic(&channel->liids, intent, 1, -1, GFP_ATOMIC);
>> +    if (ret < 0) {
>> +        spin_unlock_irqrestore(&channel->intent_lock, flags);
>> +        return NULL;
>> +    }
>> +    spin_unlock_irqrestore(&channel->intent_lock, flags);
>> +
>> +    intent->id = ret;
>> +    intent->size = size;
>> +    intent->reuse = reuseable;
>> +
>> +    return intent;
>> +}
>> +
>> +/**
>> + * glink_core_rx_cmd_remote_rx_intent_req() - Receive a request for rx_intent
>> + *                        from remote side
> 
> copy-paste mistake

 ok.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 10/18] rpmsg: glink: Add support for TX intents
@ 2017-08-22 12:35       ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-22 12:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

<snip>

> 
> spinlock intent_lock initialization is missed ?

 right, should add that.

>> ????? kref_init(&channel->refcount);
>> ? ????? return channel;
>> @@ -187,6 +215,7 @@ static void qcom_glink_channel_release(struct kref *ref)
>> ????? struct glink_channel *channel = container_of(ref, struct glink_channel,
>> ?????????????????????????????? refcount);
>> ? +??? idr_destroy(&channel->liids);
> 
> idr_destroy shouldn`t be covered by intent_lock ?
> 

 hmm, will fix this.

>> ????? kfree(channel->name);
>> ????? kfree(channel);
>> ? }
>> @@ -423,6 +452,130 @@ static void qcom_glink_receive_version_ack(struct qcom_glink *glink,
>> ????? }
>> ? }
>> ? +/**
>> + * qcom_glink_send_intent_req_ack() - convert an rx intent request ack cmd to
>> +????????????????????? wire format and transmit
>> + * @glink:??? The transport to transmit on.
>> + * @channel:??? The glink channel
>> + * @granted:??? The request response to encode.
>> + *
>> + * Return: 0 on success or standard Linux error code.
>> + */
>> +static int qcom_glink_send_intent_req_ack(struct qcom_glink *glink,
>> +????????????????????? struct glink_channel *channel,
>> +????????????????????? bool granted)
>> +{
>> +??? struct glink_msg msg;
>> +
>> +??? msg.cmd = cpu_to_le16(RPM_CMD_RX_INTENT_REQ_ACK);
>> +??? msg.param1 = cpu_to_le16(channel->lcid);
>> +??? msg.param2 = cpu_to_le32(granted);
>> +
>> +??? qcom_glink_tx(glink, &msg, sizeof(msg), NULL, 0, true);
>> +
>> +??? return 0;
>> +}
>> +
>> +/**
>> + * tx_cmd_local_rx_intent() - convert an rx intent cmd to wire format and
>> + *?????????????? transmit
> 
> copy-paste mistake

 ok.

>> + * @glink:??? The transport to transmit on.
>> + * @channel:??? The local channel
>> + * @size:??? The intent to pass on to remote.
>> + *
>> + * Return: 0 on success or standard Linux error code.
>> + */
>> +static int qcom_glink_advertise_intent(struct qcom_glink *glink,
>> +?????????????????????? struct glink_channel *channel,
>> +?????????????????????? struct glink_core_rx_intent *intent)
>> +{
>> +??? struct command {
>> +??????? u16 id;
>> +??????? u16 lcid;
>> +??????? u32 count;
>> +??????? u32 size;
>> +??????? u32 liid;
>> +??? } __packed;
>> +??? struct command cmd;
>> +
>> +??? cmd.id = cpu_to_le16(RPM_CMD_INTENT);
>> +??? cmd.lcid = cpu_to_le16(channel->lcid);
>> +??? cmd.count = cpu_to_le32(1);
>> +??? cmd.size = cpu_to_le32(intent->size);
>> +??? cmd.liid = cpu_to_le32(intent->id);
>> +
>> +??? qcom_glink_tx(glink, &cmd, sizeof(cmd), NULL, 0, true);
>> +
>> +??? return 0;
>> +}
>> +
>> +static struct glink_core_rx_intent *
>> +qcom_glink_alloc_intent(struct qcom_glink *glink,
>> +??????????? struct glink_channel *channel,
>> +??????????? size_t size,
>> +??????????? bool reuseable)
>> +{
>> +??? struct glink_core_rx_intent *intent;
>> +??? int ret;
>> +??? unsigned long flags;
>> +
>> +??? intent = kzalloc(sizeof(*intent), GFP_KERNEL);
>> +
>> +??? if (!intent)
>> +??????? return NULL;
>> +
>> +??? intent->data = kzalloc(size, GFP_KERNEL);
>> +??? if (!intent->data)
>> +??????? return NULL;
>> +
>> +??? spin_lock_irqsave(&channel->intent_lock, flags);
>> +??? ret = idr_alloc_cyclic(&channel->liids, intent, 1, -1, GFP_ATOMIC);
>> +??? if (ret < 0) {
>> +??????? spin_unlock_irqrestore(&channel->intent_lock, flags);
>> +??????? return NULL;
>> +??? }
>> +??? spin_unlock_irqrestore(&channel->intent_lock, flags);
>> +
>> +??? intent->id = ret;
>> +??? intent->size = size;
>> +??? intent->reuse = reuseable;
>> +
>> +??? return intent;
>> +}
>> +
>> +/**
>> + * glink_core_rx_cmd_remote_rx_intent_req() - Receive a request for rx_intent
>> + *??????????????????????? from remote side
> 
> copy-paste mistake

 ok.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 11/18] rpmsg: glink: Use the local intents when receiving data
  2017-08-22  9:26     ` Arun Kumar Neelakantam
@ 2017-08-22 12:39       ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-22 12:39 UTC (permalink / raw)
  To: Arun Kumar Neelakantam, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel

Hi,

<snip..>

>>   -    /* Might have an ongoing, fragmented, message to append */
>> -    if (!channel->buf) {
>> -        channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
>> -        if (!channel->buf)
>> -            return -ENOMEM;
>> +    if (glink->intentless) {
>> +        /* Might have an ongoing, fragmented, message to append */
>> +        if (!channel->buf) {
>> +            intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
>> +            if (!intent)
>> +                return -ENOMEM;
>> +
>> +            intent->data = kmalloc(chunk_size + left_size,
>> +                           GFP_ATOMIC);
> 
> Who is supposed to free the intent and intent->data memory ?
 Well, that's done as a part of the rx_done_work.

Regards,
 Sricharan
 
-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 11/18] rpmsg: glink: Use the local intents when receiving data
@ 2017-08-22 12:39       ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-22 12:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

<snip..>

>> ? -??? /* Might have an ongoing, fragmented, message to append */
>> -??? if (!channel->buf) {
>> -??????? channel->buf = kmalloc(chunk_size + left_size, GFP_ATOMIC);
>> -??????? if (!channel->buf)
>> -??????????? return -ENOMEM;
>> +??? if (glink->intentless) {
>> +??????? /* Might have an ongoing, fragmented, message to append */
>> +??????? if (!channel->buf) {
>> +??????????? intent = kzalloc(sizeof(*intent), GFP_ATOMIC);
>> +??????????? if (!intent)
>> +??????????????? return -ENOMEM;
>> +
>> +??????????? intent->data = kmalloc(chunk_size + left_size,
>> +?????????????????????????? GFP_ATOMIC);
> 
> Who is supposed to free the intent and intent->data memory ?
 Well, that's done as a part of the rx_done_work.

Regards,
 Sricharan
 
-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 13/18] rpmsg: glink: Add rx done command
  2017-08-22 10:25     ` Arun Kumar Neelakantam
@ 2017-08-22 14:16       ` Sricharan R
  -1 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-22 14:16 UTC (permalink / raw)
  To: Arun Kumar Neelakantam, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel

Hi,
>> +    /* 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);
> 
> Adding one more parallel path will hit performance, if this worker could not get CPU cycles
> or blocked by other RT or HIGH_PRIO worker on global worker pool.
 The idea is, by design to have parallel non-blocking paths for rx and tx (that is done as a
 part of rx by sending the rx_done command), otherwise trying to send the rx_done
 command in the rx isr context is a problem since the tx can wait for the FIFO space and
 in worst case, can even lead to a potential deadlock if both the local and remote try
 the same. Having said that, instead of queuing this work in to the global queue, this
 can be put in to a local glink edge owned queue (or) a threaded isr ?, downstream does the
 rx_done in a client specific worker.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 13/18] rpmsg: glink: Add rx done command
@ 2017-08-22 14:16       ` Sricharan R
  0 siblings, 0 replies; 58+ messages in thread
From: Sricharan R @ 2017-08-22 14:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,
>> +??? /* 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);
> 
> Adding one more parallel path will hit performance, if this worker could not get CPU cycles
> or blocked by other RT or HIGH_PRIO worker on global worker pool.
 The idea is, by design to have parallel non-blocking paths for rx and tx (that is done as a
 part of rx by sending the rx_done command), otherwise trying to send the rx_done
 command in the rx isr context is a problem since the tx can wait for the FIFO space and
 in worst case, can even lead to a potential deadlock if both the local and remote try
 the same. Having said that, instead of queuing this work in to the global queue, this
 can be put in to a local glink edge owned queue (or) a threaded isr ?, downstream does the
 rx_done in a client specific worker.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH 13/18] rpmsg: glink: Add rx done command
  2017-08-22 14:16       ` Sricharan R
@ 2017-08-23  4:44         ` Arun Kumar Neelakantam
  -1 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-23  4:44 UTC (permalink / raw)
  To: Sricharan R, ohad, bjorn.andersson, linux-remoteproc,
	linux-kernel, linux-arm-msm, linux-arm-kernel



On 8/22/2017 7:46 PM, Sricharan R wrote:
> Hi,
>>> +    /* 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);
>> Adding one more parallel path will hit performance, if this worker could not get CPU cycles
>> or blocked by other RT or HIGH_PRIO worker on global worker pool.
>   The idea is, by design to have parallel non-blocking paths for rx and tx (that is done as a
>   part of rx by sending the rx_done command), otherwise trying to send the rx_done
>   command in the rx isr context is a problem since the tx can wait for the FIFO space and
>   in worst case, can even lead to a potential deadlock if both the local and remote try
>   the same. Having said that, instead of queuing this work in to the global queue, this
>   can be put in to a local glink edge owned queue (or) a threaded isr ?, downstream does the
>   rx_done in a client specific worker.

Yes, mixing RX and TX path will cause dead lock. I am okay to use 
specific queue with HIGH_PRIO or a threaded isr.
down stream uses both client specific worker and client RX cb [this mix 
the TX and RX path] which want to avoid.
>
> Regards,
>   Sricharan
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH 13/18] rpmsg: glink: Add rx done command
@ 2017-08-23  4:44         ` Arun Kumar Neelakantam
  0 siblings, 0 replies; 58+ messages in thread
From: Arun Kumar Neelakantam @ 2017-08-23  4:44 UTC (permalink / raw)
  To: linux-arm-kernel



On 8/22/2017 7:46 PM, Sricharan R wrote:
> Hi,
>>> +??? /* 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);
>> Adding one more parallel path will hit performance, if this worker could not get CPU cycles
>> or blocked by other RT or HIGH_PRIO worker on global worker pool.
>   The idea is, by design to have parallel non-blocking paths for rx and tx (that is done as a
>   part of rx by sending the rx_done command), otherwise trying to send the rx_done
>   command in the rx isr context is a problem since the tx can wait for the FIFO space and
>   in worst case, can even lead to a potential deadlock if both the local and remote try
>   the same. Having said that, instead of queuing this work in to the global queue, this
>   can be put in to a local glink edge owned queue (or) a threaded isr ?, downstream does the
>   rx_done in a client specific worker.

Yes, mixing RX and TX path will cause dead lock. I am okay to use 
specific queue with HIGH_PRIO or a threaded isr.
down stream uses both client specific worker and client RX cb [this mix 
the TX and RX path] which want to avoid.
>
> Regards,
>   Sricharan
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2017-08-23  4:44 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-16 17:18 [PATCH 00/18] rpmsg: glink: Add glink smem based transport Sricharan R
2017-08-16 17:18 ` Sricharan R
2017-08-16 17:18 ` [PATCH 01/18] rpmsg: glink: Rename glink_rpm_xx functions to qcom_glink_xx Sricharan R
2017-08-16 17:18   ` Sricharan R
2017-08-16 17:18 ` [PATCH 02/18] rpmsg: glink: Associate indirections for pipe fifo accessor's Sricharan R
2017-08-16 17:18   ` Sricharan R
2017-08-16 17:18 ` [PATCH 03/18] rpmsg: glink: Split rpm_probe to reuse the common code Sricharan R
2017-08-16 17:18   ` Sricharan R
2017-08-16 17:18 ` [PATCH 04/18] rpmsg: glink: Move the common glink protocol implementation to glink_native.c Sricharan R
2017-08-16 17:18   ` Sricharan R
2017-08-22  5:58   ` Arun Kumar Neelakantam
2017-08-22  5:58     ` Arun Kumar Neelakantam
2017-08-22 12:27     ` Sricharan R
2017-08-22 12:27       ` Sricharan R
2017-08-16 17:18 ` [PATCH 05/18] rpmsg: glink: Allow unaligned data access Sricharan R
2017-08-16 17:18   ` Sricharan R
2017-08-16 17:18 ` [PATCH 06/18] rpmsg: glink: Introduce glink smem based transport Sricharan R
2017-08-16 17:18   ` Sricharan R
2017-08-16 17:19 ` [PATCH 07/18] rpmsg: glink: Fix default case while handling received commands Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-16 17:19 ` [PATCH 08/18] rpmsg: glink: Add support for transport version negotiation Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-16 17:19 ` [PATCH 09/18] rpmsg: glink: Fix idr_lock from mutex to spinlock Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-16 17:19 ` [PATCH 10/18] rpmsg: glink: Add support for TX intents Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-22  9:12   ` Arun Kumar Neelakantam
2017-08-22  9:12     ` Arun Kumar Neelakantam
2017-08-22 12:35     ` Sricharan R
2017-08-22 12:35       ` Sricharan R
2017-08-16 17:19 ` [PATCH 11/18] rpmsg: glink: Use the local intents when receiving data Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-22  9:26   ` Arun Kumar Neelakantam
2017-08-22  9:26     ` Arun Kumar Neelakantam
2017-08-22 12:39     ` Sricharan R
2017-08-22 12:39       ` Sricharan R
2017-08-16 17:19 ` [PATCH 12/18] rpmsg: glink: Make RX FIFO peak accessor to take an offset Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-16 17:19 ` [PATCH 13/18] rpmsg: glink: Add rx done command Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-22 10:25   ` Arun Kumar Neelakantam
2017-08-22 10:25     ` Arun Kumar Neelakantam
2017-08-22 14:16     ` Sricharan R
2017-08-22 14:16       ` Sricharan R
2017-08-23  4:44       ` Arun Kumar Neelakantam
2017-08-23  4:44         ` Arun Kumar Neelakantam
2017-08-16 17:19 ` [PATCH 14/18] rpmsg: glink: Add announce_create ops and preallocate intents Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-16 17:19 ` [PATCH 15/18] rpmsg: glink: Receive and store the remote intent buffers Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-22 10:41   ` Arun Kumar Neelakantam
2017-08-22 10:41     ` Arun Kumar Neelakantam
2017-08-16 17:19 ` [PATCH 16/18] rpmsg: glink: Use the intents passed by remote Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-16 17:19 ` [PATCH 17/18] rpmsg: glink: Request for intents when unavailable Sricharan R
2017-08-16 17:19   ` Sricharan R
2017-08-16 17:19 ` [PATCH 18/18] rpmsg: glink: Handle remote rx done command Sricharan R
2017-08-16 17:19   ` Sricharan R

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.