diff options
| author | Mohit Khanna <mkhannaqca@codeaurora.org> | 2017-02-17 14:51:51 -0800 |
|---|---|---|
| committer | qcabuildsw <qcabuildsw@localhost> | 2017-02-23 11:46:58 -0800 |
| commit | 1b76247e49520dc7d1e1c85b712f50d676c6962a (patch) | |
| tree | 79284a0636f6ea070f0f925c5a67d4ad23414359 | |
| parent | d0dee4eb3f3e7e90e7fc0ca509ea37be34297bd0 (diff) | |
qcacld-3.0: Debug logs to detect TSO seg double free
On stability test bed a double free of TSO segment is reported via the
TX completion path. Made following changes -
- Check for duplicate TX completions before freeing TSO segments.
- Add debug logs to check if TX descriptors are being freed from the
control path.
Change-Id: I30178de90cd0161001ded70adc26066adc9cbcb3
CRs-Fixed: 2006868
| -rw-r--r-- | core/dp/txrx/ol_tx.c | 6 | ||||
| -rw-r--r-- | core/dp/txrx/ol_tx_desc.c | 6 | ||||
| -rw-r--r-- | core/dp/txrx/ol_tx_send.c | 10 | ||||
| -rw-r--r-- | core/dp/txrx/ol_txrx.c | 7 |
4 files changed, 25 insertions, 4 deletions
diff --git a/core/dp/txrx/ol_tx.c b/core/dp/txrx/ol_tx.c index 13f815a5ccb4..713dc3ba1400 100644 --- a/core/dp/txrx/ol_tx.c +++ b/core/dp/txrx/ol_tx.c @@ -2039,6 +2039,7 @@ void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) __func__, i); QDF_BUG(0); pdev->tso_seg_pool.pool_size = i; + pdev->tso_seg_pool.num_free = i; qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); return; } @@ -2059,6 +2060,7 @@ void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) __func__, i); QDF_BUG(0); pdev->tso_seg_pool.pool_size = i; + pdev->tso_seg_pool.num_free = i; qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); return; } @@ -2066,6 +2068,7 @@ void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) c_element->cookie = TSO_SEG_MAGIC_COOKIE; c_element->next = NULL; pdev->tso_seg_pool.pool_size = num_seg; + pdev->tso_seg_pool.num_free = num_seg; qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); } @@ -2149,6 +2152,7 @@ void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) __func__, i); QDF_BUG(0); pdev->tso_num_seg_pool.num_seg_pool_size = i; + pdev->tso_num_seg_pool.num_free = i; qdf_spinlock_create(&pdev->tso_num_seg_pool. tso_num_seg_mutex); return; @@ -2167,11 +2171,13 @@ void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) __func__, i); QDF_BUG(0); pdev->tso_num_seg_pool.num_seg_pool_size = i; + pdev->tso_num_seg_pool.num_free = i; qdf_spinlock_create(&pdev->tso_num_seg_pool.tso_num_seg_mutex); return; } c_element->next = NULL; pdev->tso_num_seg_pool.num_seg_pool_size = num_seg; + pdev->tso_num_seg_pool.num_free = num_seg; qdf_spinlock_create(&pdev->tso_num_seg_pool.tso_num_seg_mutex); } diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c index 4194fd2d0ee8..128441c87e83 100644 --- a/core/dp/txrx/ol_tx_desc.c +++ b/core/dp/txrx/ol_tx_desc.c @@ -356,10 +356,11 @@ void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) { qdf_spin_lock_bh(&pdev->tx_mutex); + ol_tx_desc_dup_detect_reset(pdev, tx_desc); + if (tx_desc->pkt_type == OL_TX_FRM_TSO) ol_tx_tso_desc_free(pdev, tx_desc); - ol_tx_desc_dup_detect_reset(pdev, tx_desc); ol_tx_desc_reset_pkt_type(tx_desc); ol_tx_desc_reset_timestamp(tx_desc); @@ -813,6 +814,7 @@ void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev, return; } /*this tso seg is now a part of freelist*/ + qdf_mem_zero(tso_seg, sizeof(*tso_seg)); tso_seg->next = pdev->tso_seg_pool.freelist; tso_seg->on_freelist = 1; pdev->tso_seg_pool.freelist = tso_seg; @@ -862,7 +864,7 @@ void ol_tso_num_seg_free(struct ol_txrx_pdev_t *pdev, qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); tso_num_seg->next = pdev->tso_num_seg_pool.freelist; pdev->tso_num_seg_pool.freelist = tso_num_seg; - pdev->tso_num_seg_pool.num_free++; + pdev->tso_num_seg_pool.num_free++; qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); } #endif diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c index 118e79a3b745..ded02d24da03 100644 --- a/core/dp/txrx/ol_tx_send.c +++ b/core/dp/txrx/ol_tx_send.c @@ -493,6 +493,7 @@ void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev) { int i = 0; struct ol_tx_desc_t *tx_desc; + int num_disarded = 0; for (i = 0; i < pdev->tx_desc.pool_size; i++) { tx_desc = ol_tx_desc_find(pdev, i); @@ -505,12 +506,17 @@ void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev) */ if (qdf_atomic_read(&tx_desc->ref_cnt)) { TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, - "Warning: freeing tx frame " - "(no tx completion from the target)\n"); + "Warning: freeing tx desc %d", tx_desc->id); ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1); + num_disarded++; } } + + if (num_disarded) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Warning: freed %d tx descs for which" + "no tx completion rcvd from the target", num_disarded); } #endif diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index 41a0c223da9b..994a83265842 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -1705,6 +1705,7 @@ A_STATUS ol_txrx_pdev_attach_target(ol_txrx_pdev_handle pdev) void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) { int i; + int num_freed_tx_desc = 0; struct hif_opaque_softc *osc = cds_get_context(QDF_MODULE_ID_HIF); /*checking to ensure txrx pdev structure is not NULL */ @@ -1775,11 +1776,17 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) "Warning: freeing tx frame (no compltn)\n"); ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1); + num_freed_tx_desc++; } htt_tx_desc = tx_desc->htt_tx_desc; htt_tx_desc_free(pdev->htt_pdev, htt_tx_desc); } + if (num_freed_tx_desc) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "freed %d tx frames for which no resp from target", + num_freed_tx_desc); + htt_deregister_rx_pkt_dump_callback(pdev->htt_pdev); ol_tx_deregister_flow_control(pdev); /* Stop the communication between HTT and target at first */ |
