qcacmn: Add debug for TSO seg double-free

Add TSO segment debug code, in a featurized way, so that
when disabled, it will tolerate redundant returns to the internal
pool and when enabled, it will check sanity on free, and record a
history of last 16 actions on the segment in the object.

Goes with the corresponding cld3 component counterpart.

Change-Id: Ifee2ceae940043031e4861d0e4f5d19a51262229
CRs-Fixed: 2036665
This commit is contained in:
Orhan K AKYILDIZ
2017-04-19 21:21:45 -07:00
committed by snandini
parent 21f852f52c
commit c59be52d47
3 changed files with 87 additions and 0 deletions

View File

@@ -476,6 +476,62 @@ void __printf(3, 4) qdf_snprintf(char *str_buffer, unsigned int size,
char *str_format, ...); char *str_format, ...);
#define QDF_SNPRINTF qdf_snprintf #define QDF_SNPRINTF qdf_snprintf
#ifdef TSOSEG_DEBUG
static inline
int qdf_tso_seg_dbg_record(struct qdf_tso_seg_elem_t *tsoseg,
uint16_t caller)
{
int rc = -1;
if (tsoseg != NULL) {
tsoseg->dbg.cur++; tsoseg->dbg.cur &= 0x0f;
tsoseg->dbg.history[tsoseg->dbg.cur] = caller;
rc = tsoseg->dbg.cur;
}
return rc;
};
static inline void qdf_tso_seg_dbg_bug(char *msg)
{
qdf_print(msg);
QDF_BUG(0);
};
static inline void
qdf_tso_seg_dbg_setowner(struct qdf_tso_seg_elem_t *tsoseg, void *owner)
{
tsoseg->dbg.txdesc = owner;
};
static inline void
qdf_tso_seg_dbg_zero(struct qdf_tso_seg_elem_t *tsoseg)
{
memset(tsoseg, 0, offsetof(struct qdf_tso_seg_elem_t, dbg));
return;
};
#else
static inline
int qdf_tso_seg_dbg_record(struct qdf_tso_seg_elem_t *tsoseg,
uint16_t caller)
{
return 0;
};
static inline void qdf_tso_seg_dbg_bug(char *msg)
{
};
static inline void
qdf_tso_seg_dbg_setowner(struct qdf_tso_seg_elem_t *tsoseg, void *owner)
{
};
static inline int
qdf_tso_seg_dbg_zero(struct qdf_tso_seg_elem_t *tsoseg)
{
memset(tsoseg, 0, sizeof(struct qdf_tso_seg_elem_t));
return 0;
};
#endif /* TSOSEG_DEBUG */
#else #else
#define DPTRACE(x) #define DPTRACE(x)

View File

@@ -690,6 +690,33 @@ struct qdf_tso_seg_t {
struct qdf_tso_frag_t tso_frags[FRAG_NUM_MAX]; struct qdf_tso_frag_t tso_frags[FRAG_NUM_MAX];
}; };
/**
* TSO seg elem action caller locations: goes into dbg.history below.
* Needed to be defined outside of the feature so that
* callers can be coded without ifdefs (even if they get
* resolved to nothing)
*/
enum tsoseg_dbg_caller_e {
TSOSEG_LOC_UNDEFINED,
TSOSEG_LOC_INIT1,
TSOSEG_LOC_INIT2,
TSOSEG_LOC_DEINIT,
TSOSEG_LOC_PREPARETSO,
TSOSEG_LOC_TXPREPLLFAST,
TSOSEG_LOC_UNMAPTSO,
TSOSEG_LOC_ALLOC,
TSOSEG_LOC_FREE,
};
#ifdef TSOSEG_DEBUG
#define MAX_TSO_SEG_ACT_HISTORY 16
struct qdf_tso_seg_dbg_t {
void *txdesc; /* owner - (ol_txrx_tx_desc_t *) */
int cur; /* index of last valid entry */
uint16_t history[MAX_TSO_SEG_ACT_HISTORY];
};
#endif /* TSOSEG_DEBUG */
/** /**
* qdf_tso_seg_elem_t - tso segment element * qdf_tso_seg_elem_t - tso segment element
* @seg: instance of segment * @seg: instance of segment
@@ -700,6 +727,9 @@ struct qdf_tso_seg_elem_t {
uint16_t cookie:15, uint16_t cookie:15,
on_freelist:1; on_freelist:1;
struct qdf_tso_seg_elem_t *next; struct qdf_tso_seg_elem_t *next;
#ifdef TSOSEG_DEBUG
struct qdf_tso_seg_dbg_t dbg;
#endif /* TSOSEG_DEBUG */
}; };
/** /**

View File

@@ -1982,6 +1982,7 @@ void __qdf_nbuf_unmap_tso_segment(qdf_device_t osdev,
qdf_assert(0); qdf_assert(0);
return; return;
} }
qdf_tso_seg_dbg_record(tso_seg, TSOSEG_LOC_UNMAPTSO);
dma_unmap_single(osdev->dev, dma_unmap_single(osdev->dev,
tso_seg->seg.tso_frags[num_frags].paddr, tso_seg->seg.tso_frags[num_frags].paddr,
tso_seg->seg.tso_frags[num_frags].length, tso_seg->seg.tso_frags[num_frags].length,