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; }