summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohit Khanna <mkhannaqca@codeaurora.org>2017-02-17 14:51:51 -0800
committerqcabuildsw <qcabuildsw@localhost>2017-02-23 11:46:58 -0800
commit1b76247e49520dc7d1e1c85b712f50d676c6962a (patch)
tree79284a0636f6ea070f0f925c5a67d4ad23414359
parentd0dee4eb3f3e7e90e7fc0ca509ea37be34297bd0 (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.c6
-rw-r--r--core/dp/txrx/ol_tx_desc.c6
-rw-r--r--core/dp/txrx/ol_tx_send.c10
-rw-r--r--core/dp/txrx/ol_txrx.c7
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 */