qcacmn: Add support for Extended Mcopy Mode

Currently, mcopy mode delivers first msdu(fcs_passed 128 bytes) per-ppdu
to upper layer, add support for Extended mcopy mode to deliver first
msdu(128 bytes) per-MPDU(fcs_passed).

Change-Id: Ib345fc14a8d468788b9de78516d27e8dff24caa4
CRs-Fixed: 2644175
This commit is contained in:
Himanshu Batra
2020-03-10 14:45:17 +05:30
committed by nshrivas
parent a3f17ee459
commit 879fd03fe1
6 changed files with 234 additions and 140 deletions

View File

@@ -4591,7 +4591,6 @@ static void dp_pdev_deinit(struct cdp_pdev *txrx_pdev, int force)
dp_tx_ppdu_stats_detach(pdev);
qdf_nbuf_free(pdev->sojourn_buf);
qdf_nbuf_queue_free(&pdev->rx_ppdu_buf_q);
dp_cal_client_detach(&pdev->cal_client_ctx);
@@ -7231,10 +7230,9 @@ QDF_STATUS dp_monitor_mode_ring_config(struct dp_soc *soc, uint8_t mac_for_pdev,
static inline void
dp_pdev_disable_mcopy_code(struct dp_pdev *pdev)
{
pdev->mcopy_mode = 0;
pdev->mcopy_mode = M_COPY_DISABLED;
pdev->monitor_configured = false;
pdev->monitor_vdev = NULL;
qdf_nbuf_queue_free(&pdev->rx_ppdu_buf_q);
}
/**
@@ -8236,7 +8234,6 @@ dp_config_debug_sniffer(struct dp_pdev *pdev, int val)
}
#endif /* FEATURE_PERPKT_INFO */
}
switch (val) {
case 0:
pdev->tx_sniffer_enable = 0;
@@ -8274,13 +8271,14 @@ dp_config_debug_sniffer(struct dp_pdev *pdev, int val)
DP_PPDU_STATS_CFG_SNIFFER, pdev->pdev_id);
break;
case 2:
case 4:
if (pdev->monitor_vdev) {
status = QDF_STATUS_E_RESOURCES;
break;
}
#ifdef FEATURE_PERPKT_INFO
pdev->mcopy_mode = 1;
pdev->mcopy_mode = val;
pdev->tx_sniffer_enable = 0;
pdev->monitor_configured = true;

View File

@@ -605,6 +605,7 @@ void dp_mon_filter_setup_mcopy_mode(struct dp_pdev *pdev)
/* Setup the filter */
filter.tlv_filter.enable_mo = 1;
filter.tlv_filter.packet_header = 1;
filter.tlv_filter.mpdu_end = 1;
dp_mon_filter_show_filter(pdev, mode, &filter);
srng_type = DP_MON_FILTER_SRNG_TYPE_RXDMA_MONITOR_STATUS;

View File

