qcacmn: Handle 2k exception and rate limit delba

Upon receiving 2k jump exception, send delba
and track delba tx status and retries.

Change-Id: Ida35256233869dfa390c40030c9296b9c48481ce
Crs-fixed: 2239856
This commit is contained in:
sumedh baikady
2018-04-08 22:19:22 -07:00
committed by nshrivas
parent f3c286ed15
commit df4a57cd31
9 changed files with 284 additions and 31 deletions

View File

@@ -1061,6 +1061,36 @@ static inline int cdp_delba_process(ol_txrx_soc_handle soc,
tid, reasoncode); tid, reasoncode);
} }
/**
* cdp_delba_tx_completion() - Handle delba tx completion
* to update stats and retry transmission if failed.
* @soc: soc handle
* @peer_handle: peer handle
* @tid: Tid number
* @status: Tx completion status
*
* Return: 0 on Success, 1 on failure
*/
static inline int cdp_delba_tx_completion(ol_txrx_soc_handle soc,
void *peer_handle,
uint8_t tid, int status)
{
if (!soc || !soc->ops) {
QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG,
"%s: Invalid Instance:", __func__);
QDF_BUG(0);
return 0;
}
if (!soc->ops->cmn_drv_ops ||
!soc->ops->cmn_drv_ops->delba_tx_completion)
return 0;
return soc->ops->cmn_drv_ops->delba_tx_completion(peer_handle,
tid, status);
}
static inline void cdp_set_addbaresponse(ol_txrx_soc_handle soc, static inline void cdp_set_addbaresponse(ol_txrx_soc_handle soc,
void *peer_handle, int tid, uint16_t statuscode) void *peer_handle, int tid, uint16_t statuscode)
{ {

View File

@@ -271,6 +271,17 @@ struct cdp_cmn_ops {
int (*delba_process)(void *peer_handle, int (*delba_process)(void *peer_handle,
int tid, uint16_t reasoncode); int tid, uint16_t reasoncode);
/**
* delba_tx_completion() - Indicate delba tx status
* @peer_handle: Peer handle
* @tid: Tid number
* @status: Tx completion status
*
* Return: 0 on Success, 1 on failure
*/
int (*delba_tx_completion)(void *peer_handle,
uint8_t tid, int status);
void (*set_addba_response)(void *peer_handle, void (*set_addba_response)(void *peer_handle,
uint8_t tid, uint16_t statuscode); uint8_t tid, uint16_t statuscode);
@@ -806,6 +817,17 @@ struct ol_if_ops {
#endif #endif
int (*peer_sta_kickout)(void *ctrl_pdev, uint8_t *peer_macaddr); int (*peer_sta_kickout)(void *ctrl_pdev, uint8_t *peer_macaddr);
/**
* send_delba() - Send delba to peer
* @pdev_handle: Dp pdev handle
* @ctrl_peer: Peer handle
* @peer_macaddr: Peer mac addr
* @tid: Tid number
*
* Return: 0 for success, non-zero for failure
*/
int (*send_delba)(void *pdev_handle, void *ctrl_peer,
uint8_t *peer_macaddr, uint8_t tid, void *vdev_handle);
/* TODO: Add any other control path calls required to OL_IF/WMA layer */ /* TODO: Add any other control path calls required to OL_IF/WMA layer */
}; };

View File

@@ -656,7 +656,18 @@ extern void dp_set_addba_response(void *peer_handle, uint8_t tid,
uint16_t statuscode); uint16_t statuscode);
extern int dp_delba_process_wifi3(void *peer_handle, extern int dp_delba_process_wifi3(void *peer_handle,
int tid, uint16_t reasoncode); int tid, uint16_t reasoncode);
/*
* dp_delba_tx_completion_wifi3() - Handle delba tx completion
*
* @peer_handle: Peer handle
* @tid: Tid number
* @status: Tx completion status
* Indicate status of delba Tx to DP for stats update and retry
* delba if tx failed.
*
*/
int dp_delba_tx_completion_wifi3(void *peer_handle, uint8_t tid,
int status);
extern int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, extern int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid,
uint32_t ba_window_size, uint32_t start_seq); uint32_t ba_window_size, uint32_t start_seq);

