提交 1d2ea36e 编写于 作者: S Sricharan R 提交者: Bjorn Andersson

rpmsg: glink: Add rx done command

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.
Acked-by: NArun Kumar Neelakantam <aneela@codeaurora.org>
Signed-off-by: NSricharan R <sricharan@codeaurora.org>
Signed-off-by: NBjorn Andersson <bjorn.andersson@linaro.org>
上级 b88eee97
...@@ -77,6 +77,8 @@ struct glink_core_rx_intent { ...@@ -77,6 +77,8 @@ struct glink_core_rx_intent {
bool reuse; bool reuse;
bool in_use; bool in_use;
u32 offset; u32 offset;
struct list_head node;
}; };
/** /**
...@@ -139,6 +141,8 @@ enum { ...@@ -139,6 +141,8 @@ enum {
* @rcid: channel id, in remote space * @rcid: channel id, in remote space
* @intent_lock: lock for protection of @liids * @intent_lock: lock for protection of @liids
* @liids: idr of all local intents * @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: receive buffer, for gathering fragments
* @buf_offset: write offset in @buf * @buf_offset: write offset in @buf
* @buf_size: size of current @buf * @buf_size: size of current @buf
...@@ -161,6 +165,8 @@ struct glink_channel { ...@@ -161,6 +165,8 @@ struct glink_channel {
spinlock_t intent_lock; spinlock_t intent_lock;
struct idr liids; struct idr liids;
struct work_struct intent_work;
struct list_head done_intents;
struct glink_core_rx_intent *buf; struct glink_core_rx_intent *buf;
int buf_offset; int buf_offset;
...@@ -180,15 +186,19 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops; ...@@ -180,15 +186,19 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops;
#define RPM_CMD_CLOSE 3 #define RPM_CMD_CLOSE 3
#define RPM_CMD_OPEN_ACK 4 #define RPM_CMD_OPEN_ACK 4
#define RPM_CMD_INTENT 5 #define RPM_CMD_INTENT 5
#define RPM_CMD_RX_DONE 6
#define RPM_CMD_RX_INTENT_REQ 7 #define RPM_CMD_RX_INTENT_REQ 7
#define RPM_CMD_RX_INTENT_REQ_ACK 8 #define RPM_CMD_RX_INTENT_REQ_ACK 8
#define RPM_CMD_TX_DATA 9 #define RPM_CMD_TX_DATA 9
#define RPM_CMD_CLOSE_ACK 11 #define RPM_CMD_CLOSE_ACK 11
#define RPM_CMD_TX_DATA_CONT 12 #define RPM_CMD_TX_DATA_CONT 12
#define RPM_CMD_READ_NOTIF 13 #define RPM_CMD_READ_NOTIF 13
#define RPM_CMD_RX_DONE_W_REUSE 14
#define GLINK_FEATURE_INTENTLESS BIT(1) #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, static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
const char *name) const char *name)
{ {
...@@ -201,12 +211,16 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink, ...@@ -201,12 +211,16 @@ static struct glink_channel *qcom_glink_alloc_channel(struct qcom_glink *glink,
/* Setup glink internal glink_channel data */ /* Setup glink internal glink_channel data */
spin_lock_init(&channel->recv_lock); spin_lock_init(&channel->recv_lock);
spin_lock_init(&channel->intent_lock); spin_lock_init(&channel->intent_lock);
channel->glink = glink; channel->glink = glink;
channel->name = kstrdup(name, GFP_KERNEL); channel->name = kstrdup(name, GFP_KERNEL);
init_completion(&channel->open_req); init_completion(&channel->open_req);
init_completion(&channel->open_ack); 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); idr_init(&channel->liids);
kref_init(&channel->refcount); kref_init(&channel->refcount);
...@@ -402,6 +416,70 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink, ...@@ -402,6 +416,70 @@ static void qcom_glink_send_close_ack(struct qcom_glink *glink,
qcom_glink_tx(glink, &req, sizeof(req), NULL, 0, true); 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 * qcom_glink_receive_version() - receive version/features from remote system
* *
...@@ -718,6 +796,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail) ...@@ -718,6 +796,8 @@ static int qcom_glink_rx_data(struct qcom_glink *glink, size_t avail)
intent->offset = 0; intent->offset = 0;
channel->buf = NULL; channel->buf = NULL;
qcom_glink_rx_done(glink, channel, intent);
} }
advance_rx: advance_rx:
...@@ -1106,6 +1186,9 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid) ...@@ -1106,6 +1186,9 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid)
if (WARN(!channel, "close request on unknown channel\n")) if (WARN(!channel, "close request on unknown channel\n"))
return; return;
/* cancel pending rx_done work */
cancel_work_sync(&channel->intent_work);
if (channel->rpdev) { if (channel->rpdev) {
strncpy(chinfo.name, channel->name, sizeof(chinfo.name)); strncpy(chinfo.name, channel->name, sizeof(chinfo.name));
chinfo.src = RPMSG_ADDR_ANY; chinfo.src = RPMSG_ADDR_ANY;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册