@@ -695,87 +695,14 @@ static void dp_rx_stats_update(struct dp_pdev *pdev,
}
#endif
/*
* dp_rx_get_fcs_ok_msdu() - get ppdu status buffer containing fcs_ok msdu
* @pdev: pdev object
* @ppdu_info: ppdu info object
*
* Return: nbuf
*/
static inline qdf_nbuf_t
dp_rx_get_fcs_ok_msdu(struct dp_pdev *pdev,
struct hal_rx_ppdu_info *ppdu_info)
{
uint16_t mpdu_fcs_ok;
qdf_nbuf_t status_nbuf = NULL;
unsigned long *fcs_ok_bitmap;
if (qdf_unlikely(qdf_nbuf_is_queue_empty(&pdev->rx_ppdu_buf_q)))
return NULL;
/* Obtain fcs_ok passed index from bitmap
* this index is used to get fcs passed first msdu payload
*/
fcs_ok_bitmap =
(unsigned long *)&ppdu_info->com_info.mpdu_fcs_ok_bitmap[0];
mpdu_fcs_ok = qdf_find_first_bit(fcs_ok_bitmap,
HAL_RX_MAX_MPDU);
if (qdf_unlikely(mpdu_fcs_ok >= HAL_RX_MAX_MPDU))
goto end;
if (qdf_unlikely(!ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].nbuf))
goto end;
/* Get status buffer by indexing mpdu_fcs_ok index
* containing first msdu payload with fcs passed
* and clone the buffer
*/
status_nbuf = ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].nbuf;
ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].nbuf = NULL;
/* Take ref of status nbuf as this nbuf is to be
* freeed by upper layer.
*/
qdf_nbuf_ref(status_nbuf);
ppdu_info->fcs_ok_msdu_info.first_msdu_payload =
ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].first_msdu_payload;
ppdu_info->fcs_ok_msdu_info.payload_len =
ppdu_info->ppdu_msdu_info[mpdu_fcs_ok].payload_len;
end:
/* Free the ppdu status buffer queue */
qdf_nbuf_queue_free(&pdev->rx_ppdu_buf_q);
qdf_mem_zero(&ppdu_info->ppdu_msdu_info,
(ppdu_info->com_info.mpdu_cnt_fcs_ok +
ppdu_info->com_info.mpdu_cnt_fcs_err)
* sizeof(struct hal_rx_msdu_payload_info));
return status_nbuf;
}
static inline void
dp_rx_handle_ppdu_status_buf(struct dp_pdev *pdev,
struct hal_rx_ppdu_info *ppdu_info,
qdf_nbuf_t status_nbuf)
{
qdf_nbuf_t dropnbuf;
if (qdf_nbuf_queue_len(&pdev->rx_ppdu_buf_q) >
HAL_RX_MAX_MPDU) {
dropnbuf = qdf_nbuf_queue_remove(&pdev->rx_ppdu_buf_q);
qdf_nbuf_free(dropnbuf);
}
qdf_nbuf_queue_add(&pdev->rx_ppdu_buf_q, status_nbuf);
}
/**
* dp_rx_handle_mcopy_mode() - Allocate and deliver first MSDU payload
* @soc: core txrx main context
* @pdev: pdev strcuture
* @pdev: pdev structure
* @ppdu_info: structure for rx ppdu ring
* @nbuf: QDF nbuf
* @fcs_ok_mpdu_cnt: fcs passsed mpdu index
* @deliver_frame: flag to deliver wdi event
*
* Return: QDF_STATUS_SUCCESS - If nbuf to be freed by caller
* QDF_STATUS_E_ALREADY - If nbuf not to be freed by caller
@@ -783,24 +710,25 @@ dp_rx_handle_ppdu_status_buf(struct dp_pdev *pdev,
#ifdef FEATURE_PERPKT_INFO
static inline QDF_STATUS
dp_rx_handle_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev,
struct hal_rx_ppdu_info *ppdu_info, qdf_nbuf_t nbuf)
struct hal_rx_ppdu_info *ppdu_info, qdf_nbuf_t nbuf,
uint8_t fcs_ok_mpdu_cnt, bool deliver_frame)
{
uint8_t size = 0;
uint16_t size = 0;
struct ieee80211_frame *wh;
uint32_t *nbuf_data;
if (!ppdu_info->fcs_ok_msdu_info.first_msdu_payload)
if (!ppdu_info->ppdu_msdu_info[fcs_ok_mpdu_cnt].first_msdu_payload)
return QDF_STATUS_SUCCESS;
if (pdev->m_copy_id.rx_ppdu_id == ppdu_info->com_info.ppdu_id)
return QDF_STATUS_SUCCESS;
/* For M_COPY mode only one msdu per ppdu is sent to upper layer*/
if (pdev->mcopy_mode == M_COPY) {
if (pdev->m_copy_id.rx_ppdu_id == ppdu_info->com_info.ppdu_id)
return QDF_STATUS_SUCCESS;
}
pdev->m_copy_id.rx_ppdu_id = ppdu_info->com_info.ppdu_id;
wh = (struct ieee80211_frame *)(ppdu_info->ppdu_msdu_info[fcs_ok_mpdu_cnt].first_msdu_payload + 4);
wh = (struct ieee80211_frame *)
(ppdu_info->fcs_ok_msdu_info.first_msdu_payload + 4);
size = (ppdu_info->fcs_ok_msdu_info.first_msdu_payload -
size = (ppdu_info->ppdu_msdu_info[fcs_ok_mpdu_cnt].first_msdu_payload -
qdf_nbuf_data(nbuf));
if (qdf_nbuf_pull_head(nbuf, size) == NULL)
@@ -813,25 +741,163 @@ dp_rx_handle_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev,
return QDF_STATUS_SUCCESS;
}
ppdu_info->fcs_ok_msdu_info.first_msdu_payload = NULL;
nbuf_data = (uint32_t *)qdf_nbuf_data(nbuf);
*nbuf_data = pdev->ppdu_info.com_info.ppdu_id;
/* only retain RX MSDU payload in the skb */
qdf_nbuf_trim_tail(nbuf, qdf_nbuf_len(nbuf) -
ppdu_info->fcs_ok_msdu_info.payload_len);
dp_wdi_event_handler(WDI_EVENT_RX_DATA, soc,
nbuf, HTT_INVALID_PEER, WDI_NO_VAL, pdev->pdev_id);
qdf_nbuf_trim_tail(nbuf, qdf_nbuf_len(nbuf) - ppdu_info->ppdu_msdu_info[fcs_ok_mpdu_cnt].payload_len);
if (deliver_frame) {
pdev->m_copy_id.rx_ppdu_id = ppdu_info->com_info.ppdu_id;
dp_wdi_event_handler(WDI_EVENT_RX_DATA, soc,
nbuf, HTT_INVALID_PEER,
WDI_NO_VAL, pdev->pdev_id);
}
return QDF_STATUS_E_ALREADY;
}
#else
static inline QDF_STATUS
dp_rx_handle_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev,
struct hal_rx_ppdu_info *ppdu_info, qdf_nbuf_t nbuf)
struct hal_rx_ppdu_info *ppdu_info, qdf_nbuf_t nbuf,
uint8_t fcs_ok_cnt, bool deliver_frame)
{
return QDF_STATUS_SUCCESS;
}
#endif
/**
* dp_rx_mcopy_handle_last_mpdu() - cache and delive last MPDU header in a
* status buffer if MPDU end tlv is received in different buffer
* @soc: core txrx main context
* @pdev: pdev structure
* @ppdu_info: structure for rx ppdu ring
* @status_nbuf: QDF nbuf
*
* Return: void
*/
#ifdef FEATURE_PERPKT_INFO
static inline void
dp_rx_mcopy_handle_last_mpdu(struct dp_soc *soc, struct dp_pdev *pdev,
struct hal_rx_ppdu_info *ppdu_info,
qdf_nbuf_t status_nbuf)
{
QDF_STATUS mcopy_status;
qdf_nbuf_t nbuf_clone = NULL;
/* If the MPDU end tlv and RX header are received in different buffers,
* process the RX header based on fcs status.
*/
if (pdev->mcopy_status_nbuf) {
/* For M_COPY mode only one msdu per ppdu is sent to upper layer*/
if (pdev->mcopy_mode == M_COPY) {
if (pdev->m_copy_id.rx_ppdu_id ==
ppdu_info->com_info.ppdu_id)
goto end1;
}
if (ppdu_info->is_fcs_passed) {
nbuf_clone = qdf_nbuf_clone(pdev->mcopy_status_nbuf);
if (!nbuf_clone) {
QDF_TRACE(QDF_MODULE_ID_TXRX,
QDF_TRACE_LEVEL_ERROR,
"Failed to clone nbuf",
__func__, __LINE__);
goto end1;
}
pdev->m_copy_id.rx_ppdu_id = ppdu_info->com_info.ppdu_id;
dp_wdi_event_handler(WDI_EVENT_RX_DATA, soc,
nbuf_clone,
HTT_INVALID_PEER,
WDI_NO_VAL, pdev->pdev_id);
ppdu_info->is_fcs_passed = false;
}
end1:
qdf_nbuf_free(pdev->mcopy_status_nbuf);
pdev->mcopy_status_nbuf = NULL;
}
/* If the MPDU end tlv and RX header are received in different buffers,
* preserve the RX header as the fcs status will be received in MPDU
* end tlv in next buffer. So, cache the buffer to be processd in next
* iteration
*/
if ((ppdu_info->fcs_ok_cnt + ppdu_info->fcs_err_cnt) !=
ppdu_info->com_info.mpdu_cnt) {
pdev->mcopy_status_nbuf = qdf_nbuf_clone(status_nbuf);
if (pdev->mcopy_status_nbuf) {
mcopy_status = dp_rx_handle_mcopy_mode(
soc, pdev,
ppdu_info,
pdev->mcopy_status_nbuf,
ppdu_info->fcs_ok_cnt,
false);
if (mcopy_status == QDF_STATUS_SUCCESS) {
qdf_nbuf_free(pdev->mcopy_status_nbuf);
pdev->mcopy_status_nbuf = NULL;
}
}
}
}
#else
static inline void
dp_rx_mcopy_handle_last_mpdu(struct dp_soc *soc, struct dp_pdev *pdev,
struct hal_rx_ppdu_info *ppdu_info,
qdf_nbuf_t status_nbuf)
{
}
#endif
/**
* dp_rx_mcopy_process_ppdu_info() - update mcopy ppdu info
* @ppdu_info: structure for rx ppdu ring
* @tlv_status: processed TLV status
*
* Return: void
*/
#ifdef FEATURE_PERPKT_INFO
static inline void
dp_rx_mcopy_process_ppdu_info(struct dp_pdev *pdev,
struct hal_rx_ppdu_info *ppdu_info,
uint32_t tlv_status)
{
if (!pdev->mcopy_mode)
return;
/* The fcs status is received in MPDU end tlv. If the RX header
* and its MPDU end tlv are received in different status buffer then
* to process that header ppdu_info->is_fcs_passed is used.
* If end tlv is received in next status buffer then com_info.mpdu_cnt
* will be 0 at the time of receiving MPDU end tlv and we update the
* is_fcs_passed flag based on ppdu_info->fcs_err.
*/
if (tlv_status != HAL_TLV_STATUS_MPDU_END)
return;
if (!ppdu_info->fcs_err) {
if (ppdu_info->fcs_ok_cnt >
HAL_RX_MAX_MPDU_H_PER_STATUS_BUFFER) {
dp_err("No. of MPDUs(%d) per status buff exceeded",
ppdu_info->fcs_ok_cnt);
return;
}
if (ppdu_info->com_info.mpdu_cnt)
ppdu_info->fcs_ok_cnt++;
else
ppdu_info->is_fcs_passed = true;
} else {
if (ppdu_info->com_info.mpdu_cnt)
ppdu_info->fcs_err_cnt++;
else
ppdu_info->is_fcs_passed = false;
}
}
#else
static inline void
dp_rx_mcopy_process_ppdu_info(struct dp_pdev *pdev,
struct hal_rx_ppdu_info *ppdu_info,
uint32_t tlv_status)
{
}
#endif
#ifdef FEATURE_PERPKT_INFO
static inline void
dp_rx_process_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev,
@@ -840,36 +906,50 @@ dp_rx_process_mcopy_mode(struct dp_soc *soc, struct dp_pdev *pdev,
qdf_nbuf_t status_nbuf)
{
QDF_STATUS mcopy_status;
qdf_nbuf_t nbuf_clone = NULL;
uint8_t fcs_ok_mpdu_cnt = 0;
if (qdf_unlikely(!ppdu_info->com_info.mpdu_cnt)) {
qdf_nbuf_free(status_nbuf);
return;
}
/* Add buffers to queue until we receive
* HAL_TLV_STATUS_PPDU_DONE
*/
dp_rx_handle_ppdu_status_buf(pdev, ppdu_info, status_nbuf);
dp_rx_mcopy_handle_last_mpdu(soc, pdev, ppdu_info, status_nbuf);
/* If tlv_status is PPDU_DONE, process rx_ppdu_buf_q
* and devliver fcs_ok msdu buffer
*/
if (tlv_status == HAL_TLV_STATUS_PPDU_DONE) {
if (qdf_unlikely(ppdu_info->com_info.mpdu_cnt !=
(ppdu_info->com_info.mpdu_cnt_fcs_ok +
ppdu_info->com_info.mpdu_cnt_fcs_err))) {
qdf_nbuf_queue_free(&pdev->rx_ppdu_buf_q);
return;
}
/* Get rx ppdu status buffer having fcs ok msdu */
status_nbuf = dp_rx_get_fcs_ok_msdu(pdev, ppdu_info);
if (status_nbuf) {
mcopy_status = dp_rx_handle_mcopy_mode(soc, pdev,
ppdu_info,
status_nbuf);
if (mcopy_status == QDF_STATUS_SUCCESS)
qdf_nbuf_free(status_nbuf);
if (qdf_unlikely(!ppdu_info->com_info.mpdu_cnt))
goto end;
if (qdf_unlikely(!ppdu_info->fcs_ok_cnt))
goto end;
/* For M_COPY mode only one msdu per ppdu is sent to upper layer*/
if (pdev->mcopy_mode == M_COPY)
ppdu_info->fcs_ok_cnt = 1;
while (fcs_ok_mpdu_cnt < ppdu_info->fcs_ok_cnt) {
nbuf_clone = qdf_nbuf_clone(status_nbuf);
if (!nbuf_clone) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"Failed to clone nbuf",
__func__, __LINE__);
goto end;
}
mcopy_status = dp_rx_handle_mcopy_mode(soc, pdev,
ppdu_info,
nbuf_clone,
fcs_ok_mpdu_cnt,
true);
if (mcopy_status == QDF_STATUS_SUCCESS)
qdf_nbuf_free(nbuf_clone);
fcs_ok_mpdu_cnt++;
}
end:
qdf_nbuf_free(status_nbuf);
ppdu_info->fcs_ok_cnt = 0;
ppdu_info->fcs_err_cnt = 0;
ppdu_info->com_info.mpdu_cnt = 0;
qdf_mem_zero(&ppdu_info->ppdu_msdu_info,
HAL_RX_MAX_MPDU_H_PER_STATUS_BUFFER
* sizeof(struct hal_rx_msdu_payload_info));
}
#else
static inline void
@@ -1534,6 +1614,10 @@ dp_rx_mon_status_process_tlv(struct dp_soc *soc, uint32_t mac_id,
status_nbuf, ppdu_info,
&nbuf_used);
dp_rx_mcopy_process_ppdu_info(pdev,
ppdu_info,
tlv_status);
rx_tlv = hal_rx_status_get_next_tlv(rx_tlv);
if ((rx_tlv - rx_tlv_start) >=
@@ -2103,7 +2187,6 @@ dp_rx_pdev_mon_status_attach(struct dp_pdev *pdev, int ring_id) {
return status;
qdf_nbuf_queue_init(&pdev->rx_status_q);
qdf_nbuf_queue_init(&pdev->rx_ppdu_buf_q);
pdev->mon_ppdu_status = DP_PPDU_STATUS_START;

View File

@@ -123,6 +123,15 @@ enum rx_pktlog_mode {
};
#endif
/* enum m_copy_mode - Available mcopy mode
*
*/
enum m_copy_mode {
M_COPY_DISABLED = 0,
M_COPY = 2,
M_COPY_EXTENDED = 4,
};
struct msdu_list {
qdf_nbuf_t head;
qdf_nbuf_t tail;
@@ -1735,7 +1744,7 @@ struct dp_pdev {
bool tx_sniffer_enable;
/* mirror copy mode */
bool mcopy_mode;
enum m_copy_mode mcopy_mode;
bool cfr_rcc_mode;
bool enable_reap_timer_non_pkt;
bool bpr_enable;
@@ -1845,10 +1854,6 @@ struct dp_pdev {
uint32_t *ppdu_tlv_buf; /* Buffer to hold HTT ppdu stats TLVs*/
/* nbuf queue to maintain rx ppdu status buffer
* belonging to one ppdu
*/
qdf_nbuf_queue_t rx_ppdu_buf_q;
#ifdef WLAN_SUPPORT_RX_FLOW_TAG
/**
* Pointer to DP Flow FST at SOC level if
@@ -1877,6 +1882,7 @@ struct dp_pdev {
*/
struct hal_rx_mon_desc_info *mon_desc;
#endif
qdf_nbuf_t mcopy_status_nbuf;
};
struct dp_peer;

View File

@@ -161,6 +161,7 @@
/* Max MPDUs per status buffer */
#define HAL_RX_MAX_MPDU 256
#define HAL_RX_NUM_WORDS_PER_PPDU_BITMAP (HAL_RX_MAX_MPDU >> 5)
#define HAL_RX_MAX_MPDU_H_PER_STATUS_BUFFER 16
/* Max pilot count */
#define HAL_RX_MAX_SU_EVM_COUNT 32
@@ -476,12 +477,10 @@ struct hal_rx_ppdu_common_info {
* struct hal_rx_msdu_payload_info - msdu payload info
* @first_msdu_payload: pointer to first msdu payload
* @payload_len: payload len
* @nbuf: status network buffer to which msdu belongs to
*/
struct hal_rx_msdu_payload_info {
uint8_t *first_msdu_payload;
uint32_t payload_len;
qdf_nbuf_t nbuf;
};
/**
@@ -630,8 +629,14 @@ struct hal_rx_ppdu_info {
/* Id to indicate how to process mpdu */
uint8_t sw_frame_group_id;
struct hal_rx_ppdu_msdu_info rx_msdu_info[HAL_MAX_UL_MU_USERS];
/* first msdu payload for all mpdus in ppdu */
struct hal_rx_msdu_payload_info ppdu_msdu_info[HAL_RX_MAX_MPDU];
/* fcs passed mpdu count in rx monitor status buffer */
uint8_t fcs_ok_cnt;
/* fcs error mpdu count in rx monitor status buffer */
uint8_t fcs_err_cnt;
/* MPDU FCS passed */
bool is_fcs_passed;
/* first msdu payload for all mpdus in rx monitor status buffer */
struct hal_rx_msdu_payload_info ppdu_msdu_info[HAL_RX_MAX_MPDU_H_PER_STATUS_BUFFER];
/* evm info */
struct hal_rx_su_evm_info evm_info;
/**

View File

@@ -1513,19 +1513,20 @@ hal_rx_status_get_tlv_info_generic(void *rx_tlv_hdr, void *ppduinfo,
case WIFIRX_HEADER_E:
{
struct hal_rx_ppdu_common_info *com_info = &ppdu_info->com_info;
uint16_t mpdu_cnt = com_info->mpdu_cnt;
if (mpdu_cnt >= HAL_RX_MAX_MPDU) {
hal_alert("Number of MPDUs per PPDU exceeded");
if (ppdu_info->fcs_ok_cnt >=
HAL_RX_MAX_MPDU_H_PER_STATUS_BUFFER) {
hal_err("Number of MPDUs(%d) per status buff exceeded",
ppdu_info->fcs_ok_cnt);
break;
}
/* Update first_msdu_payload for every mpdu and increment
* com_info->mpdu_cnt for every WIFIRX_HEADER_E TLV
*/
ppdu_info->ppdu_msdu_info[mpdu_cnt].first_msdu_payload =
ppdu_info->ppdu_msdu_info[ppdu_info->fcs_ok_cnt].first_msdu_payload =
rx_tlv;
ppdu_info->ppdu_msdu_info[mpdu_cnt].payload_len = tlv_len;
ppdu_info->ppdu_msdu_info[mpdu_cnt].nbuf = nbuf;
ppdu_info->ppdu_msdu_info[ppdu_info->fcs_ok_cnt].payload_len = tlv_len;
ppdu_info->msdu_info.first_msdu_payload = rx_tlv;
ppdu_info->msdu_info.payload_len = tlv_len;
ppdu_info->user_id = user_id;