summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-11-18 01:55:00 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-11-18 01:55:00 -0800
commita708ddf420e811c23776b5a6ef4b708d44a39d4c (patch)
tree47a76772b205098518897982a8602826f6831dea
parentdc3c5f14a21930d3da0400403a03d1707a28794c (diff)
parent76c28263ad5274e8a4b43586c44a4cddeb3036bb (diff)
Merge "msm: ipa3: linearize large skbs"
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dp.c59
1 files changed, 37 insertions, 22 deletions
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 4b0cd46082a3..be2946c873b3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -1723,6 +1723,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
struct ipa3_sys_context *sys;
int src_ep_idx;
int num_frags, f;
+ struct ipa_gsi_ep_config *gsi_ep;
if (unlikely(!ipa3_ctx)) {
IPAERR("IPA3 driver was not initialized\n");
@@ -1734,23 +1735,6 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
return -EINVAL;
}
- num_frags = skb_shinfo(skb)->nr_frags;
- if (num_frags) {
- /* 1 desc for tag to resolve status out-of-order issue;
- * 1 desc is needed for the linear portion of skb;
- * 1 desc may be needed for the PACKET_INIT;
- * 1 desc for each frag
- */
- desc = kzalloc(sizeof(*desc) * (num_frags + 3), GFP_ATOMIC);
- if (!desc) {
- IPAERR("failed to alloc desc array\n");
- goto fail_mem;
- }
- } else {
- memset(_desc, 0, 3 * sizeof(struct ipa3_desc));
- desc = &_desc[0];
- }
-
/*
* USB_CONS: PKT_INIT ep_idx = dst pipe
* Q6_CONS: PKT_INIT ep_idx = sender pipe
@@ -1787,6 +1771,37 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
goto fail_gen;
}
+ num_frags = skb_shinfo(skb)->nr_frags;
+ /*
+ * make sure TLV FIFO supports the needed frags.
+ * 2 descriptors are needed for IP_PACKET_INIT and TAG_STATUS.
+ * 1 descriptor needed for the linear portion of skb.
+ */
+ gsi_ep = ipa3_get_gsi_ep_info(src_ep_idx);
+ if (gsi_ep && (num_frags + 3 > gsi_ep->ipa_if_tlv)) {
+ if (skb_linearize(skb)) {
+ IPAERR("Failed to linear skb with %d frags\n",
+ num_frags);
+ goto fail_gen;
+ }
+ num_frags = 0;
+ }
+ if (num_frags) {
+ /* 1 desc for tag to resolve status out-of-order issue;
+ * 1 desc is needed for the linear portion of skb;
+ * 1 desc may be needed for the PACKET_INIT;
+ * 1 desc for each frag
+ */
+ desc = kzalloc(sizeof(*desc) * (num_frags + 3), GFP_ATOMIC);
+ if (!desc) {
+ IPAERR("failed to alloc desc array\n");
+ goto fail_gen;
+ }
+ } else {
+ memset(_desc, 0, 3 * sizeof(struct ipa3_desc));
+ desc = &_desc[0];
+ }
+
if (dst_ep_idx != -1) {
/* SW data path */
cmd.destination_pipe_index = dst_ep_idx;
@@ -1794,7 +1809,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
IPA_IMM_CMD_IP_PACKET_INIT, &cmd, true);
if (unlikely(!cmd_pyld)) {
IPAERR("failed to construct ip_packet_init imm cmd\n");
- goto fail_gen;
+ goto fail_mem;
}
/* the tag field will be populated in ipa3_send() function */
@@ -1863,7 +1878,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
if (num_frags == 0) {
if (ipa3_send(sys, 2, desc, true)) {
IPAERR("fail to send skb %p HWP\n", skb);
- goto fail_gen;
+ goto fail_mem;
}
} else {
for (f = 0; f < num_frags; f++) {
@@ -1880,7 +1895,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
if (ipa3_send(sys, num_frags + 2, desc, true)) {
IPAERR("fail to send skb %p num_frags %u HWP\n",
skb, num_frags);
- goto fail_gen;
+ goto fail_mem;
}
}
IPA_STATS_INC_CNT(ipa3_ctx->stats.tx_hw_pkts);
@@ -1894,10 +1909,10 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
fail_send:
ipahal_destroy_imm_cmd(cmd_pyld);
-fail_gen:
+fail_mem:
if (num_frags)
kfree(desc);
-fail_mem:
+fail_gen:
return -EFAULT;
}