qcacmn: Add linked list logic to store per ppdu descriptor status tlv

Add linked list logic to hold all ppdu descriptor status in a list till
all TLVs have been processed
This design handles asynchronous arrival of tlvs from fw per ppdu

Change-Id: Ib8943d7c826c0b441f58f0eaba7ae0bdc0539d9a
This commit is contained in:
Anish Nataraj 2018-02-16 00:38:10 +05:30 • committed by nshrivas
commit b9e7d01e52
4 changed files with 383 additions and 153 deletions

View file

@ -903,6 +903,8 @@ struct cdp_tx_completion_ppdu_user {
* @num_users: Number of users
* @num_mpdu: Number of MPDUs in PPDU
* @num_msdu: Number of MSDUs in PPDU
* @frame_type: frame SU or MU
* @frame_ctrl: frame control of 80211 header
* @channel: Channel informartion
* @ack_rssi: RSSI value of last ack packet (units=dB above noise floor)
* @tx_duration: PPDU airtime
@ -918,6 +920,7 @@ struct cdp_tx_completion_ppdu {
uint32_t num_mpdu:9,
num_msdu:16;
uint16_t frame_type;
uint16_t frame_ctrl;
uint16_t channel;
uint16_t phy_mode;
uint32_t ack_rssi;

View file

@ -47,6 +47,33 @@ do { \
} while (0)
#define HTT_MGMT_CTRL_TLV_RESERVERD_LEN 12
/**
* Bitmap of HTT PPDU TLV types for Default mode
*/
#define HTT_PPDU_DEFAULT_TLV_BITMAP \
(1 << HTT_PPDU_STATS_COMMON_TLV) | \
(1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \
(1 << HTT_PPDU_STATS_USR_RATE_TLV) | \
(1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \
(1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \
(1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV)
/**
* Bitmap of HTT PPDU TLV types for Sniffer mode
*/
#define HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP \
(1 << HTT_PPDU_STATS_COMMON_TLV) | \
(1 << HTT_PPDU_STATS_USR_COMMON_TLV) | \
(1 << HTT_PPDU_STATS_USR_RATE_TLV) | \
(1 << HTT_PPDU_STATS_SCH_CMD_STATUS_TLV) | \
(1 << HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV) | \
(1 << HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) | \
(1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_64_TLV) | \
(1 << HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_64_TLV) | \
(1 << HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_256_TLV)
#define HTT_FRAMECTRL_DATATYPE 0x08
#define HTT_PPDU_DESC_MAX_DEPTH 16
/*
* dp_tx_stats_update() - Update per-peer statistics
@ -1538,24 +1565,26 @@ void htt_t2h_stats_handler(void *context)
}
/*
* dp_get_ppdu_info_user_index: Find place holder for the received
* ppdu stats info
* dp_get_ppdu_info_user_index: Find and allocate a per-user descriptor for a PPDU,
* if a new peer id arrives in a PPDU
* pdev: DP pdev handle
* @peer_id : peer unique identifier
* @ppdu_info: per ppdu tlv structure
*
* return:user index to be populated
*/
#ifdef FEATURE_PERPKT_INFO
static uint8_t dp_get_ppdu_info_user_index(struct dp_pdev *pdev,
uint16_t peer_id)
uint16_t peer_id,
struct ppdu_info *ppdu_info)
{
uint8_t user_index = 0;
struct cdp_tx_completion_ppdu *ppdu_desc;
struct cdp_tx_completion_ppdu_user *ppdu_user_desc;
ppdu_desc =
(struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
while ((user_index + 1) <= pdev->tx_ppdu_info.last_user) {
while ((user_index + 1) <= ppdu_info->last_user) {
ppdu_user_desc = &ppdu_desc->user[user_index];
if (ppdu_user_desc->peer_id != peer_id) {
user_index++;
@ -1569,33 +1598,30 @@ static uint8_t dp_get_ppdu_info_user_index(struct dp_pdev *pdev,
}
}
pdev->tx_ppdu_info.last_user++;
ppdu_info->last_user++;
/* Max users possible is 8 so last user should not exceed 8 */
qdf_assert_always(pdev->tx_ppdu_info.last_user <= CDP_MU_MAX_USERS);
return pdev->tx_ppdu_info.last_user - 1;
qdf_assert_always(ppdu_info->last_user <= CDP_MU_MAX_USERS);
return ppdu_info->last_user - 1;
}
/*
* dp_process_ppdu_stats_common_tlv: Process htt_ppdu_stats_common_tlv
* pdev: DP pdev handle
* @tag_buf: buffer containing the tlv htt_ppdu_stats_common_tlv
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_common_tlv(struct dp_pdev *pdev,
uint32_t *tag_buf)
uint32_t *tag_buf, struct ppdu_info *ppdu_info)
{
uint16_t frame_type;
uint16_t freq;
struct dp_soc *soc = NULL;
struct cdp_tx_completion_ppdu *ppdu_desc;
htt_ppdu_stats_common_tlv *dp_stats_buf =
(htt_ppdu_stats_common_tlv *)tag_buf;
struct cdp_tx_completion_ppdu *ppdu_desc = NULL;
ppdu_desc =
(struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
ppdu_desc->ppdu_id = dp_stats_buf->ppdu_id;
tag_buf += 2;
ppdu_desc->num_users =
HTT_PPDU_STATS_COMMON_TLV_NUM_USERS_GET(*tag_buf);
@ -1633,11 +1659,13 @@ static void dp_process_ppdu_stats_common_tlv(struct dp_pdev *pdev,
/*
* dp_process_ppdu_stats_user_common_tlv: Process ppdu_stats_user_common
* @tag_buf: buffer containing the tlv htt_ppdu_stats_user_common_tlv
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_user_common_tlv(
struct dp_pdev *pdev, uint32_t *tag_buf)
struct dp_pdev *pdev, uint32_t *tag_buf,
struct ppdu_info *ppdu_info)
{
uint16_t peer_id;
struct dp_peer *peer;
@ -1645,8 +1673,7 @@ static void dp_process_ppdu_stats_user_common_tlv(
struct cdp_tx_completion_ppdu_user *ppdu_user_desc;
uint8_t curr_user_index = 0;
ppdu_desc =
(struct cdp_tx_completion_ppdu *) qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
tag_buf++;
peer_id = HTT_PPDU_STATS_USER_COMMON_TLV_SW_PEER_ID_GET(*tag_buf);
@ -1655,7 +1682,7 @@ static void dp_process_ppdu_stats_user_common_tlv(
if (!peer)
return;
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id);
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info);
ppdu_user_desc = &ppdu_desc->user[curr_user_index];
ppdu_user_desc->peer_id = peer_id;
@ -1677,6 +1704,7 @@ static void dp_process_ppdu_stats_user_common_tlv(
HTT_PPDU_STATS_USER_COMMON_TLV_QOS_CTRL_GET(*tag_buf);
ppdu_user_desc->frame_ctrl =
HTT_PPDU_STATS_USER_COMMON_TLV_FRAME_CTRL_GET(*tag_buf);
ppdu_desc->frame_ctrl = ppdu_user_desc->frame_ctrl;
}
@ -1684,11 +1712,13 @@ static void dp_process_ppdu_stats_user_common_tlv(
* dp_process_ppdu_stats_user_rate_tlv() - Process htt_ppdu_stats_user_rate_tlv
* @pdev: DP pdev handle
* @tag_buf: T2H message buffer carrying the user rate TLV
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_user_rate_tlv(struct dp_pdev *pdev,
uint32_t *tag_buf)
uint32_t *tag_buf,
struct ppdu_info *ppdu_info)
{
uint16_t peer_id;
struct dp_peer *peer;
@ -1696,8 +1726,7 @@ static void dp_process_ppdu_stats_user_rate_tlv(struct dp_pdev *pdev,
struct cdp_tx_completion_ppdu_user *ppdu_user_desc;
uint8_t curr_user_index = 0;
ppdu_desc =
(struct cdp_tx_completion_ppdu *) qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
tag_buf++;
peer_id = HTT_PPDU_STATS_USER_RATE_TLV_SW_PEER_ID_GET(*tag_buf);
@ -1706,7 +1735,7 @@ static void dp_process_ppdu_stats_user_rate_tlv(struct dp_pdev *pdev,
if (!peer)
return;
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id);
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info);
ppdu_user_desc = &ppdu_desc->user[curr_user_index];
ppdu_user_desc->peer_id = peer_id;
@ -1754,11 +1783,13 @@ static void dp_process_ppdu_stats_user_rate_tlv(struct dp_pdev *pdev,
* htt_ppdu_stats_enq_mpdu_bitmap_64_tlv
* pdev: DP PDEV handle
* @tag_buf: buffer containing the tlv htt_ppdu_stats_enq_mpdu_bitmap_64_tlv
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv(
struct dp_pdev *pdev, uint32_t *tag_buf)
struct dp_pdev *pdev, uint32_t *tag_buf,
struct ppdu_info *ppdu_info)
{
htt_ppdu_stats_enq_mpdu_bitmap_64_tlv *dp_stats_buf =
(htt_ppdu_stats_enq_mpdu_bitmap_64_tlv *)tag_buf;
@ -1769,8 +1800,7 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv(
uint16_t peer_id;
struct dp_peer *peer;
ppdu_desc =
(struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
tag_buf++;
@ -1782,7 +1812,7 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv(
if (!peer)
return;
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id);
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info);
ppdu_user_desc = &ppdu_desc->user[curr_user_index];
ppdu_user_desc->peer_id = peer_id;
@ -1797,11 +1827,13 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv(
* htt_ppdu_stats_enq_mpdu_bitmap_256_tlv
* soc: DP SOC handle
* @tag_buf: buffer containing the tlv htt_ppdu_stats_enq_mpdu_bitmap_256_tlv
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv(
struct dp_pdev *pdev, uint32_t *tag_buf)
struct dp_pdev *pdev, uint32_t *tag_buf,
struct ppdu_info *ppdu_info)
{
htt_ppdu_stats_enq_mpdu_bitmap_256_tlv *dp_stats_buf =
(htt_ppdu_stats_enq_mpdu_bitmap_256_tlv *)tag_buf;
@ -1812,8 +1844,7 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv(
uint16_t peer_id;
struct dp_peer *peer;
ppdu_desc =
(struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
tag_buf++;
@ -1825,7 +1856,7 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv(
if (!peer)
return;
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id);
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info);
ppdu_user_desc = &ppdu_desc->user[curr_user_index];
ppdu_user_desc->peer_id = peer_id;
@ -1840,11 +1871,13 @@ static void dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv(
* htt_ppdu_stats_user_cmpltn_common_tlv
* soc: DP SOC handle
* @tag_buf: buffer containing the tlv htt_ppdu_stats_user_cmpltn_common_tlv
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_user_cmpltn_common_tlv(
struct dp_pdev *pdev, uint32_t *tag_buf)
struct dp_pdev *pdev, uint32_t *tag_buf,
struct ppdu_info *ppdu_info)
{
uint16_t peer_id;
struct dp_peer *peer;
@ -1854,8 +1887,7 @@ static void dp_process_ppdu_stats_user_cmpltn_common_tlv(
htt_ppdu_stats_user_cmpltn_common_tlv *dp_stats_buf =
(htt_ppdu_stats_user_cmpltn_common_tlv *)tag_buf;
ppdu_desc =
(struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
tag_buf++;
peer_id =
@ -1865,7 +1897,7 @@ static void dp_process_ppdu_stats_user_cmpltn_common_tlv(
if (!peer)
return;
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id);
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info);
ppdu_user_desc = &ppdu_desc->user[curr_user_index];
ppdu_user_desc->peer_id = peer_id;
@ -1897,6 +1929,7 @@ static void dp_process_ppdu_stats_user_cmpltn_common_tlv(
ppdu_user_desc->is_ampdu =
HTT_PPDU_STATS_USER_CMPLTN_COMMON_TLV_IS_AMPDU_GET(*tag_buf);
ppdu_info->is_ampdu = ppdu_user_desc->is_ampdu;
}
@ -1905,11 +1938,13 @@ static void dp_process_ppdu_stats_user_cmpltn_common_tlv(
* htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv
* pdev: DP PDEV handle
* @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv(
struct dp_pdev *pdev, uint32_t *tag_buf)
struct dp_pdev *pdev, uint32_t *tag_buf,
struct ppdu_info *ppdu_info)
{
htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv *dp_stats_buf =
(htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv *)tag_buf;
@ -1919,8 +1954,7 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv(
uint16_t peer_id;
struct dp_peer *peer;
ppdu_desc =
(struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
tag_buf++;
@ -1932,7 +1966,7 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv(
if (!peer)
return;
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id);
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info);
ppdu_user_desc = &ppdu_desc->user[curr_user_index];
ppdu_user_desc->peer_id = peer_id;
@ -1947,11 +1981,13 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv(
* htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv
* pdev: DP PDEV handle
* @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv(
struct dp_pdev *pdev, uint32_t *tag_buf)
struct dp_pdev *pdev, uint32_t *tag_buf,
struct ppdu_info *ppdu_info)
{
htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv *dp_stats_buf =
(htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv *)tag_buf;
@ -1961,8 +1997,7 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv(
uint16_t peer_id;
struct dp_peer *peer;
ppdu_desc =
(struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
tag_buf++;
@ -1974,7 +2009,7 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv(
if (!peer)
return;
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id);
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info);
ppdu_user_desc = &ppdu_desc->user[curr_user_index];
ppdu_user_desc->peer_id = peer_id;
@ -1989,11 +2024,13 @@ static void dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv(
* htt_ppdu_stats_user_compltn_ack_ba_status_tlv
* pdev: DP PDE handle
* @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ack_ba_status_tlv
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv(
struct dp_pdev *pdev, uint32_t *tag_buf)
struct dp_pdev *pdev, uint32_t *tag_buf,
struct ppdu_info *ppdu_info)
{
uint16_t peer_id;
struct dp_peer *peer;
@ -2001,29 +2038,31 @@ static void dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv(
struct cdp_tx_completion_ppdu_user *ppdu_user_desc;
uint8_t curr_user_index = 0;
ppdu_desc =
(struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
tag_buf += 2;
peer_id =
HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_SW_PEER_ID_GET(*tag_buf);
peer = dp_peer_find_by_id(pdev->soc, peer_id);
if (!peer)
return;
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id);
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info);
ppdu_user_desc = &ppdu_desc->user[curr_user_index];
ppdu_user_desc->peer_id = peer_id;
tag_buf++;
ppdu_user_desc->tid =
HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_TID_NUM_GET(*tag_buf);
ppdu_user_desc->num_mpdu =
HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MPDU_GET(*tag_buf);
HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MPDU_GET(*tag_buf);
ppdu_user_desc->num_msdu =
HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MSDU_GET(*tag_buf);
HTT_PPDU_STATS_USER_CMPLTN_ACK_BA_STATUS_TLV_NUM_MSDU_GET(*tag_buf);
ppdu_user_desc->success_msdus = ppdu_user_desc->num_msdu;
@ -2037,11 +2076,13 @@ static void dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv(
* htt_ppdu_stats_user_common_array_tlv
* pdev: DP PDEV handle
* @tag_buf: buffer containing the htt_ppdu_stats_user_compltn_ack_ba_status_tlv
* @ppdu_info: per ppdu tlv structure
*
* return:void
*/
static void dp_process_ppdu_stats_user_common_array_tlv(struct dp_pdev *pdev,
uint32_t *tag_buf)
static void dp_process_ppdu_stats_user_common_array_tlv(
struct dp_pdev *pdev, uint32_t *tag_buf,
struct ppdu_info *ppdu_info)
{
uint32_t peer_id;
struct dp_peer *peer;
@ -2050,8 +2091,7 @@ static void dp_process_ppdu_stats_user_common_array_tlv(struct dp_pdev *pdev,
uint8_t curr_user_index = 0;
struct htt_tx_ppdu_stats_info *dp_stats_buf;
ppdu_desc =
(struct cdp_tx_completion_ppdu *)qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)qdf_nbuf_data(ppdu_info->nbuf);
tag_buf++;
dp_stats_buf = (struct htt_tx_ppdu_stats_info *)tag_buf;
@ -2067,7 +2107,7 @@ static void dp_process_ppdu_stats_user_common_array_tlv(struct dp_pdev *pdev,
return;
}
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id);
curr_user_index = dp_get_ppdu_info_user_index(pdev, peer_id, ppdu_info);
ppdu_user_desc = &ppdu_desc->user[curr_user_index];
@ -2167,94 +2207,275 @@ static void dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv(
/**
* dp_process_ppdu_tag(): Function to process the PPDU TLVs
* @soc: DP Physical device (radio) handle
* @pdev: DP pdev handle
* @tag_buf: TLV buffer
* @tlv_len: length of tlv
* @ppdu_info: per ppdu tlv structure
*
* return: void
*/
static void dp_process_ppdu_tag(struct dp_pdev *pdev, uint32_t *tag_buf,
uint32_t tlv_len)
uint32_t tlv_len, struct ppdu_info *ppdu_info)
{
uint32_t tlv_type = HTT_STATS_TLV_TAG_GET(*tag_buf);
switch (tlv_type) {
case HTT_PPDU_STATS_COMMON_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_common_tlv));
dp_process_ppdu_stats_common_tlv(pdev, tag_buf);
dp_process_ppdu_stats_common_tlv(pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_COMMON_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_user_common_tlv));
dp_process_ppdu_stats_user_common_tlv(pdev, tag_buf);
dp_process_ppdu_stats_user_common_tlv(
pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_RATE_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_user_rate_tlv));
dp_process_ppdu_stats_user_rate_tlv(pdev, tag_buf);
dp_process_ppdu_stats_user_rate_tlv(pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_64_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_enq_mpdu_bitmap_64_tlv));
dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv(pdev, tag_buf);
dp_process_ppdu_stats_enq_mpdu_bitmap_64_tlv(
pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_MPDU_ENQ_BITMAP_256_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_enq_mpdu_bitmap_256_tlv));
dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv(pdev, tag_buf);
dp_process_ppdu_stats_enq_mpdu_bitmap_256_tlv(
pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_COMPLTN_COMMON_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_user_cmpltn_common_tlv));
dp_process_ppdu_stats_user_cmpltn_common_tlv(pdev, tag_buf);
dp_process_ppdu_stats_user_cmpltn_common_tlv(
pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_64_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_user_compltn_ba_bitmap_64_tlv));
dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv(pdev,
tag_buf);
dp_process_ppdu_stats_user_compltn_ba_bitmap_64_tlv(
pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_COMPLTN_BA_BITMAP_256_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_user_compltn_ba_bitmap_256_tlv));
dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv(pdev,
tag_buf);
dp_process_ppdu_stats_user_compltn_ba_bitmap_256_tlv(
pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_user_compltn_ack_ba_status_tlv));
dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv(pdev,
tag_buf);
dp_process_ppdu_stats_user_compltn_ack_ba_status_tlv(
pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_COMMON_ARRAY_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_usr_common_array_tlv_v));
dp_process_ppdu_stats_user_common_array_tlv(pdev,
tag_buf);
dp_process_ppdu_stats_user_common_array_tlv(
pdev, tag_buf, ppdu_info);
break;
case HTT_PPDU_STATS_USR_COMPLTN_FLUSH_TLV:
qdf_assert_always(tlv_len ==
sizeof(htt_ppdu_stats_flush_tlv));
dp_process_ppdu_stats_user_compltn_flush_tlv(pdev,
tag_buf);
dp_process_ppdu_stats_user_compltn_flush_tlv(
pdev, tag_buf);
break;
case HTT_PPDU_STATS_TX_MGMTCTRL_PAYLOAD_TLV:
dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv(pdev,
tag_buf, tlv_len);
dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv(
pdev, tag_buf, tlv_len);
break;
default:
break;
}
}
static QDF_STATUS dp_htt_process_tlv(struct dp_pdev *pdev,
/**
* dp_ppdu_desc_deliver(): Function to deliver Tx PPDU status descriptor
* to upper layer
* @pdev: DP pdev handle
* @ppdu_info: per PPDU TLV descriptor
*
* return: void
*/
static
void dp_ppdu_desc_deliver(struct dp_pdev *pdev,
struct ppdu_info *ppdu_info)
{
struct cdp_tx_completion_ppdu *ppdu_desc = NULL;
struct dp_peer *peer = NULL;
qdf_nbuf_t nbuf;
uint16_t i;
ppdu_desc = (struct cdp_tx_completion_ppdu *)
qdf_nbuf_data(ppdu_info->nbuf);
ppdu_desc->num_users = ppdu_info->last_user;
ppdu_desc->ppdu_id = ppdu_info->ppdu_id;
for (i = 0; i < ppdu_desc->num_users; i++) {
ppdu_desc->num_mpdu += ppdu_desc->user[i].num_mpdu;
ppdu_desc->num_msdu += ppdu_desc->user[i].num_msdu;
if (ppdu_desc->user[i].tid < CDP_DATA_TID_MAX) {
peer = dp_peer_find_by_id(pdev->soc,
ppdu_desc->user[i].peer_id);
/**
* This check is to make sure peer is not deleted
* after processing the TLVs.
*/
if (!peer)
continue;
dp_tx_stats_update(pdev->soc, peer,
&ppdu_desc->user[i],
ppdu_desc->ack_rssi);
}
}
/*
* Remove from the list
*/
TAILQ_REMOVE(&pdev->ppdu_info_list, ppdu_info, ppdu_info_list_elem);
nbuf = ppdu_info->nbuf;
pdev->list_depth--;
qdf_mem_free(ppdu_info);
qdf_assert_always(nbuf);
ppdu_desc = (struct cdp_tx_completion_ppdu *)
qdf_nbuf_data(nbuf);
/**
* Deliver PPDU stats only for valid (acked) data frames if
* sniffer mode is not enabled.
* If sniffer mode is enabled, PPDU stats for all frames
* including mgmt/control frames should be delivered to upper layer
*/
if (pdev->tx_sniffer_enable || pdev->mcopy_mode) {
dp_wdi_event_handler(WDI_EVENT_TX_PPDU_DESC, pdev->soc,
nbuf, HTT_INVALID_PEER,
WDI_NO_VAL, pdev->pdev_id);
} else {
if (ppdu_desc->num_mpdu != 0 && ppdu_desc->num_users != 0 &&
ppdu_desc->frame_ctrl & HTT_FRAMECTRL_DATATYPE) {
dp_wdi_event_handler(WDI_EVENT_TX_PPDU_DESC,
pdev->soc, nbuf, HTT_INVALID_PEER,
WDI_NO_VAL, pdev->pdev_id);
} else
qdf_nbuf_free(nbuf);
}
return;
}
/**
* dp_get_ppdu_desc(): Function to allocate new PPDU status
* desc for new ppdu id
* @pdev: DP pdev handle
* @ppdu_id: PPDU unique identifier
* @tlv_type: TLV type received
*
* return: ppdu_info per ppdu tlv structure
*/
static
struct ppdu_info *dp_get_ppdu_desc(struct dp_pdev *pdev, uint32_t ppdu_id,
uint8_t tlv_type)
{
struct ppdu_info *ppdu_info = NULL;
/*
* Find ppdu_id node exists or not
*/
TAILQ_FOREACH(ppdu_info, &pdev->ppdu_info_list, ppdu_info_list_elem) {
if (ppdu_info && (ppdu_info->ppdu_id == ppdu_id)) {
break;
}
}
if (ppdu_info) {
/**
* if we get tlv_type that is already been processed for ppdu,
* that means we got a new ppdu with same ppdu id.
* Hence Flush the older ppdu
*/
if (ppdu_info->tlv_bitmap & (1 << tlv_type))
dp_ppdu_desc_deliver(pdev, ppdu_info);
else
return ppdu_info;
}
/**
* Flush the head ppdu descriptor if ppdu desc list reaches max
* threshold
*/
if (pdev->list_depth > HTT_PPDU_DESC_MAX_DEPTH) {
ppdu_info = TAILQ_FIRST(&pdev->ppdu_info_list);
dp_ppdu_desc_deliver(pdev, ppdu_info);
}
/*
* Allocate new ppdu_info node
*/
ppdu_info = qdf_mem_malloc(sizeof(struct ppdu_info));
if (!ppdu_info)
return NULL;
ppdu_info->nbuf = qdf_nbuf_alloc(pdev->soc->osdev,
sizeof(struct cdp_tx_completion_ppdu), 0, 4,
TRUE);
if (!ppdu_info->nbuf) {
qdf_mem_free(ppdu_info);
return NULL;
}
qdf_mem_zero(qdf_nbuf_data(ppdu_info->nbuf),
sizeof(struct cdp_tx_completion_ppdu));
if (qdf_nbuf_put_tail(ppdu_info->nbuf,
sizeof(struct cdp_tx_completion_ppdu)) == NULL) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"No tailroom for HTT PPDU");
qdf_nbuf_free(ppdu_info->nbuf);
ppdu_info->nbuf = NULL;
ppdu_info->last_user = 0;
qdf_mem_free(ppdu_info);
return NULL;
}
/**
* No lock is needed because all PPDU TLVs are processed in
* same context and this list is updated in same context
*/
TAILQ_INSERT_TAIL(&pdev->ppdu_info_list, ppdu_info,
ppdu_info_list_elem);
pdev->list_depth++;
return ppdu_info;
}
/**
* dp_htt_process_tlv(): Function to process each PPDU TLVs
* @pdev: DP pdev handle
* @htt_t2h_msg: HTT target to host message
*
* return: ppdu_info per ppdu tlv structure
*/
static struct ppdu_info *dp_htt_process_tlv(struct dp_pdev *pdev,
qdf_nbuf_t htt_t2h_msg)
{
uint32_t length;
uint32_t ppdu_id;
uint8_t tlv_type;
uint32_t tlv_length;
uint32_t tlv_length, tlv_bitmap_expected;
uint8_t *tlv_buf;
QDF_STATUS status = QDF_STATUS_E_PENDING;
struct ppdu_info *ppdu_info = NULL;
uint32_t *msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg);
@ -2263,6 +2484,7 @@ static QDF_STATUS dp_htt_process_tlv(struct dp_pdev *pdev,
msg_word = msg_word + 1;
ppdu_id = HTT_T2H_PPDU_STATS_PPDU_ID_GET(*msg_word);
msg_word = msg_word + 3;
while (length > 0) {
tlv_buf = (uint8_t *)msg_word;
@ -2274,22 +2496,56 @@ static QDF_STATUS dp_htt_process_tlv(struct dp_pdev *pdev,
if (tlv_length == 0)
break;
if (tlv_type == HTT_PPDU_STATS_SCH_CMD_STATUS_TLV)
status = QDF_STATUS_SUCCESS;
if ((tlv_type == HTT_PPDU_STATS_USR_COMPLTN_ACK_BA_STATUS_TLV) &&
(pdev->last_ppdu_id != ppdu_id))
status = QDF_STATUS_SUCCESS;
tlv_length += HTT_TLV_HDR_LEN;
dp_process_ppdu_tag(pdev, msg_word, tlv_length);
/**
* Not allocating separate ppdu descriptor for MGMT Payload
* TLV as this is sent as separate WDI indication and it
* doesn't contain any ppdu information
*/
if (tlv_type == HTT_PPDU_STATS_TX_MGMTCTRL_PAYLOAD_TLV) {
dp_process_ppdu_tag(pdev, msg_word, tlv_length, NULL);
msg_word = (uint32_t *)((uint8_t *)tlv_buf + tlv_length);
length -= (tlv_length);
continue;
}
ppdu_info = dp_get_ppdu_desc(pdev, ppdu_id, tlv_type);
if (!ppdu_info)
return NULL;
ppdu_info->ppdu_id = ppdu_id;
ppdu_info->tlv_bitmap |= (1 << tlv_type);
dp_process_ppdu_tag(pdev, msg_word, tlv_length, ppdu_info);
/**
* Increment pdev level tlv count to monitor
* missing TLVs
*/
pdev->tlv_count++;
ppdu_info->last_tlv_cnt = pdev->tlv_count;
msg_word = (uint32_t *)((uint8_t *)tlv_buf + tlv_length);
length -= (tlv_length);
}
pdev->last_ppdu_id = ppdu_id;
return status;
tlv_bitmap_expected = HTT_PPDU_DEFAULT_TLV_BITMAP;
if (pdev->tx_sniffer_enable || pdev->mcopy_mode) {
if (ppdu_info->is_ampdu)
tlv_bitmap_expected = HTT_PPDU_SNIFFER_AMPDU_TLV_BITMAP;
}
/**
* Once all the TLVs for a given PPDU has been processed,
* return PPDU status to be delivered to higher layer
*/
if (ppdu_info->tlv_bitmap == tlv_bitmap_expected)
return ppdu_info;
return NULL;
}
#endif /* FEATURE_PERPKT_INFO */
@ -2307,78 +2563,15 @@ static void dp_txrx_ppdu_stats_handler(struct dp_soc *soc,
uint8_t pdev_id, qdf_nbuf_t htt_t2h_msg)
{
struct dp_pdev *pdev = soc->pdev_list[pdev_id];
struct dp_peer *peer;
struct cdp_tx_completion_ppdu *ppdu_desc;
int status;
int i;
struct ppdu_info *ppdu_info = NULL;
if (!pdev->enhanced_stats_en && !pdev->tx_sniffer_enable &&
!pdev->mcopy_mode)
return;
if (!pdev->tx_ppdu_info.buf) {
/*
* Todo: For MU/OFDMA, we need to account for multiple user
* descriptors in a PPDU, in skb size.
* The allocation has to be moved to ppdu_cmn tlv processing
*/
pdev->tx_ppdu_info.buf = qdf_nbuf_alloc(soc->osdev,
sizeof(struct cdp_tx_completion_ppdu), 0, 4,
TRUE);
if (!pdev->tx_ppdu_info.buf) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"Nbuf Allocation failed for HTT PPDU");
return;
}
qdf_mem_zero(qdf_nbuf_data(pdev->tx_ppdu_info.buf),
sizeof(struct cdp_tx_completion_ppdu));
if (qdf_nbuf_put_tail(pdev->tx_ppdu_info.buf,
sizeof(struct cdp_tx_completion_ppdu)) == NULL) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"No tailroom for HTT PPDU");
qdf_nbuf_free(pdev->tx_ppdu_info.buf);
pdev->tx_ppdu_info.buf = NULL;
pdev->tx_ppdu_info.last_user = 0;
return;
}
}
status = dp_htt_process_tlv(pdev, htt_t2h_msg);
if (status == QDF_STATUS_SUCCESS) {
ppdu_desc = (struct cdp_tx_completion_ppdu *)
qdf_nbuf_data(pdev->tx_ppdu_info.buf);
ppdu_desc->num_users = pdev->tx_ppdu_info.last_user;
for (i = 0; i < ppdu_desc->num_users; i++) {
peer = dp_peer_find_by_id(soc,
ppdu_desc->user[i].peer_id);
if (!peer)
continue;
ppdu_desc->num_mpdu += ppdu_desc->user[i].num_mpdu;
ppdu_desc->num_msdu += ppdu_desc->user[i].num_msdu;
if (ppdu_desc->user[i].tid < CDP_DATA_TID_MAX) {
dp_tx_stats_update(soc, peer,
&ppdu_desc->user[i],
ppdu_desc->ack_rssi);
}
}
dp_wdi_event_handler(WDI_EVENT_TX_PPDU_DESC, soc,
pdev->tx_ppdu_info.buf, HTT_INVALID_PEER,
WDI_NO_VAL, pdev_id);
pdev->tx_ppdu_info.buf = NULL;
pdev->tx_ppdu_info.last_user = 0;
}
ppdu_info = dp_htt_process_tlv(pdev, htt_t2h_msg);
if (ppdu_info)
dp_ppdu_desc_deliver(pdev, ppdu_info);
}
#else
static void dp_txrx_ppdu_stats_handler(struct dp_soc *soc,

View file

@ -2614,6 +2614,13 @@ static struct cdp_pdev *dp_pdev_attach_wifi3(struct cdp_soc_t *txrx_soc,
/* set the reo destination during initialization */
pdev->reo_dest = pdev->pdev_id + 1;
/*
* initialize ppdu tlv list
*/
TAILQ_INIT(&pdev->ppdu_info_list);
pdev->tlv_count = 0;
pdev->list_depth = 0;
return (struct cdp_pdev *)pdev;
fail1:

View file

@ -938,6 +938,29 @@ struct dp_neighbour_peer {
TAILQ_ENTRY(dp_neighbour_peer) neighbour_peer_list_elem;
};
/**
* struct ppdu_info - PPDU Status info descriptor
* @ppdu_id - Unique ppduid assigned by firmware for every tx packet
* @max_ppdu_id - wrap around for ppdu id
* @last_tlv_cnt - Keep track for missing ppdu tlvs
* @last_user - last ppdu processed for user
* @is_ampdu - set if Ampdu aggregate
* @nbuf - ppdu descriptor payload
* @ppdu_desc - ppdu descriptor
* @ppdu_info_list_elem - linked list of ppdu tlvs
*/
struct ppdu_info {
uint32_t ppdu_id;
uint32_t max_ppdu_id;
uint16_t tlv_bitmap;
uint16_t last_tlv_cnt;
uint16_t last_user:8,
is_ampdu:1;
qdf_nbuf_t nbuf;
struct cdp_tx_completion_ppdu *ppdu_desc;
TAILQ_ENTRY(ppdu_info) ppdu_info_list_elem;
};
/* PDEV level structure for data path */
struct dp_pdev {
/* PDEV handle from OSIF layer TBD: see if we really need osif_pdev */
@ -1133,6 +1156,10 @@ struct dp_pdev {
#ifdef ATH_SUPPORT_NAC_RSSI
bool nac_rssi_filtering;
#endif
/* list of ppdu tlvs */
TAILQ_HEAD(, ppdu_info) ppdu_info_list;
uint32_t tlv_count;
uint32_t list_depth;
};
struct dp_peer;