View File

@@ -7607,6 +7607,7 @@ static struct cdp_cmn_ops dp_ops_cmn = {
.txrx_peer_flush_ast_table = dp_wds_flush_ast_table_wifi3, .txrx_peer_flush_ast_table = dp_wds_flush_ast_table_wifi3,
.txrx_peer_map_attach = dp_peer_map_attach_wifi3, .txrx_peer_map_attach = dp_peer_map_attach_wifi3,
.txrx_pdev_set_ctrl_pdev = dp_pdev_set_ctrl_pdev, .txrx_pdev_set_ctrl_pdev = dp_pdev_set_ctrl_pdev,
.delba_tx_completion = dp_delba_tx_completion_wifi3,
}; };
static struct cdp_ctrl_ops dp_ops_ctrl = { static struct cdp_ctrl_ops dp_ops_ctrl = {

View File

@@ -900,15 +900,24 @@ void dp_rx_tid_stats_cb(struct dp_soc *soc, void *cb_ctxt,
queue_status->late_recv_mpdu_cnt, queue_status->win_jump_2k, queue_status->late_recv_mpdu_cnt, queue_status->win_jump_2k,
queue_status->hole_cnt); queue_status->hole_cnt);
DP_PRINT_STATS("Num of Addba Req = %d\n", rx_tid->num_of_addba_req); DP_PRINT_STATS("Addba Req : %d\n"
DP_PRINT_STATS("Num of Addba Resp = %d\n", rx_tid->num_of_addba_resp); "Addba Resp : %d\n"
DP_PRINT_STATS("Num of Addba Resp successful = %d\n", "Addba Resp success : %d\n"
rx_tid->num_addba_rsp_success); "Addba Resp failed : %d\n"
DP_PRINT_STATS("Num of Addba Resp failed = %d\n", "Delba Req received : %d\n"
rx_tid->num_addba_rsp_failed); "Delba Tx success : %d\n"
DP_PRINT_STATS("Num of Delba Req = %d\n", rx_tid->num_of_delba_req); "Delba Tx Fail : %d\n"
DP_PRINT_STATS("BA window size = %d\n", rx_tid->ba_win_size); "BA window size : %d\n"
DP_PRINT_STATS("Pn size = %d\n", rx_tid->pn_size); "Pn size : %d\n",
rx_tid->num_of_addba_req,
rx_tid->num_of_addba_resp,
rx_tid->num_addba_rsp_success,
rx_tid->num_addba_rsp_failed,
rx_tid->num_of_delba_req,
rx_tid->delba_tx_success_cnt,
rx_tid->delba_tx_fail_cnt,
rx_tid->ba_win_size,
rx_tid->pn_size);
} }
static inline struct dp_peer *dp_peer_find_add_id(struct dp_soc *soc, static inline struct dp_peer *dp_peer_find_add_id(struct dp_soc *soc,
@@ -1239,11 +1248,16 @@ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid,
if (rx_tid->hw_qdesc_vaddr_unaligned != NULL) if (rx_tid->hw_qdesc_vaddr_unaligned != NULL)
return dp_rx_tid_update_wifi3(peer, tid, ba_window_size, return dp_rx_tid_update_wifi3(peer, tid, ba_window_size,
start_seq); start_seq);
rx_tid->delba_tx_status = 0;
rx_tid->ppdu_id_2k = 0;
rx_tid->num_of_addba_req = 0; rx_tid->num_of_addba_req = 0;
rx_tid->num_of_delba_req = 0; rx_tid->num_of_delba_req = 0;
rx_tid->num_of_addba_resp = 0; rx_tid->num_of_addba_resp = 0;
rx_tid->num_addba_rsp_failed = 0; rx_tid->num_addba_rsp_failed = 0;
rx_tid->num_addba_rsp_success = 0; rx_tid->num_addba_rsp_success = 0;
rx_tid->delba_tx_success_cnt = 0;
rx_tid->delba_tx_fail_cnt = 0;
rx_tid->statuscode = 0;
#ifdef notyet #ifdef notyet
hw_qdesc_size = hal_get_reo_qdesc_size(soc->hal_soc, ba_window_size); hw_qdesc_size = hal_get_reo_qdesc_size(soc->hal_soc, ba_window_size);
#else #else
@@ -1648,8 +1662,14 @@ int dp_addba_resp_tx_completion_wifi3(void *peer_handle,
uint8_t tid, int status) uint8_t tid, int status)
{ {
struct dp_peer *peer = (struct dp_peer *)peer_handle; struct dp_peer *peer = (struct dp_peer *)peer_handle;
struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; struct dp_rx_tid *rx_tid = NULL;
if (!peer || peer->delete_in_progress) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Peer is NULL!\n", __func__);
return QDF_STATUS_E_FAILURE;
}
rx_tid = &peer->rx_tid[tid];
qdf_spin_lock_bh(&rx_tid->tid_lock); qdf_spin_lock_bh(&rx_tid->tid_lock);
if (status) { if (status) {
rx_tid->num_addba_rsp_failed++; rx_tid->num_addba_rsp_failed++;
@@ -1659,7 +1679,7 @@ int dp_addba_resp_tx_completion_wifi3(void *peer_handle,
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Rx Tid- %d addba rsp tx completion failed!", "%s: Rx Tid- %d addba rsp tx completion failed!",
__func__, tid); __func__, tid);
return 0; return QDF_STATUS_SUCCESS;
} }
rx_tid->num_addba_rsp_success++; rx_tid->num_addba_rsp_success++;
@@ -1671,19 +1691,9 @@ int dp_addba_resp_tx_completion_wifi3(void *peer_handle,
return QDF_STATUS_E_FAILURE; return QDF_STATUS_E_FAILURE;
} }
if (dp_rx_tid_update_wifi3(peer, tid, rx_tid->ba_win_size,
rx_tid->startseqnum)) {
qdf_spin_unlock_bh(&rx_tid->tid_lock);
return QDF_STATUS_E_FAILURE;
}
if (rx_tid->userstatuscode != IEEE80211_STATUS_SUCCESS)
rx_tid->statuscode = rx_tid->userstatuscode;
else
rx_tid->statuscode = IEEE80211_STATUS_SUCCESS;
rx_tid->ba_status = DP_RX_BA_ACTIVE; rx_tid->ba_status = DP_RX_BA_ACTIVE;
qdf_spin_unlock_bh(&rx_tid->tid_lock); qdf_spin_unlock_bh(&rx_tid->tid_lock);
return 0; return QDF_STATUS_SUCCESS;
} }
/* /*
@@ -1701,8 +1711,14 @@ void dp_addba_responsesetup_wifi3(void *peer_handle, uint8_t tid,
uint16_t *buffersize, uint16_t *batimeout) uint16_t *buffersize, uint16_t *batimeout)
{ {
struct dp_peer *peer = (struct dp_peer *)peer_handle; struct dp_peer *peer = (struct dp_peer *)peer_handle;
struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; struct dp_rx_tid *rx_tid = NULL;
if (!peer || peer->delete_in_progress) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Peer is NULL!\n", __func__);
return;
}
rx_tid = &peer->rx_tid[tid];
qdf_spin_lock_bh(&rx_tid->tid_lock); qdf_spin_lock_bh(&rx_tid->tid_lock);
rx_tid->num_of_addba_resp++; rx_tid->num_of_addba_resp++;
/* setup ADDBA response parameters */ /* setup ADDBA response parameters */
@@ -1732,8 +1748,14 @@ int dp_addba_requestprocess_wifi3(void *peer_handle,
uint16_t startseqnum) uint16_t startseqnum)
{ {
struct dp_peer *peer = (struct dp_peer *)peer_handle; struct dp_peer *peer = (struct dp_peer *)peer_handle;
struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; struct dp_rx_tid *rx_tid = NULL;
if (!peer || peer->delete_in_progress) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Peer is NULL!\n", __func__);
return QDF_STATUS_E_FAILURE;
}
rx_tid = &peer->rx_tid[tid];
qdf_spin_lock_bh(&rx_tid->tid_lock); qdf_spin_lock_bh(&rx_tid->tid_lock);
rx_tid->num_of_addba_req++; rx_tid->num_of_addba_req++;
if ((rx_tid->ba_status == DP_RX_BA_ACTIVE && if ((rx_tid->ba_status == DP_RX_BA_ACTIVE &&
@@ -1748,7 +1770,7 @@ int dp_addba_requestprocess_wifi3(void *peer_handle,
return QDF_STATUS_E_FAILURE; return QDF_STATUS_E_FAILURE;
} }
if (dp_rx_tid_setup_wifi3(peer, tid, 1, 0)) { if (dp_rx_tid_setup_wifi3(peer, tid, buffersize, 0)) {
rx_tid->ba_status = DP_RX_BA_INACTIVE; rx_tid->ba_status = DP_RX_BA_INACTIVE;
qdf_spin_unlock_bh(&rx_tid->tid_lock); qdf_spin_unlock_bh(&rx_tid->tid_lock);
return QDF_STATUS_E_FAILURE; return QDF_STATUS_E_FAILURE;
@@ -1758,8 +1780,15 @@ int dp_addba_requestprocess_wifi3(void *peer_handle,
rx_tid->ba_win_size = buffersize; rx_tid->ba_win_size = buffersize;
rx_tid->dialogtoken = dialogtoken; rx_tid->dialogtoken = dialogtoken;
rx_tid->startseqnum = startseqnum; rx_tid->startseqnum = startseqnum;
if (rx_tid->userstatuscode != IEEE80211_STATUS_SUCCESS)
rx_tid->statuscode = rx_tid->userstatuscode;
else
rx_tid->statuscode = IEEE80211_STATUS_SUCCESS;
qdf_spin_unlock_bh(&rx_tid->tid_lock); qdf_spin_unlock_bh(&rx_tid->tid_lock);
return 0;
return QDF_STATUS_SUCCESS;
} }
/* /*
@@ -1811,6 +1840,53 @@ int dp_delba_process_wifi3(void *peer_handle,
return 0; return 0;
} }
/*
* dp_rx_delba_tx_completion_wifi3() Send Delba Request
*
* @peer: Datapath peer handle
* @tid: TID number
* @status: tx completion status
* Return: 0 on success, error code on failure
*/
int dp_delba_tx_completion_wifi3(void *peer_handle,
uint8_t tid, int status)
{
struct dp_peer *peer = (struct dp_peer *)peer_handle;
struct dp_rx_tid *rx_tid = NULL;
if (!peer || peer->delete_in_progress) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG,
"%s: Peer is NULL!", __func__);
return QDF_STATUS_E_FAILURE;
}
rx_tid = &peer->rx_tid[tid];
qdf_spin_lock_bh(&rx_tid->tid_lock);
if (status) {
rx_tid->delba_tx_fail_cnt++;
if (rx_tid->delba_tx_retry >= DP_MAX_DELBA_RETRY) {
rx_tid->delba_tx_retry = 0;
rx_tid->delba_tx_status = 0;
qdf_spin_unlock_bh(&rx_tid->tid_lock);
} else {
rx_tid->delba_tx_retry++;
rx_tid->delba_tx_status = 1;
qdf_spin_unlock_bh(&rx_tid->tid_lock);
peer->vdev->pdev->soc->cdp_soc.ol_ops->send_delba(
peer->vdev->pdev->ctrl_pdev, peer->ctrl_peer,
peer->mac_addr.raw, tid, peer->vdev->ctrl_vdev);
}
return QDF_STATUS_SUCCESS;
} else {
rx_tid->delba_tx_success_cnt++;
rx_tid->delba_tx_retry = 0;
rx_tid->delba_tx_status = 0;
}
qdf_spin_unlock_bh(&rx_tid->tid_lock);
return QDF_STATUS_SUCCESS;
}
void dp_rx_discard(struct dp_vdev *vdev, struct dp_peer *peer, unsigned tid, void dp_rx_discard(struct dp_vdev *vdev, struct dp_peer *peer, unsigned tid,
qdf_nbuf_t msdu_list) qdf_nbuf_t msdu_list)
{ {

View File

@@ -468,6 +468,73 @@ dp_rx_chain_msdus(struct dp_soc *soc, qdf_nbuf_t nbuf, uint8_t *rx_tlv_hdr,
return mpdu_done; return mpdu_done;
} }
/**
* dp_2k_jump_handle() - Function to handle 2k jump exception
* on WBM ring
*
* @soc: core DP main context
* @nbuf: buffer pointer
* @rx_tlv_hdr: start of rx tlv header
* @peer_id: peer id of first msdu
* @tid: Tid for which exception occurred
*
* This function handles 2k jump violations arising out
* of receiving aggregates in non BA case. This typically
* may happen if aggregates are received on a QOS enabled TID
* while Rx window size is still initialized to value of 2. Or
* it may also happen if negotiated window size is 1 but peer
* sends aggregates.
*
*/
static void
dp_2k_jump_handle(struct dp_soc *soc,
qdf_nbuf_t nbuf,
uint8_t *rx_tlv_hdr,
uint16_t peer_id,
uint8_t tid)
{
uint32_t ppdu_id;
struct dp_peer *peer = NULL;
struct dp_rx_tid *rx_tid = NULL;
peer = dp_peer_find_by_id(soc, peer_id);
if (!peer || peer->delete_in_progress) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
"peer not found");
goto free_nbuf;
}
rx_tid = &peer->rx_tid[tid];
if (qdf_unlikely(rx_tid == NULL)) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
"rx_tid is NULL!!");
goto free_nbuf;
}
qdf_spin_lock_bh(&rx_tid->tid_lock);
ppdu_id = hal_rx_attn_phy_ppdu_id_get(rx_tlv_hdr);
if (rx_tid->ppdu_id_2k != ppdu_id) {
rx_tid->ppdu_id_2k = ppdu_id;
qdf_spin_unlock_bh(&rx_tid->tid_lock);
goto free_nbuf;
}
if (!rx_tid->delba_tx_status) {
rx_tid->delba_tx_retry++;
rx_tid->delba_tx_status = 1;
qdf_spin_unlock_bh(&rx_tid->tid_lock);
soc->cdp_soc.ol_ops->send_delba(peer->vdev->pdev->ctrl_pdev,
peer->ctrl_peer,
peer->mac_addr.raw,
tid,
peer->vdev->ctrl_vdev);
} else {
qdf_spin_unlock_bh(&rx_tid->tid_lock);
}
free_nbuf:
qdf_nbuf_free(nbuf);
return;
}
/** /**
* dp_rx_null_q_desc_handle() - Function to handle NULL Queue * dp_rx_null_q_desc_handle() - Function to handle NULL Queue
* descriptor violation on either a * descriptor violation on either a
@@ -1053,6 +1120,8 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota)
qdf_nbuf_t nbuf, next; qdf_nbuf_t nbuf, next;
struct hal_wbm_err_desc_info wbm_err_info = { 0 }; struct hal_wbm_err_desc_info wbm_err_info = { 0 };
uint8_t pool_id; uint8_t pool_id;
uint16_t peer_id = 0xFFFF;
uint8_t tid = 0;
/* Debug -- Remove later */ /* Debug -- Remove later */
qdf_assert(soc && hal_ring); qdf_assert(soc && hal_ring);
@@ -1190,10 +1259,25 @@ done:
continue; continue;
/* TODO */ /* TODO */
/* Add per error code accounting */ /* Add per error code accounting */
case HAL_REO_ERR_REGULAR_FRAME_2K_JUMP:
pool_id = wbm_err_info.pool_id;
QDF_TRACE(QDF_MODULE_ID_DP,
QDF_TRACE_LEVEL_ERROR,
"Got pkt with REO ERROR: %d",
wbm_err_info.reo_err_code);
if (hal_rx_msdu_end_first_msdu_get(rx_tlv_hdr)) {
peer_id =
hal_rx_mpdu_start_sw_peer_id_get(rx_tlv_hdr);
tid =
hal_rx_mpdu_start_tid_get(hal_soc, rx_tlv_hdr);
}
dp_2k_jump_handle(soc, nbuf, rx_tlv_hdr,
peer_id, tid);
nbuf = next;
continue;
default: default:
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE(QDF_MODULE_ID_DP,
QDF_TRACE_LEVEL_DEBUG, QDF_TRACE_LEVEL_ERROR,
"REO error %d detected", "REO error %d detected",
wbm_err_info.reo_err_code); wbm_err_info.reo_err_code);
} }

