qcacld-3.0: Do not free skb in OL if ce_send_fast failed

Return failure if ce_send_fast fails and let caller, HDD free the Tx msdu.
If it happens to be TSO segment then free the to be trasmited TSO segments.

Change-Id: If3a16ca841e63e7941fe732013d3b3c351a4a286
CRs-Fixed: 2004780
This commit is contained in:
Manjunathappa Prakash
2017-02-13 00:02:16 -08:00
parent ecefc07b73
commit 8623d30b4f
2 changed files with 44 additions and 23 deletions

View File

@@ -83,6 +83,18 @@ int ce_send_fast(struct CE_handle *copyeng, qdf_nbuf_t msdu,
} while (0) } while (0)
#if defined(FEATURE_TSO) #if defined(FEATURE_TSO)
static void ol_free_remaining_tso_segs(ol_txrx_vdev_handle vdev,
struct ol_txrx_msdu_info_t *msdu_info)
{
struct qdf_tso_seg_elem_t *next_seg;
struct qdf_tso_seg_elem_t *free_seg = msdu_info->tso_info.curr_seg;
while (free_seg) {
next_seg = free_seg->next;
ol_tso_free_segment(vdev->pdev, free_seg);
free_seg = next_seg;
}
}
/** /**
* ol_tx_prepare_tso() - Given a jumbo msdu, prepare the TSO * ol_tx_prepare_tso() - Given a jumbo msdu, prepare the TSO
* related information in the msdu_info meta data * related information in the msdu_info meta data
@@ -113,16 +125,10 @@ static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev,
= tso_seg; = tso_seg;
num_seg--; num_seg--;
} else { } else {
struct qdf_tso_seg_elem_t *next_seg; /* Free above alocated TSO segements till now */
struct qdf_tso_seg_elem_t *free_seg = msdu_info->tso_info.curr_seg =
msdu_info->tso_info.tso_seg_list; msdu_info->tso_info.tso_seg_list;
qdf_print("TSO seg alloc failed!\n"); ol_free_remaining_tso_segs(vdev, msdu_info);
while (free_seg) {
next_seg = free_seg->next;
ol_tso_free_segment(vdev->pdev,
free_seg);
free_seg = next_seg;
}
return 1; return 1;
} }
} }
@@ -133,16 +139,9 @@ static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev,
msdu_info->tso_info.tso_num_seg_list = tso_num_seg; msdu_info->tso_info.tso_num_seg_list = tso_num_seg;
} else { } else {
/* Free the already allocated num of segments */ /* Free the already allocated num of segments */
struct qdf_tso_seg_elem_t *next_seg; msdu_info->tso_info.curr_seg =
struct qdf_tso_seg_elem_t *free_seg =
msdu_info->tso_info.tso_seg_list; msdu_info->tso_info.tso_seg_list;
qdf_print("TSO num of seg alloc for one jumbo skb failed!\n"); ol_free_remaining_tso_segs(vdev, msdu_info);
while (free_seg) {
next_seg = free_seg->next;
ol_tso_free_segment(vdev->pdev,
free_seg);
free_seg = next_seg;
}
return 1; return 1;
} }
qdf_nbuf_get_tso_info(vdev->pdev->osdev, qdf_nbuf_get_tso_info(vdev->pdev->osdev,
@@ -698,13 +697,28 @@ ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
htt_tx_desc_display(tx_desc->htt_tx_desc); htt_tx_desc_display(tx_desc->htt_tx_desc);
if ((0 == ce_send_fast(pdev->ce_tx_hdl, msdu, if ((0 == ce_send_fast(pdev->ce_tx_hdl, msdu,
ep_id, pkt_download_len))) { ep_id, pkt_download_len))) {
struct qdf_tso_info_t *tso_info =
&msdu_info.tso_info;
/*
* If TSO packet, free associated
* remaining TSO segment descriptors
*/
if (tx_desc->pkt_type ==
OL_TX_FRM_TSO) {
tso_info->curr_seg =
tso_info->curr_seg->next;
ol_free_remaining_tso_segs(vdev,
&msdu_info);
}
/* /*
* The packet could not be sent. * The packet could not be sent.
* Free the descriptor, return the * Free the descriptor, return the
* packet to the caller. * packet to the caller.
*/ */
ol_tx_desc_frame_free_nonstd(pdev, ol_tx_desc_frame_free_nonstd(pdev,
tx_desc, 1); tx_desc,
htt_tx_status_download_fail);
return msdu; return msdu;
} }
if (msdu_info.tso_info.curr_seg) { if (msdu_info.tso_info.curr_seg) {

View File

@@ -698,8 +698,7 @@ void ol_tx_desc_frame_free_nonstd(struct ol_txrx_pdev_t *pdev,
qdf_nbuf_set_next(tx_desc->netbuf, NULL); qdf_nbuf_set_next(tx_desc->netbuf, NULL);
pdev->tx_data_callback.func(pdev->tx_data_callback.ctxt, pdev->tx_data_callback.func(pdev->tx_data_callback.ctxt,
tx_desc->netbuf, had_error); tx_desc->netbuf, had_error);
ol_tx_desc_free(pdev, tx_desc); goto free_tx_desc;
return;
} }
/* let the code below unmap and free the frame */ /* let the code below unmap and free the frame */
} }
@@ -744,11 +743,19 @@ void ol_tx_desc_frame_free_nonstd(struct ol_txrx_pdev_t *pdev,
} }
/* free the netbuf */ /* free the netbuf */
qdf_nbuf_free(tx_desc->netbuf); qdf_nbuf_free(tx_desc->netbuf);
} else if (had_error == htt_tx_status_download_fail) {
/* Failed to send to target */
/* This is to decrement skb->users count for TSO segment */
if (tx_desc->pkt_type == OL_TX_FRM_TSO)
qdf_nbuf_tx_free(tx_desc->netbuf, had_error);
goto free_tx_desc;
} else { } else {
/* single regular frame */ /* single regular frame, called from completion path */
qdf_nbuf_set_next(tx_desc->netbuf, NULL); qdf_nbuf_set_next(tx_desc->netbuf, NULL);
qdf_nbuf_tx_free(tx_desc->netbuf, had_error); qdf_nbuf_tx_free(tx_desc->netbuf, had_error);
} }
free_tx_desc:
/* free the tx desc */ /* free the tx desc */
ol_tx_desc_free(pdev, tx_desc); ol_tx_desc_free(pdev, tx_desc);
} }