msm: ipc: Add support to handle version 2 header
IPC Router Message header is 32 bytes in size since each element uses
4 bytes in size regardless of the data range being represented.
Add a version 2 header format that compacts the header into 16 bytes.
Change-Id: I5e6cfc0672ca1dc3365b31c26d2ce4b3c6230cfc
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 7263832..3249398 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -298,6 +298,8 @@
pr_err("%s: failure\n", __func__);
return NULL;
}
+ memcpy(&(cloned_pkt->hdr), &(pkt->hdr), sizeof(struct rr_header_v1));
+ /* TODO: Copy optional headers, if available */
pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
if (!pkt_fragment_q) {
@@ -323,6 +325,7 @@
kfree_skb(temp_skb);
}
kfree(pkt_fragment_q);
+ /* TODO: Free optional headers, if present */
kfree(cloned_pkt);
return NULL;
}
@@ -361,6 +364,7 @@
kfree_skb(temp_skb);
}
kfree(pkt->pkt_fragment_q);
+ /* TODO: Free Optional headers, if present */
kfree(pkt);
return;
}
@@ -373,6 +377,8 @@
int first = 1, offset = 0;
int skb_size, data_size;
void *data;
+ int last = 1;
+ int align_size;
skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
if (!skb_head) {
@@ -382,10 +388,13 @@
skb_queue_head_init(skb_head);
data_size = buf_len;
+ align_size = ALIGN_SIZE(data_size);
while (offset != buf_len) {
skb_size = data_size;
if (first)
skb_size += IPC_ROUTER_HDR_SIZE;
+ if (last)
+ skb_size += align_size;
skb = alloc_skb(skb_size, GFP_KERNEL);
if (!skb) {
@@ -394,6 +403,7 @@
goto buf_to_skb_error;
}
data_size = data_size / 2;
+ last = 0;
continue;
}
@@ -407,6 +417,7 @@
skb_queue_tail(skb_head, skb);
offset += data_size;
data_size = buf_len - offset;
+ last = 1;
}
return skb_head;
@@ -461,6 +472,328 @@
kfree(skb_head);
}
+/**
+ * extract_header_v1() - Extract IPC Router header of version 1
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v1(struct rr_packet *pkt, struct sk_buff *skb)
+{
+ if (!pkt || !skb) {
+ pr_err("%s: Invalid pkt or skb\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(&pkt->hdr, skb->data, sizeof(struct rr_header_v1));
+ skb_pull(skb, sizeof(struct rr_header_v1));
+ pkt->length -= sizeof(struct rr_header_v1);
+ return 0;
+}
+
+/**
+ * extract_header_v2() - Extract IPC Router header of version 2
+ * @pkt: Packet structure into which the header has to be extraced.
+ * @skb: SKB from which the header has to be extracted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int extract_header_v2(struct rr_packet *pkt, struct sk_buff *skb)
+{
+ struct rr_header_v2 *hdr;
+
+ if (!pkt || !skb) {
+ pr_err("%s: Invalid pkt or skb\n", __func__);
+ return -EINVAL;
+ }
+
+ hdr = (struct rr_header_v2 *)skb->data;
+ pkt->hdr.version = (uint32_t)hdr->version;
+ pkt->hdr.type = (uint32_t)hdr->type;
+ pkt->hdr.src_node_id = (uint32_t)hdr->src_node_id;
+ pkt->hdr.src_port_id = (uint32_t)hdr->src_port_id;
+ pkt->hdr.size = (uint32_t)hdr->size;
+ pkt->hdr.control_flag = (uint32_t)hdr->control_flag;
+ pkt->hdr.dst_node_id = (uint32_t)hdr->dst_node_id;
+ pkt->hdr.dst_port_id = (uint32_t)hdr->dst_port_id;
+ skb_pull(skb, sizeof(struct rr_header_v2));
+ pkt->length -= sizeof(struct rr_header_v2);
+ return 0;
+}
+
+/**
+ * extract_header() - Extract IPC Router header
+ * @pkt: Packet from which the header has to be extraced.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function will check if the header version is v1 or v2 and invoke
+ * the corresponding helper function to extract the IPC Router header.
+ */
+static int extract_header(struct rr_packet *pkt)
+{
+ struct sk_buff *temp_skb;
+ int ret;
+
+ if (!pkt) {
+ pr_err("%s: NULL PKT\n", __func__);
+ return -EINVAL;
+ }
+
+ temp_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!temp_skb || !temp_skb->data) {
+ pr_err("%s: No SKBs in skb_queue\n", __func__);
+ return -EINVAL;
+ }
+
+ if (temp_skb->data[0] == IPC_ROUTER_V1) {
+ ret = extract_header_v1(pkt, temp_skb);
+ } else if (temp_skb->data[0] == IPC_ROUTER_V2) {
+ ret = extract_header_v2(pkt, temp_skb);
+ /* TODO: Extract optional headers if present */
+ } else {
+ pr_err("%s: Invalid Header version %02x\n",
+ __func__, temp_skb->data[0]);
+ print_hex_dump(KERN_ERR, "Header: ", DUMP_PREFIX_ADDRESS,
+ 16, 1, temp_skb->data, pkt->length, true);
+ return -EINVAL;
+ }
+ return ret;
+}
+
+/**
+ * calc_tx_header_size() - Calculate header size to be reserved in SKB
+ * @pkt: Packet in which the space for header has to be reserved.
+ * @dst_xprt_info: XPRT through which the destination is reachable.
+ *
+ * @return: required header size on success,
+ * starndard Linux error codes on failure.
+ *
+ * This function is used to calculate the header size that has to be reserved
+ * in a transmit SKB. The header size is calculated based on the XPRT through
+ * which the destination node is reachable.
+ */
+static int calc_tx_header_size(struct rr_packet *pkt,
+ struct msm_ipc_router_xprt_info *dst_xprt_info)
+{
+ int hdr_size = 0;
+ int xprt_version = 0;
+ struct msm_ipc_routing_table_entry *rt_entry;
+ struct msm_ipc_router_xprt_info *xprt_info = dst_xprt_info;
+
+ if (!pkt) {
+ pr_err("%s: NULL PKT\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!xprt_info) {
+ rt_entry = lookup_routing_table(pkt->hdr.dst_node_id);
+ if (!rt_entry || !(rt_entry->xprt_info)) {
+ pr_err("%s: Node %d is not up\n",
+ __func__, pkt->hdr.dst_node_id);
+ return -ENODEV;
+ }
+
+ xprt_info = rt_entry->xprt_info;
+ }
+ if (xprt_info)
+ xprt_version = xprt_info->xprt->get_version(xprt_info->xprt);
+
+ if (xprt_version == IPC_ROUTER_V1) {
+ pkt->hdr.version = IPC_ROUTER_V1;
+ hdr_size = sizeof(struct rr_header_v1);
+ } else if (xprt_version == IPC_ROUTER_V2) {
+ pkt->hdr.version = IPC_ROUTER_V2;
+ hdr_size = sizeof(struct rr_header_v2);
+ /* TODO: Calculate optional header length, if present */
+ } else {
+ pr_err("%s: Invalid xprt_version %d\n",
+ __func__, xprt_version);
+ hdr_size = -EINVAL;
+ }
+
+ return hdr_size;
+}
+
+/**
+ * prepend_header_v1() - Prepend IPC Router header of version 1
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v1(struct rr_packet *pkt, int hdr_size)
+{
+ struct sk_buff *temp_skb;
+ struct rr_header_v1 *hdr;
+
+ if (!pkt || hdr_size <= 0) {
+ pr_err("%s: Invalid input parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ temp_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!temp_skb || !temp_skb->data) {
+ pr_err("%s: No SKBs in skb_queue\n", __func__);
+ return -EINVAL;
+ }
+
+ if (skb_headroom(temp_skb) < hdr_size) {
+ temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+ if (!temp_skb) {
+ pr_err("%s: Could not allocate SKB of size %d\n",
+ __func__, hdr_size);
+ return -ENOMEM;
+ }
+ }
+
+ hdr = (struct rr_header_v1 *)skb_push(temp_skb, hdr_size);
+ memcpy(hdr, &pkt->hdr, hdr_size);
+ if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+ skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+ pkt->length += hdr_size;
+ return 0;
+}
+
+/**
+ * prepend_header_v2() - Prepend IPC Router header of version 2
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @hdr_size: Size of the header
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int prepend_header_v2(struct rr_packet *pkt, int hdr_size)
+{
+ struct sk_buff *temp_skb;
+ struct rr_header_v2 *hdr;
+
+ if (!pkt || hdr_size <= 0) {
+ pr_err("%s: Invalid input parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ temp_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!temp_skb || !temp_skb->data) {
+ pr_err("%s: No SKBs in skb_queue\n", __func__);
+ return -EINVAL;
+ }
+
+ if (skb_headroom(temp_skb) < hdr_size) {
+ temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
+ if (!temp_skb) {
+ pr_err("%s: Could not allocate SKB of size %d\n",
+ __func__, hdr_size);
+ return -ENOMEM;
+ }
+ }
+
+ hdr = (struct rr_header_v2 *)skb_push(temp_skb, hdr_size);
+ hdr->version = (uint8_t)pkt->hdr.version;
+ hdr->type = (uint8_t)pkt->hdr.type;
+ hdr->control_flag = (uint16_t)pkt->hdr.control_flag;
+ hdr->size = (uint32_t)pkt->hdr.size;
+ hdr->src_node_id = (uint16_t)pkt->hdr.src_node_id;
+ hdr->src_port_id = (uint16_t)pkt->hdr.src_port_id;
+ hdr->dst_node_id = (uint16_t)pkt->hdr.dst_node_id;
+ hdr->dst_port_id = (uint16_t)pkt->hdr.dst_port_id;
+ /* TODO: Add optional headers, if present */
+ if (temp_skb != skb_peek(pkt->pkt_fragment_q))
+ skb_queue_head(pkt->pkt_fragment_q, temp_skb);
+ pkt->length += hdr_size;
+ return 0;
+}
+
+/**
+ * prepend_header() - Prepend IPC Router header
+ * @pkt: Packet structure which contains the header info to be prepended.
+ * @xprt_info: XPRT through which the packet is transmitted.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * This function prepends the header to the packet to be transmitted. The
+ * IPC Router header version to be prepended depends on the XPRT through
+ * which the destination is reachable.
+ */
+static int prepend_header(struct rr_packet *pkt,
+ struct msm_ipc_router_xprt_info *xprt_info)
+{
+ int hdr_size;
+ struct sk_buff *temp_skb;
+
+ if (!pkt) {
+ pr_err("%s: NULL PKT\n", __func__);
+ return -EINVAL;
+ }
+
+ temp_skb = skb_peek(pkt->pkt_fragment_q);
+ if (!temp_skb || !temp_skb->data) {
+ pr_err("%s: No SKBs in skb_queue\n", __func__);
+ return -EINVAL;
+ }
+
+ hdr_size = calc_tx_header_size(pkt, xprt_info);
+ if (hdr_size <= 0)
+ return hdr_size;
+
+ if (pkt->hdr.version == IPC_ROUTER_V1)
+ return prepend_header_v1(pkt, hdr_size);
+ else if (pkt->hdr.version == IPC_ROUTER_V2)
+ return prepend_header_v2(pkt, hdr_size);
+ else
+ return -EINVAL;
+}
+
+/**
+ * defragment_pkt() - Defragment and linearize the packet
+ * @pkt: Packet to be linearized.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ *
+ * Some packets contain fragments of data over multiple SKBs. If an XPRT
+ * does not supported fragmented writes, linearize multiple SKBs into one
+ * single SKB.
+ */
+static int defragment_pkt(struct rr_packet *pkt)
+{
+ struct sk_buff *dst_skb, *src_skb, *temp_skb;
+ int offset = 0, buf_len = 0, copy_len;
+ void *buf;
+ int align_size;
+
+ if (!pkt || pkt->length <= 0) {
+ pr_err("%s: Invalid PKT\n", __func__);
+ return -EINVAL;
+ }
+
+ if (skb_queue_len(pkt->pkt_fragment_q) == 1)
+ return 0;
+
+ align_size = ALIGN_SIZE(pkt->length);
+ dst_skb = alloc_skb(pkt->length + align_size, GFP_KERNEL);
+ if (!dst_skb) {
+ pr_err("%s: could not allocate one skb of size %d\n",
+ __func__, pkt->length);
+ return -ENOMEM;
+ }
+ buf = skb_put(dst_skb, pkt->length);
+ buf_len = pkt->length;
+
+ skb_queue_walk(pkt->pkt_fragment_q, src_skb) {
+ copy_len = buf_len < src_skb->len ? buf_len : src_skb->len;
+ memcpy(buf + offset, src_skb->data, copy_len);
+ offset += copy_len;
+ buf_len -= copy_len;
+ }
+
+ while (!skb_queue_empty(pkt->pkt_fragment_q)) {
+ temp_skb = skb_dequeue(pkt->pkt_fragment_q);
+ kfree_skb(temp_skb);
+ }
+ skb_queue_tail(pkt->pkt_fragment_q, dst_skb);
+ return 0;
+}
+
static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
struct rr_packet *pkt, int clone)
{
@@ -515,7 +848,7 @@
down_read(&local_ports_lock_lha2);
do {
next_port_id++;
- if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
+ if ((next_port_id & IPC_ROUTER_ADDRESS) == IPC_ROUTER_ADDRESS)
next_port_id = 1;
key = (next_port_id & (LP_HASH_SIZE - 1));
@@ -932,7 +1265,7 @@
{
struct rr_packet *pkt;
struct sk_buff *ipc_rtr_pkt;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
int pkt_size;
void *data;
struct sk_buff_head *pkt_fragment_q;
@@ -973,32 +1306,33 @@
skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
data = skb_put(ipc_rtr_pkt, sizeof(*msg));
memcpy(data, msg, sizeof(*msg));
- hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
- if (!hdr) {
- pr_err("%s: skb_push failed\n", __func__);
- kfree_skb(ipc_rtr_pkt);
- kfree(pkt_fragment_q);
- kfree(pkt);
- return -ENOMEM;
- }
+ skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
+ pkt->pkt_fragment_q = pkt_fragment_q;
+ pkt->length = sizeof(*msg);
- hdr->version = IPC_ROUTER_VERSION;
+ hdr = &(pkt->hdr);
+ hdr->version = IPC_ROUTER_V1;
hdr->type = msg->cmd;
hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
hdr->src_port_id = IPC_ROUTER_ADDRESS;
- hdr->confirm_rx = 0;
+ hdr->control_flag = 0;
hdr->size = sizeof(*msg);
if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
hdr->dst_node_id = dst_node_id;
else
hdr->dst_node_id = xprt_info->remote_node_id;
hdr->dst_port_id = IPC_ROUTER_ADDRESS;
- skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
- pkt->pkt_fragment_q = pkt_fragment_q;
- pkt->length = pkt_size;
mutex_lock(&xprt_info->tx_lock_lhb2);
- ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
+ ret = prepend_header(pkt, xprt_info);
+ if (ret < 0) {
+ mutex_unlock(&xprt_info->tx_lock_lhb2);
+ pr_err("%s: Prepend Header failed\n", __func__);
+ release_pkt(pkt);
+ return ret;
+ }
+
+ ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
mutex_unlock(&xprt_info->tx_lock_lhb2);
release_pkt(pkt);
@@ -1074,7 +1408,7 @@
{
struct rr_packet *pkt;
struct sk_buff *ipc_rtr_pkt;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
int pkt_size;
void *data;
struct sk_buff_head *pkt_fragment_q;
@@ -1094,7 +1428,7 @@
}
skb_queue_head_init(pkt_fragment_q);
- pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
+ pkt_size = sizeof(*msg);
ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
if (!ipc_rtr_pkt) {
pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
@@ -1103,22 +1437,14 @@
return -ENOMEM;
}
- skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
data = skb_put(ipc_rtr_pkt, sizeof(*msg));
memcpy(data, msg, sizeof(*msg));
- hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
- if (!hdr) {
- pr_err("%s: skb_push failed\n", __func__);
- kfree_skb(ipc_rtr_pkt);
- kfree(pkt_fragment_q);
- kfree(pkt);
- return -ENOMEM;
- }
- hdr->version = IPC_ROUTER_VERSION;
+ hdr = &(pkt->hdr);
+ hdr->version = IPC_ROUTER_V1;
hdr->type = msg->cmd;
hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
hdr->src_port_id = IPC_ROUTER_ADDRESS;
- hdr->confirm_rx = 0;
+ hdr->control_flag = 0;
hdr->size = sizeof(*msg);
hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
hdr->dst_port_id = IPC_ROUTER_ADDRESS;
@@ -1164,70 +1490,60 @@
return 0;
}
-static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
- struct rr_packet *pkt)
-{
- struct msm_ipc_router_xprt_info *fwd_xprt_info;
-
- if (!xprt_info || !pkt)
- return -EINVAL;
-
- down_read(&xprt_info_list_lock_lha5);
- list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
- mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
- if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
- fwd_xprt_info->xprt->write(pkt, pkt->length,
- fwd_xprt_info->xprt);
- mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
- }
- up_read(&xprt_info_list_lock_lha5);
- return 0;
-}
-
static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
struct rr_packet *pkt)
{
- uint32_t dst_node_id;
- struct sk_buff *head_pkt;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct msm_ipc_router_xprt_info *fwd_xprt_info;
struct msm_ipc_routing_table_entry *rt_entry;
int ret = 0;
+ int fwd_xprt_option;
if (!xprt_info || !pkt)
return -EINVAL;
- head_pkt = skb_peek(pkt->pkt_fragment_q);
- if (!head_pkt)
- return -EINVAL;
-
- hdr = (struct rr_header *)head_pkt->data;
- dst_node_id = hdr->dst_node_id;
+ hdr = &(pkt->hdr);
down_read(&routing_table_lock_lha3);
- rt_entry = lookup_routing_table(dst_node_id);
+ rt_entry = lookup_routing_table(hdr->dst_node_id);
if (!(rt_entry) || !(rt_entry->xprt_info)) {
- up_read(&routing_table_lock_lha3);
pr_err("%s: Routing table not initialized\n", __func__);
- return -ENODEV;
+ ret = -ENODEV;
+ goto fm_error1;
}
down_read(&rt_entry->lock_lha4);
fwd_xprt_info = rt_entry->xprt_info;
+ ret = prepend_header(pkt, fwd_xprt_info);
+ if (ret < 0) {
+ pr_err("%s: Prepend Header failed\n", __func__);
+ goto fm_error2;
+ }
+ fwd_xprt_option = fwd_xprt_info->xprt->get_option(fwd_xprt_info->xprt);
+ if (!(fwd_xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+ ret = defragment_pkt(pkt);
+ if (ret < 0)
+ goto fm_error2;
+ }
+
+ mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
pr_err("%s: Discarding Command to route back\n", __func__);
ret = -EINVAL;
- goto fwd_msg_out;
+ goto fm_error3;
}
if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
pr_err("%s: DST in the same cluster\n", __func__);
- goto fwd_msg_out;
+ ret = 0;
+ goto fm_error3;
}
- mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
+
+fm_error3:
mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
-fwd_msg_out:
+fm_error2:
up_read(&rt_entry->lock_lha4);
+fm_error1:
up_read(&routing_table_lock_lha3);
return ret;
@@ -1470,7 +1786,7 @@
}
static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
- struct rr_header *hdr)
+ struct rr_header_v1 *hdr)
{
int i, rc = 0;
union rr_control_msg ctl;
@@ -1508,7 +1824,7 @@
/* Send a reply HELLO message */
memset(&ctl, 0, sizeof(ctl));
- ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+ ctl.hello.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
IPC_ROUTER_DUMMY_DEST_NODE);
if (rc < 0) {
@@ -1654,7 +1970,7 @@
* to the cluster from which this message is received. Notify the
* local clients waiting for this service.
*/
- relay_msg(xprt_info, pkt);
+ relay_ctl_msg(xprt_info, msg);
post_control_ports(pkt);
return 0;
}
@@ -1677,7 +1993,7 @@
* belong to the cluster from which this message is received.
* Notify the local clients communicating with the service.
*/
- relay_msg(xprt_info, pkt);
+ relay_ctl_msg(xprt_info, msg);
post_control_ports(pkt);
}
up_write(&server_list_lock_lha2);
@@ -1697,7 +2013,7 @@
msm_ipc_router_destroy_remote_port(rport_ptr);
up_write(&routing_table_lock_lha3);
- relay_msg(xprt_info, pkt);
+ relay_ctl_msg(xprt_info, msg);
post_control_ports(pkt);
return 0;
}
@@ -1707,26 +2023,20 @@
{
union rr_control_msg *msg;
int rc = 0;
- struct sk_buff *temp_ptr;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
- if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
+ if (pkt->length != sizeof(*msg)) {
pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
- (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
+ sizeof(*msg));
return -EINVAL;
}
- temp_ptr = skb_peek(pkt->pkt_fragment_q);
- if (!temp_ptr) {
- pr_err("%s: pkt_fragment_q is empty\n", __func__);
- return -EINVAL;
+ hdr = &(pkt->hdr);
+ msg = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, sizeof(*msg));
+ if (!msg) {
+ pr_err("%s: Error extracting control msg\n", __func__);
+ return -ENOMEM;
}
- hdr = (struct rr_header *)temp_ptr->data;
- if (!hdr) {
- pr_err("%s: No data inside the skb\n", __func__);
- return -EINVAL;
- }
- msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
switch (msg->cmd) {
case IPC_ROUTER_CTRL_CMD_HELLO:
@@ -1752,17 +2062,17 @@
RR("o UNKNOWN(%08x)\n", msg->cmd);
rc = -ENOSYS;
}
-
+ kfree(msg);
return rc;
}
static void do_read_data(struct work_struct *work)
{
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct rr_packet *pkt = NULL;
struct msm_ipc_port *port_ptr;
- struct sk_buff *head_skb;
struct msm_ipc_router_remote_port *rport_ptr;
+ int ret;
struct msm_ipc_router_xprt_info *xprt_info =
container_of(work,
@@ -1777,24 +2087,15 @@
goto fail_data;
}
- head_skb = skb_peek(pkt->pkt_fragment_q);
- if (!head_skb) {
- pr_err("%s: head_skb is invalid\n", __func__);
+ ret = extract_header(pkt);
+ if (ret < 0)
goto fail_data;
- }
-
- hdr = (struct rr_header *)(head_skb->data);
+ hdr = &(pkt->hdr);
RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
hdr->version, hdr->type, hdr->src_node_id,
- hdr->src_port_id, hdr->confirm_rx, hdr->size,
+ hdr->src_port_id, hdr->control_flag, hdr->size,
hdr->dst_node_id, hdr->dst_port_id);
- if (hdr->version != IPC_ROUTER_VERSION) {
- pr_err("version %d != %d\n",
- hdr->version, IPC_ROUTER_VERSION);
- goto fail_data;
- }
-
if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
(hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
@@ -1803,8 +2104,7 @@
continue;
}
- if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
- (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
+ if (hdr->type != IPC_ROUTER_CTRL_CMD_DATA) {
process_control_msg(xprt_info, pkt);
release_pkt(pkt);
continue;
@@ -1819,7 +2119,7 @@
(hdr->src_port_id & 0xffffff),
(hdr->dst_node_id << 24) |
(hdr->dst_port_id & 0xffffff),
- (hdr->type << 24) | (hdr->confirm_rx << 16) |
+ (hdr->type << 24) | (hdr->control_flag << 16) |
(hdr->size & 0xffff));
}
#endif
@@ -1969,8 +2269,7 @@
uint32_t port_id,
struct sk_buff_head *data)
{
- struct sk_buff *head_skb;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct msm_ipc_port *port_ptr;
struct rr_packet *pkt;
int ret_len;
@@ -1985,28 +2284,15 @@
pr_err("%s: New pkt create failed\n", __func__);
return -ENOMEM;
}
-
- head_skb = skb_peek(pkt->pkt_fragment_q);
- if (!head_skb) {
- pr_err("%s: pkt_fragment_q is empty\n", __func__);
- release_pkt(pkt);
- return -EINVAL;
- }
- hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
- if (!hdr) {
- pr_err("%s: Prepend Header failed\n", __func__);
- release_pkt(pkt);
- return -ENOMEM;
- }
- hdr->version = IPC_ROUTER_VERSION;
+ hdr = &(pkt->hdr);
+ hdr->version = IPC_ROUTER_V1;
hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
hdr->src_node_id = src->this_port.node_id;
hdr->src_port_id = src->this_port.port_id;
hdr->size = pkt->length;
- hdr->confirm_rx = 0;
+ hdr->control_flag = 0;
hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
hdr->dst_port_id = port_id;
- pkt->length += IPC_ROUTER_HDR_SIZE;
down_read(&local_ports_lock_lha2);
port_ptr = msm_ipc_router_lookup_local_port(port_id);
@@ -2029,35 +2315,26 @@
struct msm_ipc_router_remote_port *rport_ptr,
struct rr_packet *pkt)
{
- struct sk_buff *head_skb;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct msm_ipc_router_xprt_info *xprt_info;
struct msm_ipc_routing_table_entry *rt_entry;
struct msm_ipc_resume_tx_port *resume_tx_port;
+ struct sk_buff *temp_skb;
+ int xprt_option;
int ret;
+ int align_size;
if (!rport_ptr || !src || !pkt)
return -EINVAL;
- head_skb = skb_peek(pkt->pkt_fragment_q);
- if (!head_skb) {
- pr_err("%s: pkt_fragment_q is empty\n", __func__);
- return -EINVAL;
- }
- hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
- if (!hdr) {
- pr_err("%s: Prepend Header failed\n", __func__);
- return -ENOMEM;
- }
- hdr->version = IPC_ROUTER_VERSION;
+ hdr = &(pkt->hdr);
hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
hdr->src_node_id = src->this_port.node_id;
hdr->src_port_id = src->this_port.port_id;
hdr->size = pkt->length;
- hdr->confirm_rx = 0;
+ hdr->control_flag = 0;
hdr->dst_node_id = rport_ptr->node_id;
hdr->dst_port_id = rport_ptr->port_id;
- pkt->length += IPC_ROUTER_HDR_SIZE;
mutex_lock(&rport_ptr->quota_lock_lhb2);
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
@@ -2085,7 +2362,7 @@
}
rport_ptr->tx_quota_cnt++;
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
- hdr->confirm_rx = 1;
+ hdr->control_flag |= CONTROL_FLAG_CONFIRM_RX;
mutex_unlock(&rport_ptr->quota_lock_lhb2);
rt_entry = lookup_routing_table(hdr->dst_node_id);
@@ -2096,6 +2373,25 @@
}
down_read(&rt_entry->lock_lha4);
xprt_info = rt_entry->xprt_info;
+ ret = prepend_header(pkt, xprt_info);
+ if (ret < 0) {
+ up_read(&rt_entry->lock_lha4);
+ pr_err("%s: Prepend Header failed\n", __func__);
+ return ret;
+ }
+ xprt_option = xprt_info->xprt->get_option(xprt_info->xprt);
+ if (!(xprt_option & FRAG_PKT_WRITE_ENABLE)) {
+ ret = defragment_pkt(pkt);
+ if (ret < 0) {
+ up_read(&rt_entry->lock_lha4);
+ return ret;
+ }
+ }
+
+ temp_skb = skb_peek_tail(pkt->pkt_fragment_q);
+ align_size = ALIGN_SIZE(pkt->length);
+ skb_put(temp_skb, align_size);
+ pkt->length += align_size;
mutex_lock(&xprt_info->tx_lock_lhb2);
ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
mutex_unlock(&xprt_info->tx_lock_lhb2);
@@ -2109,10 +2405,10 @@
RAW_HDR("[w rr_h] "
"ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
- "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+ "control_flag=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
hdr->version, type_to_str(hdr->type),
hdr->src_node_id, hdr->src_port_id,
- hdr->confirm_rx, hdr->size,
+ hdr->control_flag, hdr->size,
hdr->dst_node_id, hdr->dst_port_id);
#if defined(CONFIG_MSM_SMD_LOGGING)
@@ -2125,13 +2421,13 @@
(hdr->src_port_id & 0xffffff),
(hdr->dst_node_id << 24) |
(hdr->dst_port_id & 0xffffff),
- (hdr->type << 24) | (hdr->confirm_rx << 16) |
+ (hdr->type << 24) | (hdr->control_flag << 16) |
(hdr->size & 0xffff));
}
#endif
#endif
- return pkt->length;
+ return hdr->size;
}
int msm_ipc_router_send_to(struct msm_ipc_port *src,
@@ -2250,7 +2546,7 @@
static int msm_ipc_router_send_resume_tx(void *data)
{
union rr_control_msg msg;
- struct rr_header *hdr = (struct rr_header *)data;
+ struct rr_header_v1 *hdr = (struct rr_header_v1 *)data;
struct msm_ipc_routing_table_entry *rt_entry;
int ret;
@@ -2280,14 +2576,12 @@
}
int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
- struct sk_buff_head **data,
+ struct rr_packet **read_pkt,
size_t buf_len)
{
struct rr_packet *pkt;
- struct sk_buff *head_skb;
- int ret;
- if (!port_ptr || !data)
+ if (!port_ptr || !read_pkt)
return -EINVAL;
mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
@@ -2297,26 +2591,19 @@
}
pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
- if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
+ if ((buf_len) && (pkt->hdr.size > buf_len)) {
mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return -ETOOSMALL;
}
list_del(&pkt->list);
if (list_empty(&port_ptr->port_rx_q))
wake_unlock(&port_ptr->port_rx_wake_lock);
- *data = pkt->pkt_fragment_q;
- ret = pkt->length;
+ *read_pkt = pkt;
mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
- kfree(pkt);
- head_skb = skb_peek(*data);
- if (!head_skb) {
- pr_err("%s: Socket Buffer not found", __func__);
- return -EFAULT;
- }
- if (((struct rr_header *)(head_skb->data))->confirm_rx)
- msm_ipc_router_send_resume_tx((void *)(head_skb->data));
+ if (pkt->hdr.control_flag & CONTROL_FLAG_CONFIRM_RX)
+ msm_ipc_router_send_resume_tx(&pkt->hdr);
- return ret;
+ return pkt->length;
}
/**
@@ -2364,7 +2651,7 @@
/**
* msm_ipc_router_recv_from() - Recieve messages destined to a local port.
* @port_ptr: Pointer to the local port
- * @data : Pointer to the socket buffer head
+ * @pkt : Pointer to the router-to-router packet
* @src: Pointer to local port address
* @timeout: < 0 timeout indicates infinite wait till a message arrives.
* > 0 timeout indicates the wait time.
@@ -2385,31 +2672,30 @@
* of bytes that are read.
*/
int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
- struct sk_buff_head **data,
+ struct rr_packet **pkt,
struct msm_ipc_addr *src,
long timeout)
{
int ret, data_len, align_size;
struct sk_buff *temp_skb;
- struct rr_header *hdr = NULL;
+ struct rr_header_v1 *hdr = NULL;
- if (!port_ptr || !data) {
+ if (!port_ptr || !pkt) {
pr_err("%s: Invalid pointers being passed\n", __func__);
return -EINVAL;
}
- *data = NULL;
+ *pkt = NULL;
ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
if (ret)
return ret;
- ret = msm_ipc_router_read(port_ptr, data, 0);
- if (ret <= 0 || !(*data))
+ ret = msm_ipc_router_read(port_ptr, pkt, 0);
+ if (ret <= 0 || !(*pkt))
return ret;
- temp_skb = skb_peek(*data);
- hdr = (struct rr_header *)(temp_skb->data);
+ hdr = &((*pkt)->hdr);
if (src) {
src->addrtype = MSM_IPC_ADDR_ID;
src->addr.port_addr.node_id = hdr->src_node_id;
@@ -2417,10 +2703,9 @@
}
data_len = hdr->size;
- skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
align_size = ALIGN_SIZE(data_len);
if (align_size) {
- temp_skb = skb_peek_tail(*data);
+ temp_skb = skb_peek_tail((*pkt)->pkt_fragment_q);
skb_trim(temp_skb, (temp_skb->len - align_size));
}
return data_len;
@@ -2431,11 +2716,10 @@
unsigned char **data,
unsigned int *len)
{
- struct sk_buff_head *in_skb_head;
+ struct rr_packet *pkt;
int ret;
- ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, 0);
-
+ ret = msm_ipc_router_recv_from(port_ptr, &pkt, src, 0);
if (ret < 0) {
if (ret != -ENOMSG)
pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
@@ -2443,12 +2727,12 @@
return ret;
}
- *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
+ *data = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, ret);
if (!(*data))
pr_err("%s: Buf conversion failed\n", __func__);
*len = ret;
- msm_ipc_router_free_skb(in_skb_head);
+ release_pkt(pkt);
return 0;
}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 7bfc52b..a788295 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -24,12 +24,17 @@
#include <net/sock.h>
/* definitions for the R2R wire protcol */
-#define IPC_ROUTER_VERSION 1
+#define IPC_ROUTER_V1 1
+/*
+ * Ambiguous definition but will enable multiplexing IPC_ROUTER_V2 packets
+ * with an existing alternate transport in user-space, if needed.
+ */
+#define IPC_ROUTER_V2 3
-#define IPC_ROUTER_CLIENT_BCAST_ID 0xffffffff
-#define IPC_ROUTER_ADDRESS 0xfffffffe
+#define IPC_ROUTER_ADDRESS 0x0000FFFF
#define IPC_ROUTER_NID_LOCAL 1
+#define MAX_IPC_PKT_SIZE 66000
#define IPC_ROUTER_CTRL_CMD_DATA 1
#define IPC_ROUTER_CTRL_CMD_HELLO 2
@@ -55,6 +60,11 @@
#define ALL_SERVICE 0xFFFFFFFF
#define ALL_INSTANCE 0xFFFFFFFF
+#define CONTROL_FLAG_CONFIRM_RX 0x1
+#define CONTROL_FLAG_OPT_HDR 0x2
+
+#define FRAG_PKT_WRITE_ENABLE 0x1
+
enum {
CLIENT_PORT,
SERVER_PORT,
@@ -68,10 +78,22 @@
MULTI_LINK_MODE,
};
+/**
+ * rr_control_msg - Control message structure
+ * @cmd: Command identifier for HELLO message in Version 1.
+ * @hello: Message structure for HELLO message in Version 2.
+ * @srv: Message structure for NEW_SERVER/REMOVE_SERVER events.
+ * @cli: Message structure for REMOVE_CLIENT event.
+ */
union rr_control_msg {
uint32_t cmd;
struct {
uint32_t cmd;
+ uint32_t magic;
+ uint32_t capability;
+ } hello;
+ struct {
+ uint32_t cmd;
uint32_t service;
uint32_t instance;
uint32_t node_id;
@@ -84,22 +106,67 @@
} cli;
};
-struct rr_header {
+/**
+ * rr_header_v1 - IPC Router header version 1
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @control_flag: Flag to indicate flow control.
+ * @size: Size of the IPC Router payload.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v1 {
uint32_t version;
uint32_t type;
uint32_t src_node_id;
uint32_t src_port_id;
- uint32_t confirm_rx;
+ uint32_t control_flag;
uint32_t size;
uint32_t dst_node_id;
uint32_t dst_port_id;
};
-#define IPC_ROUTER_HDR_SIZE sizeof(struct rr_header)
-#define MAX_IPC_PKT_SIZE 66000
+/**
+ * rr_header_v2 - IPC Router header version 2
+ * @version: Version information.
+ * @type: IPC Router Message Type.
+ * @control_flag: Flags to indicate flow control, optional header etc.
+ * @size: Size of the IPC Router payload.
+ * @src_node_id: Source Node ID of the message.
+ * @src_port_id: Source Port ID of the message.
+ * @dst_node_id: Destination Node ID of the message.
+ * @dst_port_id: Destination Port ID of the message.
+ */
+struct rr_header_v2 {
+ uint8_t version;
+ uint8_t type;
+ uint16_t control_flag;
+ uint32_t size;
+ uint16_t src_node_id;
+ uint16_t src_port_id;
+ uint16_t dst_node_id;
+ uint16_t dst_port_id;
+} __attribute__((__packed__));
+union rr_header {
+ struct rr_header_v1 hdr_v1;
+ struct rr_header_v2 hdr_v2;
+};
+
+#define IPC_ROUTER_HDR_SIZE sizeof(union rr_header)
+
+/**
+ * rr_packet - Router to Router packet structure
+ * @list: Pointer to prev & next packets in a port's rx list.
+ * @hdr: Header information extracted from or prepended to a packet.
+ * @pkt_fragment_q: Queue of SKBs containing payload.
+ * @length: Length of data in the chain of SKBs
+ */
struct rr_packet {
struct list_head list;
+ struct rr_header_v1 hdr;
struct sk_buff_head *pkt_fragment_q;
uint32_t length;
};
@@ -110,11 +177,28 @@
void *default_pil;
};
+/**
+ * msm_ipc_router_xprt - Structure to hold XPRT specific information
+ * @name: Name of the XPRT.
+ * @link_id: Network cluster ID to which the XPRT belongs to.
+ * @priv: XPRT's private data.
+ * @get_version: Method to get header version supported by the XPRT.
+ * @get_option: Method to get XPRT specific options.
+ * @read_avail: Method to get data size available to be read from the XPRT.
+ * @read: Method to read data from the XPRT.
+ * @write_avail: Method to get write space available in the XPRT.
+ * @write: Method to write data to the XPRT.
+ * @close: Method to close the XPRT.
+ * @sft_close_done: Method to indicate to the XPRT that handling of reset
+ * event is complete.
+ */
struct msm_ipc_router_xprt {
char *name;
uint32_t link_id;
void *priv;
+ int (*get_version)(struct msm_ipc_router_xprt *xprt);
+ int (*get_option)(struct msm_ipc_router_xprt *xprt);
int (*read_avail)(struct msm_ipc_router_xprt *xprt);
int (*read)(void *data, uint32_t len,
struct msm_ipc_router_xprt *xprt);
@@ -141,12 +225,12 @@
struct sk_buff_head *data,
struct msm_ipc_addr *dest);
int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
- struct sk_buff_head **data,
+ struct rr_packet **pkt,
size_t buf_len);
int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
- struct sk_buff_head **data,
+ struct rr_packet **pkt,
struct msm_ipc_addr *src_addr,
long timeout);
int msm_ipc_router_register_server(struct msm_ipc_port *server_port,
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 38a838d..9c7ae90 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -55,6 +55,8 @@
int ss_reset;
void *pil;
struct completion sft_close_complete;
+ unsigned xprt_version;
+ unsigned xprt_option;
};
struct msm_ipc_router_smd_xprt_work {
@@ -71,13 +73,14 @@
char xprt_name[XPRT_NAME_LEN];
uint32_t edge;
uint32_t link_id;
+ unsigned xprt_version;
};
struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
- {"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
- {"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
- {"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1},
- {"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1},
+ {"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1, 1},
+ {"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1, 1},
+ {"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1, 1},
+ {"IPCRTR", "ipc_rtr_wcnss_ipcrtr", SMD_APPS_WCNSS, 1, 1},
};
static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
@@ -95,6 +98,28 @@
return -ENODEV;
}
+static int msm_ipc_router_smd_get_xprt_version(
+ struct msm_ipc_router_xprt *xprt)
+{
+ struct msm_ipc_router_smd_xprt *smd_xprtp;
+ if (!xprt)
+ return -EINVAL;
+ smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+ return (int)smd_xprtp->xprt_version;
+}
+
+static int msm_ipc_router_smd_get_xprt_option(
+ struct msm_ipc_router_xprt *xprt)
+{
+ struct msm_ipc_router_smd_xprt *smd_xprtp;
+ if (!xprt)
+ return -EINVAL;
+ smd_xprtp = container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
+
+ return (int)smd_xprtp->xprt_option;
+}
+
static int msm_ipc_router_smd_remote_write_avail(
struct msm_ipc_router_xprt *xprt)
{
@@ -110,7 +135,6 @@
{
struct rr_packet *pkt = (struct rr_packet *)data;
struct sk_buff *ipc_rtr_pkt;
- int align_sz, align_data = 0;
int offset, sz_written = 0;
int ret, num_retries = 0;
unsigned long flags;
@@ -123,9 +147,7 @@
if (!len || pkt->length != len)
return -EINVAL;
- align_sz = ALIGN_SIZE(pkt->length);
- while ((ret = smd_write_start(smd_xprtp->channel,
- (len + align_sz))) < 0) {
+ while ((ret = smd_write_start(smd_xprtp->channel, len)) < 0) {
spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
if (smd_xprtp->ss_reset) {
spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
@@ -143,7 +165,7 @@
num_retries++;
}
- D("%s: Ready to write\n", __func__);
+ D("%s: Ready to write %d bytes\n", __func__, len);
skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
offset = 0;
while (offset < ipc_rtr_pkt->len) {
@@ -175,30 +197,6 @@
__func__, offset, xprt->name);
}
- if (align_sz) {
- if (smd_write_avail(smd_xprtp->channel) < align_sz)
- smd_enable_read_intr(smd_xprtp->channel);
-
- wait_event(smd_xprtp->write_avail_wait_q,
- ((smd_write_avail(smd_xprtp->channel) >=
- align_sz) || smd_xprtp->ss_reset));
- smd_disable_read_intr(smd_xprtp->channel);
- spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
- if (smd_xprtp->ss_reset) {
- spin_unlock_irqrestore(
- &smd_xprtp->ss_reset_lock, flags);
- pr_err("%s: %s chnl reset\n",
- __func__, xprt->name);
- return -ENETRESET;
- }
- spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
- flags);
-
- smd_write_segment(smd_xprtp->channel,
- &align_data, align_sz, 0);
- D("%s: Wrote %d align bytes over %s\n",
- __func__, align_sz, xprt->name);
- }
if (!smd_write_end(smd_xprtp->channel))
D("%s: Finished writing\n", __func__);
return len;
@@ -453,6 +451,10 @@
smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
+ smd_remote_xprt[id].xprt.get_version =
+ msm_ipc_router_smd_get_xprt_version;
+ smd_remote_xprt[id].xprt.get_option =
+ msm_ipc_router_smd_get_xprt_option;
smd_remote_xprt[id].xprt.read_avail = NULL;
smd_remote_xprt[id].xprt.read = NULL;
smd_remote_xprt[id].xprt.write_avail =
@@ -468,6 +470,8 @@
INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
smd_remote_xprt[id].ss_reset = 0;
+ smd_remote_xprt[id].xprt_version = smd_xprt_cfg[id].xprt_version;
+ smd_remote_xprt[id].xprt_option = FRAG_PKT_WRITE_ENABLE;
smd_remote_xprt[id].pil = msm_ipc_load_subsystem(
smd_xprt_cfg[id].edge);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index ea27c71..d96d459 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -131,12 +131,15 @@
int i, copied, first = 1;
int data_size = 0, request_size, offset;
void *data;
+ int last = 0;
+ int align_size;
for (i = 0; i < num_sect; i++)
data_size += msg_sect[i].iov_len;
if (!data_size)
return NULL;
+ align_size = ALIGN_SIZE(data_size);
msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
if (!msg_head) {
@@ -148,10 +151,14 @@
for (copied = 1, i = 0; copied && (i < num_sect); i++) {
data_size = msg_sect[i].iov_len;
offset = 0;
+ if (i == (num_sect - 1))
+ last = 1;
while (offset != msg_sect[i].iov_len) {
request_size = data_size;
if (first)
request_size += IPC_ROUTER_HDR_SIZE;
+ if (last)
+ request_size += align_size;
msg = alloc_skb(request_size, GFP_KERNEL);
if (!msg) {
@@ -161,6 +168,7 @@
goto msg_build_failure;
}
data_size = data_size / 2;
+ last = 0;
continue;
}
@@ -182,6 +190,8 @@
skb_queue_tail(msg_head, msg);
offset += data_size;
data_size = msg_sect[i].iov_len - offset;
+ if (i == (num_sect - 1))
+ last = 1;
}
}
return msg_head;
@@ -196,24 +206,23 @@
}
static int msm_ipc_router_extract_msg(struct msghdr *m,
- struct sk_buff_head *msg_head)
+ struct rr_packet *pkt)
{
struct sockaddr_msm_ipc *addr;
- struct rr_header *hdr;
+ struct rr_header_v1 *hdr;
struct sk_buff *temp;
union rr_control_msg *ctl_msg;
int offset = 0, data_len = 0, copy_len;
- if (!m || !msg_head) {
+ if (!m || !pkt) {
pr_err("%s: Invalid pointers passed\n", __func__);
return -EINVAL;
}
addr = (struct sockaddr_msm_ipc *)m->msg_name;
- temp = skb_peek(msg_head);
- hdr = (struct rr_header *)(temp->data);
+ hdr = &(pkt->hdr);
if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
- skb_pull(temp, IPC_ROUTER_HDR_SIZE);
+ temp = skb_peek(pkt->pkt_fragment_q);
ctl_msg = (union rr_control_msg *)(temp->data);
addr->family = AF_MSM_IPC;
addr->address.addrtype = MSM_IPC_ADDR_ID;
@@ -222,7 +231,7 @@
m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
return offset;
}
- if (addr && (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
+ if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) {
addr->family = AF_MSM_IPC;
addr->address.addrtype = MSM_IPC_ADDR_ID;
addr->address.addr.port_addr.node_id = hdr->src_node_id;
@@ -231,8 +240,7 @@
}
data_len = hdr->size;
- skb_pull(temp, IPC_ROUTER_HDR_SIZE);
- skb_queue_walk(msg_head, temp) {
+ skb_queue_walk(pkt->pkt_fragment_q, temp) {
copy_len = data_len < temp->len ? data_len : temp->len;
if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
copy_len)) {
@@ -245,22 +253,6 @@
return offset;
}
-static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
-{
- struct sk_buff *temp;
-
- if (!msg_head) {
- pr_err("%s: Invalid msg pointer\n", __func__);
- return;
- }
-
- while (!skb_queue_empty(msg_head)) {
- temp = skb_dequeue(msg_head);
- kfree_skb(temp);
- }
- kfree(msg_head);
-}
-
static int msm_ipc_router_create(struct net *net,
struct socket *sock,
int protocol,
@@ -385,8 +377,10 @@
if (ipc_buf)
msm_ipc_router_ipc_log(IPC_SEND, ipc_buf, port_ptr);
ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
- if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
- ret = total_len;
+ if (ret != total_len) {
+ pr_err("%s: Send_to failure %d\n", __func__, ret);
+ ret = -EFAULT;
+ }
out_sendmsg:
release_sock(sk);
@@ -398,7 +392,7 @@
{
struct sock *sk = sock->sk;
struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
- struct sk_buff_head *msg;
+ struct rr_packet *pkt;
struct sk_buff *ipc_buf;
long timeout;
int ret;
@@ -420,18 +414,17 @@
return ret;
}
- ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
- if (ret <= 0 || !msg) {
+ ret = msm_ipc_router_read(port_ptr, &pkt, buf_len);
+ if (ret <= 0 || !pkt) {
release_sock(sk);
return ret;
}
- ret = msm_ipc_router_extract_msg(m, msg);
- ipc_buf = skb_peek(msg);
+ ret = msm_ipc_router_extract_msg(m, pkt);
+ ipc_buf = skb_peek(pkt->pkt_fragment_q);
if (ipc_buf)
msm_ipc_router_ipc_log(IPC_RECV, ipc_buf, port_ptr);
- msm_ipc_router_release_msg(msg);
- msg = NULL;
+ release_pkt(pkt);
release_sock(sk);
return ret;
}
@@ -460,7 +453,7 @@
switch (cmd) {
case IPC_ROUTER_IOCTL_GET_VERSION:
- n = IPC_ROUTER_VERSION;
+ n = IPC_ROUTER_V1;
ret = put_user(n, (unsigned int *)arg);
break;