View File

@@ -92,6 +92,9 @@
#define DP_MAX_INTERRUPT_CONTEXTS 8 #define DP_MAX_INTERRUPT_CONTEXTS 8
/* Maximum retries for Delba per tid per peer */
#define DP_MAX_DELBA_RETRY 3
#ifndef REMOVE_PKT_LOG #ifndef REMOVE_PKT_LOG
enum rx_pktlog_mode { enum rx_pktlog_mode {
DP_RX_PKTLOG_DISABLED = 0, DP_RX_PKTLOG_DISABLED = 0,
@@ -480,6 +483,20 @@ struct dp_rx_tid {
uint16_t statuscode; uint16_t statuscode;
/* user defined ADDBA response status code */ /* user defined ADDBA response status code */
uint16_t userstatuscode; uint16_t userstatuscode;
/* Store ppdu_id when 2k exception is received */
uint32_t ppdu_id_2k;
/* Delba Tx completion status */
uint8_t delba_tx_status;
/* Delba Tx retry count */
uint8_t delba_tx_retry;
/* Delba stats */
uint32_t delba_tx_success_cnt;
uint32_t delba_tx_fail_cnt;
}; };
/* per interrupt context */ /* per interrupt context */

View File

@@ -496,7 +496,13 @@ inline int hal_reo_cmd_update_rx_queue(void *reo_ring, struct hal_soc *soc,
if (p->ba_window_size < 1) if (p->ba_window_size < 1)
p->ba_window_size = 1; p->ba_window_size = 1;
/*
* WAR to get 2k exception in Non BA case.
* Setting window size to 2 to get 2k jump exception
* when we receive aggregates in Non BA case
*/
if (p->ba_window_size == 1)
p->ba_window_size++;
HAL_DESC_SET_FIELD(reo_desc, REO_UPDATE_RX_REO_QUEUE_4, HAL_DESC_SET_FIELD(reo_desc, REO_UPDATE_RX_REO_QUEUE_4,
BA_WINDOW_SIZE, p->ba_window_size - 1); BA_WINDOW_SIZE, p->ba_window_size - 1);

View File

@@ -105,7 +105,13 @@ void hal_reo_qdesc_setup(void *hal_soc, int tid, uint32_t ba_window_size,
if (ba_window_size < 1) if (ba_window_size < 1)
ba_window_size = 1; ba_window_size = 1;
/*
* WAR to get 2k exception in Non BA case.
* Setting window size to 2 to get 2k jump exception
* when we receive aggregates in Non BA case
*/
if (ba_window_size == 1)
ba_window_size++;
/* Set RTY bit for non-BA case. Duplicate detection is currently not /* Set RTY bit for non-BA case. Duplicate detection is currently not
* done by HW in non-BA case if RTY bit is not set. * done by HW in non-BA case if RTY bit is not set.
* TODO: This is a temporary War and should be removed once HW fix is * TODO: This is a temporary War and should be removed once HW fix is