qcacmn: Fix issues from monitor path

a. Fix memleak issue due to RX_HDR not received for a MPDU
b. Compute appropriate packet offset for non-decapped packets
c. Add correct DMA_LEN while adding a frag to SKB.
d. Add debug stats

Change-Id: Ie946f79df94df05789220b97c159c60d608bf1b2
CRs-Fixed: 3213698
Cette révision appartient à :
Amir Patel
2022-06-10 19:13:12 +05:30
révisé par Madan Koyyalamudi
Parent 823d493a71
révision debe4c7ecf
7 fichiers modifiés avec 192 ajouts et 84 suppressions

Voir le fichier

@@ -392,6 +392,13 @@ enum cdp_mon_phyrx_abort_reason_code {
* ring ppdu id
* @rx_undecoded_count: Received undecoded frame count
* @rx_undecoded_error: Rx undecoded errors
* @rx_hdr_not_received: Rx HDR not received for MPDU
* @parent_buf_alloc: Numder of parent nbuf allocated for MPDU
* @parent_buf_free: Number of parent nbuf freed
* @pkt_buf_count: Number of packet buffers received
* @mpdus_to_stack: Number of MPDUs delivered to stack
* @status_buf_count: Number of status buffer received
* @empty_desc_ppdu: Number of empty desc received
*/
struct cdp_pdev_mon_stats {
#ifndef REMOVE_MON_DBG_STATS
@@ -428,6 +435,13 @@ struct cdp_pdev_mon_stats {
uint32_t rx_undecoded_count;
uint32_t rx_undecoded_error[CDP_PHYRX_ERR_MAX];
#endif
uint32_t rx_hdr_not_received;
uint32_t parent_buf_alloc;
uint32_t parent_buf_free;
uint32_t pkt_buf_count;
uint32_t mpdus_buf_to_stack;
uint32_t status_buf_count;
uint32_t empty_desc_ppdu;
};
#ifdef QCA_SUPPORT_LITE_MONITOR

Voir le fichier

@@ -243,6 +243,7 @@ dp_mon_buffers_replenish(struct dp_soc *dp_soc,
union dp_mon_desc_list_elem_t *next;
void *mon_srng;
QDF_STATUS ret = QDF_STATUS_E_FAILURE;
struct dp_mon_soc *mon_soc = dp_soc->monitor_soc;
if (!num_req_buffers) {
dp_mon_debug("%pK: Received request for 0 buffers replenish",
@@ -318,6 +319,7 @@ dp_mon_buffers_replenish(struct dp_soc *dp_soc,
(*desc_list)->mon_desc.paddr = mon_desc.paddr;
(*desc_list)->mon_desc.magic = DP_MON_DESC_MAGIC;
mon_soc->stats.frag_alloc++;
hal_mon_buff_addr_info_set(dp_soc->hal_soc,
mon_ring_entry,
&((*desc_list)->mon_desc),

Voir le fichier

@@ -30,7 +30,7 @@
#define DP_MON_RING_FILL_LEVEL_DEFAULT 2048
#define DP_MON_DATA_BUFFER_SIZE 2048
#define DP_MON_DESC_MAGIC 0xdeadabcd
#define DP_MON_MAX_STATUS_BUF 128
#define DP_MON_MAX_STATUS_BUF 1200
#define DP_MON_QUEUE_DEPTH_MAX 16
#define DP_MON_MSDU_LOGGING 0
#define DP_MON_MPDU_LOGGING 1

Voir le fichier

@@ -66,6 +66,53 @@ dp_rx_mon_pf_update_stats(struct dp_pdev *dp_pdev, uint32_t flow_idx,
}
#endif
/**
* dp_rx_mon_nbuf_add_rx_frag () - Add frag to SKB
*
* @nbuf: SKB to which frag is going to be added
* @frag: frag to be added to SKB
* @frag_len: frag length
* @offset: frag offset
* @buf_size: buffer size
* @frag_ref: take frag ref
*
* Return: QDF_STATUS
*/
static inline QDF_STATUS
dp_rx_mon_nbuf_add_rx_frag(qdf_nbuf_t nbuf, qdf_frag_t *frag,
uint16_t frag_len, uint16_t offset,
uint16_t buf_size, bool frag_ref)
{
uint8_t num_frags;
num_frags = qdf_nbuf_get_nr_frags(nbuf);
if (num_frags < QDF_NBUF_MAX_FRAGS) {
qdf_nbuf_add_rx_frag(frag, nbuf,
offset,
frag_len,
buf_size,
frag_ref);
return QDF_STATUS_SUCCESS;
}
return QDF_STATUS_E_FAILURE;
}
/**
* dp_mon_free_parent_nbuf() - Free parent SKB
*
* @mon_pdev: monitor pdev
* @nbuf: SKB to be freed
*
* @Return: void
*/
static inline void
dp_mon_free_parent_nbuf(struct dp_mon_pdev *mon_pdev,
qdf_nbuf_t nbuf)
{
mon_pdev->rx_mon_stats.parent_buf_free++;
qdf_nbuf_free(nbuf);
}
void
dp_rx_mon_shift_pf_tag_in_headroom(qdf_nbuf_t nbuf, struct dp_soc *soc)
{
@@ -172,7 +219,9 @@ dp_rx_mon_free_ppdu_info(struct dp_pdev *pdev,
struct hal_rx_ppdu_info *ppdu_info)
{
uint8_t user;
struct dp_mon_pdev *mon_pdev;
mon_pdev = (struct dp_mon_pdev *)pdev->monitor_pdev;
for (user = 0; user < ppdu_info->com_info.num_users; user++) {
uint16_t mpdu_count = ppdu_info->mpdu_count[user];
uint16_t mpdu_idx;
@@ -183,7 +232,7 @@ dp_rx_mon_free_ppdu_info(struct dp_pdev *pdev,
if (!mpdu)
continue;
qdf_nbuf_free(mpdu);
dp_mon_free_parent_nbuf(mon_pdev, mpdu);
}
}
}
@@ -209,17 +258,15 @@ void dp_rx_mon_drain_wq(struct dp_pdev *pdev)
mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
qdf_spin_lock_bh(&mon_pdev_be->rx_mon_wq_lock);
if (!TAILQ_EMPTY(&mon_pdev_be->rx_mon_queue)) {
TAILQ_FOREACH_SAFE(ppdu_info,
&mon_pdev_be->rx_mon_queue,
ppdu_list_elem,
temp_ppdu_info) {
TAILQ_REMOVE(&mon_pdev_be->rx_mon_queue,
ppdu_info, ppdu_list_elem);
TAILQ_FOREACH_SAFE(ppdu_info,
&mon_pdev_be->rx_mon_queue,
ppdu_list_elem,
temp_ppdu_info) {
mon_pdev_be->rx_mon_queue_depth--;
TAILQ_REMOVE(&mon_pdev_be->rx_mon_queue,
ppdu_info, ppdu_list_elem);
dp_rx_mon_free_ppdu_info(pdev, ppdu_info);
qdf_mem_free(ppdu_info);
}
dp_rx_mon_free_ppdu_info(pdev, ppdu_info);
}
qdf_spin_unlock_bh(&mon_pdev_be->rx_mon_wq_lock);
}
@@ -238,7 +285,16 @@ dp_rx_mon_deliver_mpdu(struct dp_mon_pdev *mon_pdev,
qdf_nbuf_t mpdu,
struct mon_rx_status *rx_status)
{
qdf_nbuf_t nbuf;
if (mon_pdev->mvdev && mon_pdev->mvdev->monitor_vdev->osif_rx_mon) {
mon_pdev->rx_mon_stats.mpdus_buf_to_stack++;
nbuf = qdf_nbuf_get_ext_list(mpdu);
while (nbuf) {
mon_pdev->rx_mon_stats.mpdus_buf_to_stack++;
nbuf = nbuf->next;
}
mon_pdev->mvdev->monitor_vdev->osif_rx_mon(mon_pdev->mvdev->osif_vdev,
mpdu,
rx_status);
@@ -288,14 +344,14 @@ dp_rx_mon_process_ppdu_info(struct dp_pdev *pdev,
} else {
if (mpdu_meta->full_pkt) {
if (qdf_unlikely(mpdu_meta->truncated)) {
qdf_nbuf_free(mpdu);
dp_mon_free_parent_nbuf(mon_pdev, mpdu);
continue;
}
dp_rx_mon_handle_full_mon(pdev,
ppdu_info, mpdu);
} else {
qdf_nbuf_free(mpdu);
dp_mon_free_parent_nbuf(mon_pdev, mpdu);
continue;
}
@@ -315,9 +371,8 @@ dp_rx_mon_process_ppdu_info(struct dp_pdev *pdev,
status = dp_rx_mon_deliver_mpdu(mon_pdev,
mpdu,
&ppdu_info->rx_status);
if (status != QDF_STATUS_SUCCESS)
qdf_nbuf_free(mpdu);
dp_mon_free_parent_nbuf(mon_pdev, mpdu);
}
}
}
@@ -355,18 +410,15 @@ void dp_rx_mon_process_ppdu(void *context)
mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
qdf_spin_lock_bh(&mon_pdev_be->rx_mon_wq_lock);
if (!TAILQ_EMPTY(&mon_pdev_be->rx_mon_queue)) {
TAILQ_FOREACH_SAFE(ppdu_info,
&mon_pdev_be->rx_mon_queue,
ppdu_list_elem,
temp_ppdu_info) {
TAILQ_REMOVE(&mon_pdev_be->rx_mon_queue,
ppdu_info, ppdu_list_elem);
TAILQ_FOREACH_SAFE(ppdu_info,
&mon_pdev_be->rx_mon_queue,
ppdu_list_elem, temp_ppdu_info) {
TAILQ_REMOVE(&mon_pdev_be->rx_mon_queue,
ppdu_info, ppdu_list_elem);
mon_pdev_be->rx_mon_queue_depth--;
dp_rx_mon_process_ppdu_info(pdev, ppdu_info);
qdf_mem_free(ppdu_info);
}
mon_pdev_be->rx_mon_queue_depth--;
dp_rx_mon_process_ppdu_info(pdev, ppdu_info);
qdf_mem_free(ppdu_info);
}
qdf_spin_unlock_bh(&mon_pdev_be->rx_mon_wq_lock);
}
@@ -767,6 +819,7 @@ dp_rx_mon_flush_status_buf_queue(struct dp_pdev *pdev)
mon_pdev_be->desc_count--;
qdf_frag_free(buf);
DP_STATS_INC(mon_soc, frag_free, 1);
}
if (work_done) {
@@ -802,6 +855,7 @@ dp_rx_mon_handle_flush_n_trucated_ppdu(struct dp_soc *soc,
/* Flush status buffers in queue */
dp_rx_mon_flush_status_buf_queue(pdev);
qdf_frag_free(mon_desc->buf_addr);
DP_STATS_INC(mon_soc, frag_free, 1);
dp_mon_add_to_free_desc_list(&desc_list, &tail, mon_desc);
work_done = 1;
dp_mon_buffers_replenish(soc, &soc->rxdma_mon_buf_ring[0],
@@ -818,6 +872,7 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
union dp_mon_desc_list_elem_t **tail)
{
struct dp_soc *soc = pdev->soc;
struct dp_mon_soc *mon_soc = soc->monitor_soc;
struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
qdf_nbuf_t nbuf, tmp_nbuf;
qdf_frag_t addr;
@@ -825,6 +880,7 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
uint8_t mpdu_idx = ppdu_info->mpdu_count[user_id];
uint16_t num_frags;
uint8_t num_buf_reaped = 0;
QDF_STATUS status;
if (!mon_pdev->monitor_configured &&
!dp_lite_mon_is_rx_enabled(mon_pdev)) {
@@ -847,26 +903,21 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
/* Set *head_msdu->next as NULL as all msdus are
* * mapped via nr frags
* */
if (!nbuf) {
if (qdf_unlikely(!nbuf)) {
dp_mon_err("malloc failed pdev: %pK ", pdev);
return num_buf_reaped;
}
mon_pdev->rx_mon_stats.parent_buf_alloc++;
qdf_nbuf_set_next(nbuf, NULL);
ppdu_info->mpdu_q[user_id][mpdu_idx] = nbuf;
num_frags = qdf_nbuf_get_nr_frags(nbuf);
if (num_frags < QDF_NBUF_MAX_FRAGS) {
qdf_nbuf_add_rx_frag(status_frag, nbuf,
ppdu_info->data - (unsigned char *)status_frag + 4,
ppdu_info->hdr_len - DP_RX_MON_RX_HDR_OFFSET,
DP_MON_DATA_BUFFER_SIZE,
true);
} else {
status = dp_rx_mon_nbuf_add_rx_frag(nbuf, status_frag,
ppdu_info->data - (unsigned char *)status_frag + 4,
ppdu_info->hdr_len - DP_RX_MON_RX_HDR_OFFSET,
DP_MON_DATA_BUFFER_SIZE, true);
if (qdf_unlikely(status != QDF_STATUS_SUCCESS)) {
dp_mon_err("num_frags exceeding MAX frags");
qdf_assert_always(0);
}
@@ -899,23 +950,16 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
dp_mon_err("nbuf is NULL");
qdf_assert_always(0);
}
mon_pdev->rx_mon_stats.parent_buf_alloc++;
/* add new skb to frag list */
qdf_nbuf_append_ext_list(nbuf, tmp_nbuf,
qdf_nbuf_len(tmp_nbuf));
}
num_frags = qdf_nbuf_get_nr_frags(tmp_nbuf);
if (num_frags < QDF_NBUF_MAX_FRAGS) {
qdf_nbuf_add_rx_frag(status_frag,
tmp_nbuf,
ppdu_info->data - (unsigned char *)status_frag + 4,
ppdu_info->hdr_len - DP_RX_MON_RX_HDR_OFFSET,
DP_MON_DATA_BUFFER_SIZE,
true);
} else {
dp_mon_err("num_frags exceeding MAX frags");
qdf_assert_always(0);
}
dp_rx_mon_nbuf_add_rx_frag(tmp_nbuf, status_frag,
ppdu_info->data - (unsigned char *)status_frag + 4,
ppdu_info->hdr_len - DP_RX_MON_RX_HDR_OFFSET,
DP_MON_DATA_BUFFER_SIZE,
true);
}
}
break;
@@ -946,51 +990,66 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
dp_mon_add_to_free_desc_list(desc_list, tail, mon_desc);
num_buf_reaped++;
mon_pdev->rx_mon_stats.pkt_buf_count++;
nbuf = ppdu_info->mpdu_q[user_id][mpdu_idx];
mpdu_info->full_pkt = true;
if (qdf_unlikely(!nbuf)) {
nbuf = qdf_nbuf_alloc(pdev->soc->osdev,
DP_RX_MON_MAX_MONITOR_HEADER,
DP_RX_MON_MAX_MONITOR_HEADER,
4, FALSE);
if (!nbuf) {
dp_mon_err("nbuf allocation failed ...");
/* WAR: RX_HDR is not received for this MPDU, drop this frame */
DP_STATS_INC(mon_soc, frag_free, 1);
qdf_frag_free(addr);
return num_buf_reaped;
}
tmp_nbuf = qdf_get_nbuf_valid_frag(nbuf);
if (!tmp_nbuf) {
tmp_nbuf = qdf_nbuf_alloc(pdev->soc->osdev,
DP_RX_MON_MAX_MONITOR_HEADER,
DP_RX_MON_MAX_MONITOR_HEADER,
4, FALSE);
if (qdf_unlikely(!tmp_nbuf)) {
dp_mon_err("nbuf is NULL");
DP_STATS_INC(mon_soc, frag_free, 1);
mon_pdev->rx_mon_stats.parent_buf_free++;
qdf_frag_free(addr);
qdf_nbuf_free(nbuf);
ppdu_info->mpdu_q[user_id][mpdu_idx] = NULL;
return num_buf_reaped;
}
mon_pdev->rx_mon_stats.parent_buf_alloc++;
/* add new skb to frag list */
qdf_nbuf_append_ext_list(nbuf, tmp_nbuf,
qdf_nbuf_len(tmp_nbuf));
}
mpdu_info->full_pkt = true;
if (mpdu_info->decap_type == HAL_HW_RX_DECAP_FORMAT_RAW) {
if (mpdu_info->first_rx_hdr_rcvd) {
qdf_nbuf_remove_frag(nbuf, frag_idx, DP_MON_DATA_BUFFER_SIZE);
qdf_nbuf_add_rx_frag(addr, nbuf,
DP_RX_MON_PACKET_OFFSET,
packet_info->dma_length,
DP_MON_DATA_BUFFER_SIZE,
false);
dp_rx_mon_nbuf_add_rx_frag(nbuf, addr,
packet_info->dma_length,
DP_RX_MON_PACKET_OFFSET,
DP_MON_DATA_BUFFER_SIZE,
false);
DP_STATS_INC(mon_soc, frag_free, 1);
mpdu_info->first_rx_hdr_rcvd = false;
} else {
num_frags = qdf_nbuf_get_nr_frags(nbuf);
if (num_frags < QDF_NBUF_MAX_FRAGS) {
qdf_nbuf_add_rx_frag(addr, nbuf,
DP_RX_MON_PACKET_OFFSET,
packet_info->dma_length,
RX_MONITOR_BUFFER_SIZE,
false);
}
dp_rx_mon_nbuf_add_rx_frag(tmp_nbuf, addr,
packet_info->dma_length,
DP_RX_MON_PACKET_OFFSET,
DP_MON_DATA_BUFFER_SIZE,
false);
DP_STATS_INC(mon_soc, frag_free, 1);
}
} else {
num_frags = qdf_nbuf_get_nr_frags(nbuf);
if (num_frags < QDF_NBUF_MAX_FRAGS) {
qdf_nbuf_add_rx_frag(addr, nbuf,
DP_RX_MON_NONRAW_L2_HDR_PAD_BYTE +
DP_RX_MON_PACKET_OFFSET,
packet_info->dma_length,
RX_MONITOR_BUFFER_SIZE,
false);
}
dp_rx_mon_nbuf_add_rx_frag(tmp_nbuf, addr,
packet_info->dma_length,
DP_RX_MON_NONRAW_L2_HDR_PAD_BYTE +
DP_RX_MON_PACKET_OFFSET,
DP_MON_DATA_BUFFER_SIZE,
false);
DP_STATS_INC(mon_soc, frag_free, 1);
buf_info = addr;
if (!ppdu_info->msdu[user_id].first_buffer) {
@@ -1007,7 +1066,6 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
buf_info->frag_len = packet_info->dma_length;
}
if (qdf_unlikely(packet_info->truncated))
mpdu_info->truncated = true;
}
@@ -1082,7 +1140,7 @@ uint8_t dp_rx_mon_process_tlv_status(struct dp_pdev *pdev,
mpdu_meta->overflow_err = mpdu_info->overflow_err;
mpdu_meta->decrypt_err = mpdu_info->decrypt_err;
mpdu_meta->full_pkt = mpdu_info->full_pkt;
num_frags = qdf_nbuf_get_nr_frags(nbuf);
mpdu_meta->truncated = mpdu_info->truncated;
num_frags = qdf_nbuf_get_nr_frags(nbuf);
ppdu_info->mpdu_q[user_id][mpdu_idx] = nbuf;
@@ -1188,6 +1246,8 @@ dp_rx_mon_process_status_tlv(struct dp_pdev *pdev)
mon_pdev_be->desc_count--;
qdf_frag_free(buf);
DP_STATS_INC(mon_soc, frag_free, 1);
mon_pdev->rx_mon_stats.status_buf_count++;
}
if (work_done) {
@@ -1312,6 +1372,7 @@ dp_rx_mon_srng_process_2_0(struct dp_soc *soc, struct dp_intr *int_ctx,
mon_pdev);
rx_mon_dst_ring_desc =
hal_srng_dst_get_next(hal_soc, mon_dst_srng);
mon_pdev->rx_mon_stats.empty_desc_ppdu++;
continue;
}
mon_desc = (struct dp_mon_desc *)(uintptr_t)(hal_mon_rx_desc.buf_addr);
@@ -1343,6 +1404,7 @@ dp_rx_mon_srng_process_2_0(struct dp_soc *soc, struct dp_intr *int_ctx,
hal_mon_rx_desc.end_reason == HAL_MON_PPDU_TRUNCATED) {
dp_mon_debug("end_resaon: %d mon_pdev: %pK",
hal_mon_rx_desc.end_reason, mon_pdev);
mon_pdev->rx_mon_stats.status_ppdu_drop++;
dp_rx_mon_handle_flush_n_trucated_ppdu(soc,
pdev,
mon_desc);

Voir le fichier

@@ -827,6 +827,7 @@ dp_print_pdev_rx_mon_stats(struct dp_pdev *pdev)
uint32_t *dest_ring_ppdu_ids;
int i, idx;
struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
struct dp_mon_soc *mon_soc = pdev->soc->monitor_soc;
rx_mon_stats = &mon_pdev->rx_mon_stats;
@@ -903,6 +904,22 @@ dp_print_pdev_rx_mon_stats(struct dp_pdev *pdev)
DP_PRINT_STATS("mon_rx_dest_stuck = %d",
rx_mon_stats->mon_rx_dest_stuck);
DP_PRINT_STATS("rx_hdr_not_received = %d",
rx_mon_stats->rx_hdr_not_received);
DP_PRINT_STATS("parent_buf_alloc = %d",
rx_mon_stats->parent_buf_alloc);
DP_PRINT_STATS("parent_buf_free = %d",
rx_mon_stats->parent_buf_free);
DP_PRINT_STATS("mpdus_buf_to_stack = %d",
rx_mon_stats->mpdus_buf_to_stack);
DP_PRINT_STATS("frag_alloc = %d",
mon_soc->stats.frag_alloc);
DP_PRINT_STATS("frag_free = %d",
mon_soc->stats.frag_free);
DP_PRINT_STATS("status_buf_count = %d",
rx_mon_stats->status_buf_count);
DP_PRINT_STATS("pkt_buf_count = %d",
rx_mon_stats->pkt_buf_count);
dp_pdev_get_undecoded_capture_stats(mon_pdev, rx_mon_stats);
}

Voir le fichier

@@ -785,6 +785,16 @@ struct dp_mon_ops {
(struct dp_soc *soc, struct dp_mon_pdev *mon_pdev);
};
/**
* struct dp_mon_soc_stats - monitor stats
* @frag_alloc: Number of frags allocated
* @frag_free: Number of frags freed
*/
struct dp_mon_soc_stats {
uint32_t frag_alloc;
uint32_t frag_free;
};
struct dp_mon_soc {
/* Holds all monitor related fields extracted from dp_soc */
/* Holds pointer to monitor ops */
@@ -828,6 +838,8 @@ struct dp_mon_soc {
#ifdef WLAN_TX_PKT_CAPTURE_ENH
struct dp_soc_tx_capture dp_soc_tx_capt;
#endif
/* monitor stats */
struct dp_mon_soc_stats stats;
};
#ifdef WLAN_TELEMETRY_STATS_SUPPORT

Voir le fichier

@@ -1819,7 +1819,8 @@ hal_rx_status_get_mon_buf_addr(uint8_t *rx_tlv,
ppdu_info->packet_info.sw_cookie = (((uint64_t)addr->buffer_virt_addr_63_32 << 32) |
(addr->buffer_virt_addr_31_0));
ppdu_info->packet_info.dma_length = addr->dma_length;
/* HW DMA length is '-1' of actual DMA length*/
ppdu_info->packet_info.dma_length = addr->dma_length + 1;
ppdu_info->packet_info.msdu_continuation = addr->msdu_continuation;
ppdu_info->packet_info.truncated = addr->truncated;