qcacld-3.0: Add txrx apis for High Latency systems (Part 2 - HL Datapath)
Add tx schedular module, tx classify module within the data SW, tx frame queues logging, group credit support and send-recieve tx frames instance for HL system. CRs-Fixed: 975526 Change-Id: If1655d4d832f88e565ab946ef9e9719f256ab7b1
This commit is contained in:

committed by
Vishwajith Upendra

parent
1df1cd85b4
commit
b2011f6435
@@ -68,6 +68,10 @@
|
||||
#define WLAN_HDD_NETIF_OPER_HISTORY 4
|
||||
#define WLAN_DUMP_TX_FLOW_POOL_INFO 5
|
||||
#define WLAN_TXRX_DESC_STATS 6
|
||||
#define WLAN_SCHEDULER_STATS 21
|
||||
#define WLAN_TX_QUEUE_STATS 22
|
||||
#define WLAN_BUNDLE_STATS 23
|
||||
#define WLAN_CREDIT_STATS 24
|
||||
|
||||
/**
|
||||
* @brief Set up the data SW subsystem.
|
||||
@@ -156,6 +160,7 @@ struct ol_tx_wmm_param_t {
|
||||
struct ol_tx_ac_param_t ac[OL_TX_NUM_WMM_AC];
|
||||
};
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
/**
|
||||
* @brief Set paramters of WMM scheduler per AC settings. .
|
||||
* @details
|
||||
@@ -164,23 +169,9 @@ struct ol_tx_wmm_param_t {
|
||||
* @param data_pdev - the physical device being paused
|
||||
* @param wmm_param - the wmm parameters
|
||||
*/
|
||||
#define ol_txrx_set_wmm_param(data_pdev, wmm_param) /* no-op */
|
||||
|
||||
/**
|
||||
* @brief notify tx data SW that a peer's transmissions are suspended.
|
||||
* @details
|
||||
* This function applies only to HL systems - in LL systems, tx flow control
|
||||
* is handled entirely within the target FW.
|
||||
* The HL host tx data SW is doing tx classification and tx download
|
||||
* scheduling, and therefore also needs to actively participate in tx
|
||||
* flow control. Specifically, the HL tx data SW needs to check whether a
|
||||
* given peer is available to transmit to, or is paused.
|
||||
* This function is used to tell the HL tx data SW when a peer is paused,
|
||||
* so the host tx data SW can hold the tx frames for that SW.
|
||||
*
|
||||
* @param data_peer - which peer is being paused
|
||||
*/
|
||||
#define ol_txrx_peer_pause(data_peer) /* no-op */
|
||||
void
|
||||
ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev,
|
||||
struct ol_tx_wmm_param_t wmm_param);
|
||||
|
||||
/**
|
||||
* @brief notify tx data SW that a peer-TID is ready to transmit to.
|
||||
@@ -204,7 +195,9 @@ struct ol_tx_wmm_param_t {
|
||||
* @param tid - which TID within the peer is being unpaused, or -1 as a
|
||||
* wildcard to unpause all TIDs within the peer
|
||||
*/
|
||||
#define ol_txrx_peer_tid_unpause(data_peer, tid) /* no-op */
|
||||
void
|
||||
ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Tell a paused peer to release a specified number of tx frames.
|
||||
@@ -230,8 +223,9 @@ struct ol_tx_wmm_param_t {
|
||||
* @param max_frms - limit on the number of tx frames to release from the
|
||||
* specified TID's queues within the specified peer
|
||||
*/
|
||||
#define ol_txrx_tx_release(peer, tid_mask, max_frms) /* no-op */
|
||||
|
||||
void ol_txrx_tx_release(ol_txrx_peer_handle peer,
|
||||
u_int32_t tid_mask,
|
||||
int max_frms);
|
||||
|
||||
/**
|
||||
* @brief Suspend all tx data per thermal event/timer for the
|
||||
@@ -240,7 +234,9 @@ struct ol_tx_wmm_param_t {
|
||||
* This function applies only to HL systerms, and it makes pause and
|
||||
* unpause operations happen in pairs.
|
||||
*/
|
||||
#define ol_txrx_throttle_pause(data_pdev) /* no-op */
|
||||
void
|
||||
ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Resume all tx data per thermal event/timer for the
|
||||
@@ -249,7 +245,64 @@ struct ol_tx_wmm_param_t {
|
||||
* This function applies only to HL systerms, and it makes pause and
|
||||
* unpause operations happen in pairs.
|
||||
*/
|
||||
#define ol_txrx_throttle_unpause(data_pdev) /* no-op */
|
||||
void
|
||||
ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev);
|
||||
|
||||
#else
|
||||
|
||||
static inline
|
||||
void ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev,
|
||||
struct ol_tx_wmm_param_t wmm_param)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_txrx_tx_release(ol_txrx_peer_handle peer,
|
||||
u_int32_t tid_mask,
|
||||
int max_frms)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HL_SUPPORT */
|
||||
|
||||
/**
|
||||
* @brief notify tx data SW that a peer's transmissions are suspended.
|
||||
* @details
|
||||
* This function applies only to HL systems - in LL systems, tx flow control
|
||||
* is handled entirely within the target FW.
|
||||
* The HL host tx data SW is doing tx classification and tx download
|
||||
* scheduling, and therefore also needs to actively participate in tx
|
||||
* flow control. Specifically, the HL tx data SW needs to check whether a
|
||||
* given peer is available to transmit to, or is paused.
|
||||
* This function is used to tell the HL tx data SW when a peer is paused,
|
||||
* so the host tx data SW can hold the tx frames for that SW.
|
||||
*
|
||||
* @param data_peer - which peer is being paused
|
||||
*/
|
||||
static inline void ol_txrx_peer_pause(struct ol_txrx_peer_t *data_peer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suspend all tx data for the specified physical device.
|
||||
@@ -263,7 +316,9 @@ struct ol_tx_wmm_param_t {
|
||||
*
|
||||
* @param data_pdev - the physical device being paused
|
||||
*/
|
||||
#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2)
|
||||
#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \
|
||||
defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason);
|
||||
#else
|
||||
static inline
|
||||
@@ -281,7 +336,9 @@ void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason)
|
||||
*
|
||||
* @param data_pdev - the physical device being unpaused
|
||||
*/
|
||||
#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2)
|
||||
#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \
|
||||
defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason);
|
||||
#else
|
||||
static inline
|
||||
@@ -488,6 +545,58 @@ int16_t ol_txrx_peer_rssi(ol_txrx_peer_handle peer);
|
||||
*/
|
||||
#define QCA_TX_DELAY_HIST_REPORT_BINS 6
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL)
|
||||
|
||||
/**
|
||||
* @brief Configure the bad peer tx limit setting.
|
||||
* @details
|
||||
*
|
||||
* @param pdev - the physics device
|
||||
*/
|
||||
void
|
||||
ol_txrx_bad_peer_txctl_set_setting(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
int enable,
|
||||
int period,
|
||||
int txq_limit);
|
||||
|
||||
/**
|
||||
* @brief Configure the bad peer tx threshold limit
|
||||
* @details
|
||||
*
|
||||
* @param pdev - the physics device
|
||||
*/
|
||||
void
|
||||
ol_txrx_bad_peer_txctl_update_threshold(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
int level,
|
||||
int tput_thresh,
|
||||
int tx_limit);
|
||||
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_txrx_bad_peer_txctl_set_setting(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
int enable,
|
||||
int period,
|
||||
int txq_limit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_txrx_bad_peer_txctl_update_threshold(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
int level,
|
||||
int tput_thresh,
|
||||
int tx_limit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */
|
||||
|
||||
|
||||
void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_peer_t *peer);
|
||||
|
||||
|
@@ -134,7 +134,26 @@ void ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev, int just_once);
|
||||
/* uncomment this to enable the tx queue log feature */
|
||||
/* #define ENABLE_TX_QUEUE_LOG 1 */
|
||||
|
||||
#define ol_tx_queue_log_display(pdev)
|
||||
#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
void
|
||||
ol_tx_queue_log_display(ol_txrx_pdev_handle pdev);
|
||||
void ol_tx_queue_log_clear(ol_txrx_pdev_handle pdev);
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_tx_queue_log_display(ol_txrx_pdev_handle pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline
|
||||
void ol_tx_queue_log_clear(ol_txrx_pdev_handle pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) */
|
||||
|
||||
|
||||
/*----------------------------------------*/
|
||||
|
||||
|
@@ -57,6 +57,36 @@ void ol_tx_set_flow_control_parameters(struct txrx_pdev_cfg_t *cfg_ctx,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HL_SUPPORT
|
||||
|
||||
/**
|
||||
* ol_pdev_cfg_param_update() - assign download size of tx frame for txrx
|
||||
* pdev that will be used across datapath
|
||||
* @cfg_ctx: ptr to config parameter for txrx pdev
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static inline
|
||||
void ol_pdev_cfg_param_update(struct txrx_pdev_cfg_t *cfg_ctx)
|
||||
{
|
||||
cfg_ctx->is_high_latency = 1;
|
||||
/* 802.1Q and SNAP / LLC headers are accounted for elsewhere */
|
||||
cfg_ctx->tx_download_size = 1500;
|
||||
cfg_ctx->tx_free_at_download = 0;
|
||||
}
|
||||
#else
|
||||
|
||||
static inline
|
||||
void ol_pdev_cfg_param_update(struct txrx_pdev_cfg_t *cfg_ctx)
|
||||
{
|
||||
/*
|
||||
* Need to change HTT_LL_TX_HDR_SIZE_IP accordingly.
|
||||
* Include payload, up to the end of UDP header for IPv4 case
|
||||
*/
|
||||
cfg_ctx->tx_download_size = 16;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK
|
||||
static inline
|
||||
uint8_t ol_defrag_timeout_check(void)
|
||||
@@ -86,6 +116,7 @@ uint8_t ol_defrag_timeout_check(void)
|
||||
*
|
||||
* Return: the control device object
|
||||
*/
|
||||
|
||||
ol_pdev_handle ol_pdev_cfg_attach(qdf_device_t osdev,
|
||||
struct txrx_pdev_cfg_param_t cfg_param)
|
||||
{
|
||||
@@ -97,11 +128,8 @@ ol_pdev_handle ol_pdev_cfg_attach(qdf_device_t osdev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to change HTT_LL_TX_HDR_SIZE_IP accordingly.
|
||||
* Include payload, up to the end of UDP header for IPv4 case
|
||||
*/
|
||||
cfg_ctx->tx_download_size = 16;
|
||||
ol_pdev_cfg_param_update(cfg_ctx);
|
||||
|
||||
/* temporarily diabled PN check for Riva/Pronto */
|
||||
cfg_ctx->rx_pn_check = 1;
|
||||
cfg_ctx->defrag_timeout_check = ol_defrag_timeout_check();
|
||||
@@ -248,6 +276,21 @@ int ol_cfg_tx_free_at_download(ol_pdev_handle pdev)
|
||||
return cfg->tx_free_at_download;
|
||||
}
|
||||
|
||||
void ol_cfg_set_tx_free_at_download(ol_pdev_handle pdev)
|
||||
{
|
||||
struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev;
|
||||
cfg->tx_free_at_download = 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_HL_SUPPORT
|
||||
uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev)
|
||||
{
|
||||
struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev;
|
||||
return cfg->target_tx_credit;
|
||||
}
|
||||
#else
|
||||
|
||||
uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev)
|
||||
{
|
||||
struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev;
|
||||
@@ -259,6 +302,7 @@ uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev)
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ol_cfg_tx_download_size(ol_pdev_handle pdev)
|
||||
{
|
||||
@@ -326,6 +370,7 @@ int ol_cfg_get_tx_flow_start_queue_offset(ol_pdev_handle pdev)
|
||||
struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev;
|
||||
return cfg->tx_flow_start_queue_offset;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef IPA_OFFLOAD
|
||||
|
@@ -1019,6 +1019,10 @@ ol_rx_deliver(struct ol_txrx_vdev_t *vdev,
|
||||
qdf_nbuf_t next = qdf_nbuf_next(msdu);
|
||||
|
||||
rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu);
|
||||
/* for HL, point to payload right now*/
|
||||
if (pdev->cfg.is_high_latency)
|
||||
qdf_nbuf_pull_head(msdu,
|
||||
htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc));
|
||||
|
||||
#ifdef QCA_SUPPORT_SW_TXRX_ENCAP
|
||||
info.is_msdu_cmpl_mpdu =
|
||||
|
@@ -104,16 +104,178 @@ const struct ol_rx_defrag_cipher f_wep = {
|
||||
0,
|
||||
};
|
||||
|
||||
inline struct ieee80211_frame *ol_rx_frag_get_mac_hdr(
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
/**
|
||||
* ol_rx_frag_get_mac_hdr() - retrieve mac header
|
||||
* @htt_pdev: pointer to htt pdev handle
|
||||
* @frag: rx fragment
|
||||
*
|
||||
* Return: pointer to ieee mac header of frag
|
||||
*/
|
||||
static struct ieee80211_frame *ol_rx_frag_get_mac_hdr(
|
||||
htt_pdev_handle htt_pdev, qdf_nbuf_t frag)
|
||||
{
|
||||
void *rx_desc;
|
||||
int rx_desc_len;
|
||||
|
||||
rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag);
|
||||
rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc);
|
||||
return (struct ieee80211_frame *)(qdf_nbuf_data(frag) + rx_desc_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_rx_frag_pull_hdr() - point to payload of rx frag
|
||||
* @htt_pdev: pointer to htt pdev handle
|
||||
* @frag: rx fragment
|
||||
* @hdrsize: header size
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev,
|
||||
qdf_nbuf_t frag, int hdrsize)
|
||||
{
|
||||
void *rx_desc;
|
||||
int rx_desc_len;
|
||||
|
||||
rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag);
|
||||
rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc);
|
||||
qdf_nbuf_pull_head(frag, rx_desc_len + hdrsize);
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_rx_frag_clone() - clone the rx frag
|
||||
* @frag: rx fragment to clone from
|
||||
*
|
||||
* Return: cloned buffer
|
||||
*/
|
||||
static inline qdf_nbuf_t
|
||||
ol_rx_frag_clone(qdf_nbuf_t frag)
|
||||
{
|
||||
return qdf_nbuf_clone(frag);
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_rx_frag_desc_adjust() - adjust rx frag descriptor position
|
||||
* @pdev: pointer to txrx handle
|
||||
* @msdu: msdu
|
||||
* @rx_desc_old_position: rx descriptor old position
|
||||
* @ind_old_position:index of old position
|
||||
* @rx_desc_len: rx desciptor length
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static void
|
||||
ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev,
|
||||
qdf_nbuf_t msdu,
|
||||
void **rx_desc_old_position,
|
||||
void **ind_old_position, int *rx_desc_len)
|
||||
{
|
||||
*rx_desc_old_position = htt_rx_msdu_desc_retrieve(pdev->htt_pdev,
|
||||
msdu);
|
||||
*ind_old_position = *rx_desc_old_position - HTT_RX_IND_HL_BYTES;
|
||||
*rx_desc_len = htt_rx_msdu_rx_desc_size_hl(pdev->htt_pdev,
|
||||
*rx_desc_old_position);
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_rx_frag_restructure() - point to payload for HL
|
||||
* @pdev: physical device object
|
||||
* @msdu: the buffer containing the MSDU payload
|
||||
* @rx_desc_old_position: rx MSDU descriptor
|
||||
* @ind_old_position: rx msdu indication
|
||||
* @f_type: pointing to rx defrag cipher
|
||||
* @rx_desc_len: length by which rx descriptor to move
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static void
|
||||
ol_rx_frag_restructure(
|
||||
ol_txrx_pdev_handle pdev,
|
||||
qdf_nbuf_t msdu,
|
||||
void *rx_desc_old_position,
|
||||
void *ind_old_position,
|
||||
const struct ol_rx_defrag_cipher *f_type,
|
||||
int rx_desc_len)
|
||||
{
|
||||
if ((ind_old_position == NULL) || (rx_desc_old_position == NULL)) {
|
||||
TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
|
||||
"ind_old_position,rx_desc_old_position is NULL\n");
|
||||
ASSERT(0);
|
||||
return;
|
||||
}
|
||||
/* move rx description*/
|
||||
qdf_mem_move(rx_desc_old_position + f_type->ic_header,
|
||||
rx_desc_old_position, rx_desc_len);
|
||||
/* move rx indication*/
|
||||
qdf_mem_move(ind_old_position + f_type->ic_header, ind_old_position,
|
||||
HTT_RX_IND_HL_BYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_rx_get_desc_len() - point to payload for HL
|
||||
* @htt_pdev: the HTT instance the rx data was received on
|
||||
* @wbuf: buffer containing the MSDU payload
|
||||
* @rx_desc_old_position: rx MSDU descriptor
|
||||
*
|
||||
* Return: Return the HL rx desc size
|
||||
*/
|
||||
static
|
||||
int ol_rx_get_desc_len(htt_pdev_handle htt_pdev,
|
||||
qdf_nbuf_t wbuf,
|
||||
void **rx_desc_old_position)
|
||||
{
|
||||
int rx_desc_len = 0;
|
||||
*rx_desc_old_position = htt_rx_msdu_desc_retrieve(htt_pdev, wbuf);
|
||||
rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev,
|
||||
*rx_desc_old_position);
|
||||
|
||||
return rx_desc_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_rx_defrag_push_rx_desc() - point to payload for HL
|
||||
* @nbuf: buffer containing the MSDU payload
|
||||
* @rx_desc_old_position: rx MSDU descriptor
|
||||
* @ind_old_position: rx msdu indication
|
||||
* @rx_desc_len: HL rx desc size
|
||||
*
|
||||
* Return: Return the HL rx desc size
|
||||
*/
|
||||
static
|
||||
void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf,
|
||||
void *rx_desc_old_position,
|
||||
void *ind_old_position,
|
||||
int rx_desc_len)
|
||||
{
|
||||
qdf_nbuf_push_head(nbuf, rx_desc_len);
|
||||
qdf_mem_move(
|
||||
qdf_nbuf_data(nbuf), rx_desc_old_position, rx_desc_len);
|
||||
qdf_mem_move(
|
||||
qdf_nbuf_data(nbuf) - HTT_RX_IND_HL_BYTES, ind_old_position,
|
||||
HTT_RX_IND_HL_BYTES);
|
||||
}
|
||||
#else
|
||||
|
||||
static inline struct ieee80211_frame *ol_rx_frag_get_mac_hdr(
|
||||
htt_pdev_handle htt_pdev,
|
||||
qdf_nbuf_t frag)
|
||||
{
|
||||
return
|
||||
(struct ieee80211_frame *) qdf_nbuf_data(frag);
|
||||
}
|
||||
#define ol_rx_frag_pull_hdr(pdev, frag, hdrsize) \
|
||||
|
||||
static inline void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev,
|
||||
qdf_nbuf_t frag, int hdrsize)
|
||||
{
|
||||
qdf_nbuf_pull_head(frag, hdrsize);
|
||||
#define OL_RX_FRAG_CLONE(frag) NULL /* no-op */
|
||||
}
|
||||
|
||||
static inline qdf_nbuf_t
|
||||
ol_rx_frag_clone(qdf_nbuf_t frag)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev,
|
||||
@@ -126,6 +288,38 @@ ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev,
|
||||
*rx_desc_len = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_rx_frag_restructure(
|
||||
ol_txrx_pdev_handle pdev,
|
||||
qdf_nbuf_t msdu,
|
||||
void *rx_desc_old_position,
|
||||
void *ind_old_position,
|
||||
const struct ol_rx_defrag_cipher *f_type,
|
||||
int rx_desc_len)
|
||||
{
|
||||
/* no op */
|
||||
return;
|
||||
}
|
||||
|
||||
static inline
|
||||
int ol_rx_get_desc_len(htt_pdev_handle htt_pdev,
|
||||
qdf_nbuf_t wbuf,
|
||||
void **rx_desc_old_position)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf,
|
||||
void *rx_desc_old_position,
|
||||
void *ind_old_position,
|
||||
int rx_desc_len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_HL_SUPPORT */
|
||||
|
||||
|
||||
/*
|
||||
* Process incoming fragments
|
||||
*/
|
||||
@@ -302,7 +496,7 @@ ol_rx_fraglist_insert(htt_pdev_handle htt_pdev,
|
||||
qdf_nbuf_t frag_clone;
|
||||
|
||||
qdf_assert(frag);
|
||||
frag_clone = OL_RX_FRAG_CLONE(frag);
|
||||
frag_clone = ol_rx_frag_clone(frag);
|
||||
frag = frag_clone ? frag_clone : frag;
|
||||
|
||||
mac_hdr = (struct ieee80211_frame *)
|
||||
@@ -608,6 +802,13 @@ ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev,
|
||||
return OL_RX_DEFRAG_ERR;
|
||||
|
||||
qdf_mem_move(origHdr + f_tkip.ic_header, origHdr, hdrlen);
|
||||
ol_rx_frag_restructure(
|
||||
pdev,
|
||||
msdu,
|
||||
rx_desc_old_position,
|
||||
ind_old_position,
|
||||
&f_tkip,
|
||||
rx_desc_len);
|
||||
qdf_nbuf_pull_head(msdu, f_tkip.ic_header);
|
||||
qdf_nbuf_trim_tail(msdu, f_tkip.ic_trailer);
|
||||
return OL_RX_DEFRAG_OK;
|
||||
@@ -630,6 +831,13 @@ ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t hdrlen)
|
||||
&ind_old_position, &rx_desc_len);
|
||||
origHdr = (uint8_t *) (qdf_nbuf_data(msdu) + rx_desc_len);
|
||||
qdf_mem_move(origHdr + f_wep.ic_header, origHdr, hdrlen);
|
||||
ol_rx_frag_restructure(
|
||||
pdev,
|
||||
msdu,
|
||||
rx_desc_old_position,
|
||||
ind_old_position,
|
||||
&f_wep,
|
||||
rx_desc_len);
|
||||
qdf_nbuf_pull_head(msdu, f_wep.ic_header);
|
||||
qdf_nbuf_trim_tail(msdu, f_wep.ic_trailer);
|
||||
return OL_RX_DEFRAG_OK;
|
||||
@@ -694,6 +902,13 @@ ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev,
|
||||
return OL_RX_DEFRAG_ERR;
|
||||
|
||||
qdf_mem_move(origHdr + f_ccmp.ic_header, origHdr, hdrlen);
|
||||
ol_rx_frag_restructure(
|
||||
pdev,
|
||||
nbuf,
|
||||
rx_desc_old_position,
|
||||
ind_old_position,
|
||||
&f_ccmp,
|
||||
rx_desc_len);
|
||||
qdf_nbuf_pull_head(nbuf, f_ccmp.ic_header);
|
||||
|
||||
return OL_RX_DEFRAG_OK;
|
||||
@@ -788,6 +1003,7 @@ ol_rx_defrag_mic(ol_txrx_pdev_handle pdev,
|
||||
void *rx_desc_old_position = NULL;
|
||||
void *ind_old_position = NULL;
|
||||
int rx_desc_len = 0;
|
||||
htt_pdev_handle htt_pdev = pdev->htt_pdev;
|
||||
|
||||
ol_rx_frag_desc_adjust(pdev,
|
||||
wbuf,
|
||||
@@ -831,7 +1047,8 @@ ol_rx_defrag_mic(ol_txrx_pdev_handle pdev,
|
||||
if (wbuf == NULL)
|
||||
return OL_RX_DEFRAG_ERR;
|
||||
|
||||
rx_desc_len = 0;
|
||||
rx_desc_len = ol_rx_get_desc_len(htt_pdev, wbuf,
|
||||
&rx_desc_old_position);
|
||||
|
||||
if (space != 0) {
|
||||
const uint8_t *data_next;
|
||||
@@ -1008,6 +1225,9 @@ void ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu)
|
||||
|
||||
qdf_mem_copy(eth_hdr->ethertype, llchdr.ethertype,
|
||||
sizeof(llchdr.ethertype));
|
||||
|
||||
ol_rx_defrag_push_rx_desc(msdu, rx_desc_old_position,
|
||||
ind_old_position, rx_desc_len);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1058,5 +1278,8 @@ ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev,
|
||||
if (wh)
|
||||
wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS;
|
||||
|
||||
ol_rx_defrag_push_rx_desc(nbuf, rx_desc_old_position,
|
||||
ind_old_position, rx_desc_len);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -121,7 +121,18 @@ static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu)
|
||||
*/
|
||||
qdf_nbuf_set_next(msdu, NULL); /* add NULL terminator */
|
||||
|
||||
msdu = OL_TX_LL(vdev, msdu);
|
||||
/* for HL, point to payload before send to tx again.*/
|
||||
if (pdev->cfg.is_high_latency) {
|
||||
void *rx_desc;
|
||||
|
||||
rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev,
|
||||
msdu);
|
||||
qdf_nbuf_pull_head(msdu,
|
||||
htt_rx_msdu_rx_desc_size_hl(pdev->htt_pdev,
|
||||
rx_desc));
|
||||
}
|
||||
|
||||
msdu = OL_TX_SEND(vdev, msdu);
|
||||
|
||||
if (msdu) {
|
||||
/*
|
||||
@@ -131,6 +142,7 @@ static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu)
|
||||
*/
|
||||
qdf_nbuf_tx_free(msdu, QDF_NBUF_PKT_ERROR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -232,6 +244,7 @@ ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev,
|
||||
ol_rx_deliver(vdev, peer, tid, deliver_list_head);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -41,7 +41,10 @@
|
||||
#include <ol_txrx.h>
|
||||
|
||||
/* internal header files relevant only for HL systems */
|
||||
#include <ol_tx_classify.h> /* ol_tx_classify, ol_tx_classify_mgmt */
|
||||
#include <ol_tx_queue.h> /* ol_tx_enqueue */
|
||||
#include <ol_tx_sched.h> /* ol_tx_sched */
|
||||
|
||||
|
||||
/* internal header files relevant only for specific systems (Pronto) */
|
||||
#include <ol_txrx_encap.h> /* OL_TX_ENCAP, etc */
|
||||
@@ -165,7 +168,7 @@ qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle vdev, qdf_nbuf_t skb)
|
||||
|
||||
/* Terminate the (single-element) list of tx frames */
|
||||
qdf_nbuf_set_next(skb, NULL);
|
||||
ret = OL_TX_LL(vdev, skb);
|
||||
ret = OL_TX_SEND(vdev, skb);
|
||||
if (ret) {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_WARN,
|
||||
"%s: Failed to tx", __func__);
|
||||
@@ -202,7 +205,7 @@ qdf_nbuf_t ol_tx_send_ipa_data_frame(void *vdev,
|
||||
|
||||
/* Terminate the (single-element) list of tx frames */
|
||||
qdf_nbuf_set_next(skb, NULL);
|
||||
ret = OL_TX_LL((struct ol_txrx_vdev_t *)vdev, skb);
|
||||
ret = OL_TX_SEND((struct ol_txrx_vdev_t *)vdev, skb);
|
||||
if (ret) {
|
||||
TXRX_PRINT(TXRX_PRINT_LEVEL_WARN,
|
||||
"%s: Failed to tx", __func__);
|
||||
@@ -1041,7 +1044,8 @@ static inline uint8_t ol_txrx_tx_raw_subtype(enum ol_tx_spec tx_spec)
|
||||
|
||||
qdf_nbuf_t
|
||||
ol_tx_non_std_ll(ol_txrx_vdev_handle vdev,
|
||||
enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list)
|
||||
enum ol_tx_spec tx_spec,
|
||||
qdf_nbuf_t msdu_list)
|
||||
{
|
||||
qdf_nbuf_t msdu = msdu_list;
|
||||
htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev;
|
||||
@@ -1082,14 +1086,14 @@ ol_tx_non_std_ll(ol_txrx_vdev_handle vdev,
|
||||
uint8_t sub_type =
|
||||
ol_txrx_tx_raw_subtype(tx_spec);
|
||||
htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc,
|
||||
htt_pkt_type_native_wifi,
|
||||
sub_type);
|
||||
htt_pkt_type_native_wifi,
|
||||
sub_type);
|
||||
} else if (ol_txrx_tx_is_raw(tx_spec)) {
|
||||
/* different types of raw frames */
|
||||
uint8_t sub_type =
|
||||
ol_txrx_tx_raw_subtype(tx_spec);
|
||||
htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc,
|
||||
htt_pkt_type_raw, sub_type);
|
||||
htt_pkt_type_raw, sub_type);
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -1125,9 +1129,10 @@ ol_tx_non_std_ll(ol_txrx_vdev_handle vdev,
|
||||
|
||||
/**
|
||||
* parse_ocb_tx_header() - Function to check for OCB
|
||||
* TX control header on a packet and extract it if present
|
||||
*
|
||||
* @msdu: Pointer to OS packet (qdf_nbuf_t)
|
||||
* @tx_ctrl: TX control header on a packet and extract it if present
|
||||
*
|
||||
* Return: true if ocb parsing is successful
|
||||
*/
|
||||
#define OCB_HEADER_VERSION 1
|
||||
bool parse_ocb_tx_header(qdf_nbuf_t msdu,
|
||||
@@ -1137,7 +1142,7 @@ bool parse_ocb_tx_header(qdf_nbuf_t msdu,
|
||||
struct ocb_tx_ctrl_hdr_t *tx_ctrl_hdr;
|
||||
|
||||
/* Check if TX control header is present */
|
||||
eth_hdr_p = (struct ether_header *) qdf_nbuf_data(msdu);
|
||||
eth_hdr_p = (struct ether_header *)qdf_nbuf_data(msdu);
|
||||
if (eth_hdr_p->ether_type != QDF_SWAP_U16(ETHERTYPE_OCB_TX))
|
||||
/* TX control header is not present. Nothing to do.. */
|
||||
return true;
|
||||
@@ -1146,12 +1151,12 @@ bool parse_ocb_tx_header(qdf_nbuf_t msdu,
|
||||
qdf_nbuf_pull_head(msdu, sizeof(struct ether_header));
|
||||
|
||||
/* Parse the TX control header */
|
||||
tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t *) qdf_nbuf_data(msdu);
|
||||
tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t *)qdf_nbuf_data(msdu);
|
||||
|
||||
if (tx_ctrl_hdr->version == OCB_HEADER_VERSION) {
|
||||
if (tx_ctrl)
|
||||
qdf_mem_copy(tx_ctrl, tx_ctrl_hdr,
|
||||
sizeof(*tx_ctrl_hdr));
|
||||
sizeof(*tx_ctrl_hdr));
|
||||
} else {
|
||||
/* The TX control header is invalid. */
|
||||
return false;
|
||||
@@ -1162,6 +1167,440 @@ bool parse_ocb_tx_header(qdf_nbuf_t msdu,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(CONFIG_TX_DESC_HI_PRIO_RESERVE)
|
||||
|
||||
/**
|
||||
* ol_tx_hl_desc_alloc() - Allocate and initialize a tx descriptor
|
||||
* for a HL system.
|
||||
* @pdev: the data physical device sending the data
|
||||
* @vdev: the virtual device sending the data
|
||||
* @msdu: the tx frame
|
||||
* @msdu_info: the tx meta data
|
||||
*
|
||||
* Return: the tx decriptor
|
||||
*/
|
||||
static inline
|
||||
struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
qdf_nbuf_t msdu,
|
||||
struct ol_txrx_msdu_info_t *msdu_info)
|
||||
{
|
||||
struct ol_tx_desc_t *tx_desc = NULL;
|
||||
|
||||
if (qdf_atomic_read(&pdev->tx_queue.rsrc_cnt) >
|
||||
TXRX_HL_TX_DESC_HI_PRIO_RESERVED) {
|
||||
tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info);
|
||||
} else if (qdf_nbuf_is_ipv4_pkt(msdu) == true) {
|
||||
if ((qdf_nbuf_is_ipv4_dhcp_pkt(msdu) == true) ||
|
||||
(qdf_nbuf_is_ipv4_eapol_pkt(msdu) == true)) {
|
||||
tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info);
|
||||
TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
|
||||
"Provided tx descriptor from reserve pool for DHCP/EAPOL\n");
|
||||
}
|
||||
}
|
||||
return tx_desc;
|
||||
}
|
||||
#else
|
||||
|
||||
static inline
|
||||
struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
qdf_nbuf_t msdu,
|
||||
struct ol_txrx_msdu_info_t *msdu_info)
|
||||
{
|
||||
struct ol_tx_desc_t *tx_desc = NULL;
|
||||
tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info);
|
||||
return tx_desc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
/**
|
||||
* ol_txrx_mgmt_tx_desc_alloc() - Allocate and initialize a tx descriptor
|
||||
* for management frame
|
||||
* @pdev: the data physical device sending the data
|
||||
* @vdev: the virtual device sending the data
|
||||
* @tx_mgmt_frm: the tx managment frame
|
||||
* @tx_msdu_info: the tx meta data
|
||||
*
|
||||
* Return: the tx decriptor
|
||||
*/
|
||||
static inline
|
||||
struct ol_tx_desc_t *
|
||||
ol_txrx_mgmt_tx_desc_alloc(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
qdf_nbuf_t tx_mgmt_frm,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
struct ol_tx_desc_t *tx_desc;
|
||||
tx_msdu_info->htt.action.tx_comp_req = 1;
|
||||
tx_desc = ol_tx_desc_hl(pdev, vdev, tx_mgmt_frm, tx_msdu_info);
|
||||
return tx_desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_txrx_mgmt_send_frame() - send a management frame
|
||||
* @vdev: virtual device sending the frame
|
||||
* @tx_desc: tx desc
|
||||
* @tx_mgmt_frm: management frame to send
|
||||
* @tx_msdu_info: the tx meta data
|
||||
* @chanfreq: download change frequency
|
||||
*
|
||||
* Return:
|
||||
* 0 -> the frame is accepted for transmission, -OR-
|
||||
* 1 -> the frame was not accepted
|
||||
*/
|
||||
static inline
|
||||
int ol_txrx_mgmt_send_frame(
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
qdf_nbuf_t tx_mgmt_frm,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info,
|
||||
uint16_t chanfreq)
|
||||
{
|
||||
struct ol_txrx_pdev_t *pdev = vdev->pdev;
|
||||
struct ol_tx_frms_queue_t *txq;
|
||||
/*
|
||||
* 1. Look up the peer and queue the frame in the peer's mgmt queue.
|
||||
* 2. Invoke the download scheduler.
|
||||
*/
|
||||
txq = ol_tx_classify_mgmt(vdev, tx_desc, tx_mgmt_frm, tx_msdu_info);
|
||||
if (!txq) {
|
||||
/*TXRX_STATS_MSDU_LIST_INCR(vdev->pdev, tx.dropped.no_txq,
|
||||
msdu);*/
|
||||
qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt);
|
||||
ol_tx_desc_frame_free_nonstd(vdev->pdev, tx_desc,
|
||||
1 /* error */);
|
||||
if (tx_msdu_info->peer) {
|
||||
/* remove the peer reference added above */
|
||||
ol_txrx_peer_unref_delete(tx_msdu_info->peer);
|
||||
}
|
||||
return 1; /* can't accept the tx mgmt frame */
|
||||
}
|
||||
/* Initialize the HTT tx desc l2 header offset field.
|
||||
* Even though tx encap does not apply to mgmt frames,
|
||||
* htt_tx_desc_mpdu_header still needs to be called,
|
||||
* to specifiy that there was no L2 header added by tx encap,
|
||||
* so the frame's length does not need to be adjusted to account for
|
||||
* an added L2 header.
|
||||
*/
|
||||
htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0);
|
||||
htt_tx_desc_init(
|
||||
pdev->htt_pdev, tx_desc->htt_tx_desc,
|
||||
tx_desc->htt_tx_desc_paddr,
|
||||
ol_tx_desc_id(pdev, tx_desc),
|
||||
tx_mgmt_frm,
|
||||
&tx_msdu_info->htt, &tx_msdu_info->tso_info, NULL, 0);
|
||||
htt_tx_desc_display(tx_desc->htt_tx_desc);
|
||||
htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq);
|
||||
|
||||
ol_tx_enqueue(vdev->pdev, txq, tx_desc, tx_msdu_info);
|
||||
if (tx_msdu_info->peer) {
|
||||
/* remove the peer reference added above */
|
||||
ol_txrx_peer_unref_delete(tx_msdu_info->peer);
|
||||
}
|
||||
ol_tx_sched(vdev->pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline
|
||||
struct ol_tx_desc_t *
|
||||
ol_txrx_mgmt_tx_desc_alloc(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
qdf_nbuf_t tx_mgmt_frm,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
struct ol_tx_desc_t *tx_desc;
|
||||
/* For LL tx_comp_req is not used so initialized to 0 */
|
||||
tx_msdu_info->htt.action.tx_comp_req = 0;
|
||||
tx_desc = ol_tx_desc_ll(pdev, vdev, tx_mgmt_frm, tx_msdu_info);
|
||||
/* FIX THIS -
|
||||
* The FW currently has trouble using the host's fragments table
|
||||
* for management frames. Until this is fixed, rather than
|
||||
* specifying the fragment table to the FW, specify just the
|
||||
* address of the initial fragment.
|
||||
*/
|
||||
#if defined(HELIUMPLUS_PADDR64)
|
||||
/* dump_frag_desc("ol_txrx_mgmt_send(): after ol_tx_desc_ll",
|
||||
tx_desc); */
|
||||
#endif /* defined(HELIUMPLUS_PADDR64) */
|
||||
if (tx_desc) {
|
||||
/*
|
||||
* Following the call to ol_tx_desc_ll, frag 0 is the
|
||||
* HTT tx HW descriptor, and the frame payload is in
|
||||
* frag 1.
|
||||
*/
|
||||
htt_tx_desc_frags_table_set(
|
||||
pdev->htt_pdev,
|
||||
tx_desc->htt_tx_desc,
|
||||
qdf_nbuf_get_frag_paddr(tx_mgmt_frm, 1),
|
||||
0, 0);
|
||||
#if defined(HELIUMPLUS_PADDR64) && defined(HELIUMPLUS_DEBUG)
|
||||
dump_frag_desc(
|
||||
"after htt_tx_desc_frags_table_set",
|
||||
tx_desc);
|
||||
#endif /* defined(HELIUMPLUS_PADDR64) */
|
||||
}
|
||||
|
||||
return tx_desc;
|
||||
}
|
||||
|
||||
static inline
|
||||
int ol_txrx_mgmt_send_frame(
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
qdf_nbuf_t tx_mgmt_frm,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info,
|
||||
uint16_t chanfreq)
|
||||
{
|
||||
struct ol_txrx_pdev_t *pdev = vdev->pdev;
|
||||
htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq);
|
||||
QDF_NBUF_CB_TX_PACKET_TRACK(tx_desc->netbuf) =
|
||||
QDF_NBUF_TX_PKT_MGMT_TRACK;
|
||||
ol_tx_send_nonstd(pdev, tx_desc, tx_mgmt_frm,
|
||||
htt_pkt_type_mgmt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ol_tx_hl_base() - send tx frames for a HL system.
|
||||
* @vdev: the virtual device sending the data
|
||||
* @tx_spec: indicate what non-standard transmission actions to apply
|
||||
* @msdu_list: the tx frames to send
|
||||
* @tx_comp_req: tx completion req
|
||||
*
|
||||
* Return: NULL if all MSDUs are accepted
|
||||
*/
|
||||
static inline qdf_nbuf_t
|
||||
ol_tx_hl_base(
|
||||
ol_txrx_vdev_handle vdev,
|
||||
enum ol_tx_spec tx_spec,
|
||||
qdf_nbuf_t msdu_list,
|
||||
int tx_comp_req)
|
||||
{
|
||||
struct ol_txrx_pdev_t *pdev = vdev->pdev;
|
||||
qdf_nbuf_t msdu = msdu_list;
|
||||
struct ol_txrx_msdu_info_t tx_msdu_info;
|
||||
struct ocb_tx_ctrl_hdr_t tx_ctrl;
|
||||
|
||||
htt_pdev_handle htt_pdev = pdev->htt_pdev;
|
||||
tx_msdu_info.peer = NULL;
|
||||
tx_msdu_info.tso_info.is_tso = 0;
|
||||
|
||||
/*
|
||||
* The msdu_list variable could be used instead of the msdu var,
|
||||
* but just to clarify which operations are done on a single MSDU
|
||||
* vs. a list of MSDUs, use a distinct variable for single MSDUs
|
||||
* within the list.
|
||||
*/
|
||||
while (msdu) {
|
||||
qdf_nbuf_t next;
|
||||
struct ol_tx_frms_queue_t *txq;
|
||||
struct ol_tx_desc_t *tx_desc = NULL;
|
||||
|
||||
qdf_mem_zero(&tx_ctrl, sizeof(tx_ctrl));
|
||||
|
||||
/*
|
||||
* The netbuf will get stored into a (peer-TID) tx queue list
|
||||
* inside the ol_tx_classify_store function or else dropped,
|
||||
* so store the next pointer immediately.
|
||||
*/
|
||||
next = qdf_nbuf_next(msdu);
|
||||
|
||||
tx_desc = ol_tx_hl_desc_alloc(pdev, vdev, msdu, &tx_msdu_info);
|
||||
|
||||
if (!tx_desc) {
|
||||
/*
|
||||
* If we're out of tx descs, there's no need to try
|
||||
* to allocate tx descs for the remaining MSDUs.
|
||||
*/
|
||||
TXRX_STATS_MSDU_LIST_INCR(pdev, tx.dropped.host_reject,
|
||||
msdu);
|
||||
return msdu; /* the list of unaccepted MSDUs */
|
||||
}
|
||||
|
||||
/* OL_TXRX_PROT_AN_LOG(pdev->prot_an_tx_sent, msdu);*/
|
||||
|
||||
if (tx_spec != OL_TX_SPEC_STD) {
|
||||
#if defined(FEATURE_WLAN_TDLS)
|
||||
if (tx_spec & OL_TX_SPEC_NO_FREE) {
|
||||
tx_desc->pkt_type = OL_TX_FRM_NO_FREE;
|
||||
} else if (tx_spec & OL_TX_SPEC_TSO) {
|
||||
#else
|
||||
if (tx_spec & OL_TX_SPEC_TSO) {
|
||||
#endif
|
||||
tx_desc->pkt_type = OL_TX_FRM_TSO;
|
||||
}
|
||||
if (ol_txrx_tx_is_raw(tx_spec)) {
|
||||
/* CHECK THIS: does this need
|
||||
* to happen after htt_tx_desc_init?
|
||||
*/
|
||||
/* different types of raw frames */
|
||||
u_int8_t sub_type =
|
||||
ol_txrx_tx_raw_subtype(
|
||||
tx_spec);
|
||||
htt_tx_desc_type(htt_pdev,
|
||||
tx_desc->htt_tx_desc,
|
||||
htt_pkt_type_raw,
|
||||
sub_type);
|
||||
}
|
||||
}
|
||||
|
||||
tx_msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu);
|
||||
tx_msdu_info.htt.info.vdev_id = vdev->vdev_id;
|
||||
tx_msdu_info.htt.info.frame_type = htt_frm_type_data;
|
||||
tx_msdu_info.htt.info.l2_hdr_type = pdev->htt_pkt_type;
|
||||
tx_msdu_info.htt.action.tx_comp_req = tx_comp_req;
|
||||
|
||||
/* If the vdev is in OCB mode,
|
||||
* parse the tx control header.
|
||||
*/
|
||||
if (vdev->opmode == wlan_op_mode_ocb) {
|
||||
if (!parse_ocb_tx_header(msdu, &tx_ctrl)) {
|
||||
/* There was an error parsing
|
||||
* the header.Skip this packet.
|
||||
*/
|
||||
goto MSDU_LOOP_BOTTOM;
|
||||
}
|
||||
}
|
||||
|
||||
txq = ol_tx_classify(vdev, tx_desc, msdu,
|
||||
&tx_msdu_info);
|
||||
|
||||
if ((!txq) || TX_FILTER_CHECK(&tx_msdu_info)) {
|
||||
/* drop this frame,
|
||||
* but try sending subsequent frames
|
||||
*/
|
||||
/*TXRX_STATS_MSDU_LIST_INCR(pdev,
|
||||
tx.dropped.no_txq,
|
||||
msdu);*/
|
||||
qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt);
|
||||
ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1);
|
||||
if (tx_msdu_info.peer) {
|
||||
/* remove the peer reference
|
||||
* added above */
|
||||
ol_txrx_peer_unref_delete(
|
||||
tx_msdu_info.peer);
|
||||
}
|
||||
goto MSDU_LOOP_BOTTOM;
|
||||
}
|
||||
|
||||
if (tx_msdu_info.peer) {
|
||||
/*If the state is not associated then drop all
|
||||
*the data packets received for that peer*/
|
||||
if (tx_msdu_info.peer->state ==
|
||||
OL_TXRX_PEER_STATE_DISC) {
|
||||
qdf_atomic_inc(
|
||||
&pdev->tx_queue.rsrc_cnt);
|
||||
ol_tx_desc_frame_free_nonstd(pdev,
|
||||
tx_desc,
|
||||
1);
|
||||
ol_txrx_peer_unref_delete(
|
||||
tx_msdu_info.peer);
|
||||
msdu = next;
|
||||
continue;
|
||||
} else if (tx_msdu_info.peer->state !=
|
||||
OL_TXRX_PEER_STATE_AUTH) {
|
||||
if (tx_msdu_info.htt.info.ethertype !=
|
||||
ETHERTYPE_PAE &&
|
||||
tx_msdu_info.htt.info.ethertype
|
||||
!= ETHERTYPE_WAI) {
|
||||
qdf_atomic_inc(
|
||||
&pdev->tx_queue.
|
||||
rsrc_cnt);
|
||||
ol_tx_desc_frame_free_nonstd(
|
||||
pdev,
|
||||
tx_desc, 1);
|
||||
ol_txrx_peer_unref_delete(
|
||||
tx_msdu_info.peer);
|
||||
msdu = next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Initialize the HTT tx desc l2 header offset field.
|
||||
* htt_tx_desc_mpdu_header needs to be called to
|
||||
* make sure, the l2 header size is initialized
|
||||
* correctly to handle cases where TX ENCAP is disabled
|
||||
* or Tx Encap fails to perform Encap
|
||||
*/
|
||||
htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0);
|
||||
|
||||
/*
|
||||
* Note: when the driver is built without support for
|
||||
* SW tx encap,the following macro is a no-op.
|
||||
* When the driver is built with support for SW tx
|
||||
* encap, it performs encap, and if an error is
|
||||
* encountered, jumps to the MSDU_LOOP_BOTTOM label.
|
||||
*/
|
||||
OL_TX_ENCAP_WRAPPER(pdev, vdev, tx_desc, msdu,
|
||||
tx_msdu_info);
|
||||
|
||||
/* initialize the HW tx descriptor */
|
||||
htt_tx_desc_init(
|
||||
pdev->htt_pdev, tx_desc->htt_tx_desc,
|
||||
tx_desc->htt_tx_desc_paddr,
|
||||
ol_tx_desc_id(pdev, tx_desc),
|
||||
msdu,
|
||||
&tx_msdu_info.htt,
|
||||
&tx_msdu_info.tso_info,
|
||||
&tx_ctrl,
|
||||
vdev->opmode == wlan_op_mode_ocb);
|
||||
/*
|
||||
* If debug display is enabled, show the meta-data
|
||||
* being downloaded to the target via the
|
||||
* HTT tx descriptor.
|
||||
*/
|
||||
htt_tx_desc_display(tx_desc->htt_tx_desc);
|
||||
|
||||
ol_tx_enqueue(pdev, txq, tx_desc, &tx_msdu_info);
|
||||
if (tx_msdu_info.peer) {
|
||||
OL_TX_PEER_STATS_UPDATE(tx_msdu_info.peer,
|
||||
msdu);
|
||||
/* remove the peer reference added above */
|
||||
ol_txrx_peer_unref_delete(tx_msdu_info.peer);
|
||||
}
|
||||
MSDU_LOOP_BOTTOM:
|
||||
msdu = next;
|
||||
}
|
||||
ol_tx_sched(pdev);
|
||||
return NULL; /* all MSDUs were accepted */
|
||||
}
|
||||
|
||||
qdf_nbuf_t
|
||||
ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list)
|
||||
{
|
||||
struct ol_txrx_pdev_t *pdev = vdev->pdev;
|
||||
int tx_comp_req = pdev->cfg.default_tx_comp_req;
|
||||
return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list, tx_comp_req);
|
||||
}
|
||||
|
||||
qdf_nbuf_t
|
||||
ol_tx_non_std_hl(ol_txrx_vdev_handle vdev,
|
||||
enum ol_tx_spec tx_spec,
|
||||
qdf_nbuf_t msdu_list)
|
||||
{
|
||||
struct ol_txrx_pdev_t *pdev = vdev->pdev;
|
||||
int tx_comp_req = pdev->cfg.default_tx_comp_req;
|
||||
|
||||
if (!tx_comp_req) {
|
||||
if ((tx_spec == OL_TX_SPEC_NO_FREE) &&
|
||||
(pdev->tx_data_callback.func))
|
||||
tx_comp_req = 1;
|
||||
}
|
||||
return ol_tx_hl_base(vdev, tx_spec, msdu_list, tx_comp_req);
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_tx_non_std - Allow the control-path SW to send data frames
|
||||
*
|
||||
@@ -1188,7 +1627,10 @@ qdf_nbuf_t
|
||||
ol_tx_non_std(ol_txrx_vdev_handle vdev,
|
||||
enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list)
|
||||
{
|
||||
return ol_tx_non_std_ll(vdev, tx_spec, msdu_list);
|
||||
if (vdev->pdev->cfg.is_high_latency)
|
||||
return ol_tx_non_std_hl(vdev, tx_spec, msdu_list);
|
||||
else
|
||||
return ol_tx_non_std_ll(vdev, tx_spec, msdu_list);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1297,7 +1739,7 @@ ol_txrx_mgmt_send_ext(ol_txrx_vdev_handle vdev,
|
||||
struct ol_txrx_pdev_t *pdev = vdev->pdev;
|
||||
struct ol_tx_desc_t *tx_desc;
|
||||
struct ol_txrx_msdu_info_t tx_msdu_info;
|
||||
|
||||
int result = 0;
|
||||
tx_msdu_info.tso_info.is_tso = 0;
|
||||
|
||||
tx_msdu_info.htt.action.use_6mbps = use_6mbps;
|
||||
@@ -1348,37 +1790,8 @@ ol_txrx_mgmt_send_ext(ol_txrx_vdev_handle vdev,
|
||||
|
||||
tx_msdu_info.peer = NULL;
|
||||
|
||||
|
||||
/* For LL tx_comp_req is not used so initialized to 0 */
|
||||
tx_msdu_info.htt.action.tx_comp_req = 0;
|
||||
tx_desc = ol_tx_desc_ll(pdev, vdev, tx_mgmt_frm, &tx_msdu_info);
|
||||
/* FIX THIS -
|
||||
* The FW currently has trouble using the host's fragments table
|
||||
* for management frames. Until this is fixed, rather than
|
||||
* specifying the fragment table to the FW, specify just the
|
||||
* address of the initial fragment.
|
||||
*/
|
||||
#if defined(HELIUMPLUS_PADDR64)
|
||||
/* dump_frag_desc("ol_txrx_mgmt_send(): after ol_tx_desc_ll",
|
||||
tx_desc); */
|
||||
#endif /* defined(HELIUMPLUS_PADDR64) */
|
||||
if (tx_desc) {
|
||||
/*
|
||||
* Following the call to ol_tx_desc_ll, frag 0 is the
|
||||
* HTT tx HW descriptor, and the frame payload is in
|
||||
* frag 1.
|
||||
*/
|
||||
htt_tx_desc_frags_table_set(
|
||||
pdev->htt_pdev,
|
||||
tx_desc->htt_tx_desc,
|
||||
qdf_nbuf_get_frag_paddr(tx_mgmt_frm, 1),
|
||||
0, 0);
|
||||
#if defined(HELIUMPLUS_PADDR64) && defined(HELIUMPLUS_DEBUG)
|
||||
dump_frag_desc(
|
||||
"after htt_tx_desc_frags_table_set",
|
||||
tx_desc);
|
||||
#endif /* defined(HELIUMPLUS_PADDR64) */
|
||||
}
|
||||
tx_desc = ol_txrx_mgmt_tx_desc_alloc(pdev, vdev, tx_mgmt_frm,
|
||||
&tx_msdu_info);
|
||||
if (!tx_desc)
|
||||
return -EINVAL; /* can't accept the tx mgmt frame */
|
||||
|
||||
@@ -1386,11 +1799,8 @@ ol_txrx_mgmt_send_ext(ol_txrx_vdev_handle vdev,
|
||||
TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES);
|
||||
tx_desc->pkt_type = type + OL_TXRX_MGMT_TYPE_BASE;
|
||||
|
||||
htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq);
|
||||
QDF_NBUF_CB_TX_PACKET_TRACK(tx_desc->netbuf) =
|
||||
QDF_NBUF_TX_PKT_MGMT_TRACK;
|
||||
ol_tx_send_nonstd(pdev, tx_desc, tx_mgmt_frm,
|
||||
htt_pkt_type_mgmt);
|
||||
result = ol_txrx_mgmt_send_frame(vdev, tx_desc, tx_mgmt_frm,
|
||||
&tx_msdu_info, chanfreq);
|
||||
|
||||
return 0; /* accepted the tx mgmt frame */
|
||||
}
|
||||
|
@@ -47,6 +47,12 @@ qdf_nbuf_t ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list);
|
||||
|
||||
qdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list);
|
||||
|
||||
#ifdef CONFIG_HL_SUPPORT
|
||||
#define OL_TX_SEND ol_tx_hl
|
||||
#else
|
||||
#define OL_TX_SEND OL_TX_LL
|
||||
#endif
|
||||
|
||||
#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
|
||||
#define OL_TX_LL ol_tx_ll_queue
|
||||
#else
|
||||
@@ -67,6 +73,29 @@ void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ol_tx_non_std_hl() - send non std tx frame.
|
||||
* @vdev: the virtual device sending the data
|
||||
* @tx_spec: indicate what non-standard transmission actions to apply
|
||||
* @msdu_list: the tx frames to send
|
||||
*
|
||||
* Return: NULL if all MSDUs are accepted
|
||||
*/
|
||||
qdf_nbuf_t
|
||||
ol_tx_non_std_hl(ol_txrx_vdev_handle data_vdev,
|
||||
enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list);
|
||||
|
||||
/**
|
||||
* ol_tx_hl() - transmit tx frames for a HL system.
|
||||
* @vdev: the virtual device transmit the data
|
||||
* @msdu_list: the tx frames to send
|
||||
*
|
||||
* Return: NULL if all MSDUs are accepted
|
||||
*/
|
||||
qdf_nbuf_t
|
||||
ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list);
|
||||
|
||||
qdf_nbuf_t
|
||||
ol_tx_non_std_ll(ol_txrx_vdev_handle data_vdev,
|
||||
enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list);
|
||||
|
888
core/dp/txrx/ol_tx_classify.c
Normal file
888
core/dp/txrx/ol_tx_classify.c
Normal file
@@ -0,0 +1,888 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
|
||||
*
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file was originally distributed by Qualcomm Atheros, Inc.
|
||||
* under proprietary terms before Copyright ownership was assigned
|
||||
* to the Linux Foundation.
|
||||
*/
|
||||
|
||||
#include <qdf_nbuf.h> /* qdf_nbuf_t, etc. */
|
||||
#include <htt.h> /* HTT_TX_EXT_TID_MGMT */
|
||||
#include <ol_htt_tx_api.h> /* htt_tx_desc_tid */
|
||||
#include <ol_txrx_api.h> /* ol_txrx_vdev_handle */
|
||||
#include <ol_txrx_ctrl_api.h> /* ol_txrx_sync */
|
||||
#include <ol_txrx.h>
|
||||
#include <ol_txrx_internal.h> /* TXRX_ASSERT1 */
|
||||
#include <ol_txrx_types.h> /* pdev stats */
|
||||
#include <ol_tx_desc.h> /* ol_tx_desc */
|
||||
#include <ol_tx_send.h> /* ol_tx_send */
|
||||
#include <ol_txrx_peer_find.h>
|
||||
#include <ol_tx_classify.h>
|
||||
#include <ol_tx_queue.h>
|
||||
#include <ipv4.h>
|
||||
#include <ipv6_defs.h>
|
||||
#include <ip_prot.h>
|
||||
#include <enet.h> /* ETHERTYPE_VLAN, etc. */
|
||||
#include <cds_ieee80211_common.h> /* ieee80211_frame */
|
||||
|
||||
/*
|
||||
* In theory, this tx classify code could be used on the host or in the target.
|
||||
* Thus, this code uses generic OS primitives, that can be aliased to either
|
||||
* the host's OS primitives or the target's OS primitives.
|
||||
* For now, the following #defines set up these host-specific or
|
||||
* target-specific aliases.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
#define OL_TX_CLASSIFY_EXTENSION(vdev, tx_desc, netbuf, msdu_info, txq)
|
||||
#define OL_TX_CLASSIFY_MGMT_EXTENSION(vdev, tx_desc, netbuf, msdu_info, txq)
|
||||
|
||||
#ifdef QCA_TX_HTT2_SUPPORT
|
||||
static void
|
||||
ol_tx_classify_htt2_frm(
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
qdf_nbuf_t tx_nbuf,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
struct htt_msdu_info_t *htt = &tx_msdu_info->htt;
|
||||
A_UINT8 candi_frm = 0;
|
||||
|
||||
/*
|
||||
* Offload the frame re-order to L3 protocol and ONLY support
|
||||
* TCP protocol now.
|
||||
*/
|
||||
if ((htt->info.l2_hdr_type == htt_pkt_type_ethernet) &&
|
||||
(htt->info.frame_type == htt_frm_type_data) &&
|
||||
htt->info.is_unicast &&
|
||||
(htt->info.ethertype == ETHERTYPE_IPV4)) {
|
||||
struct ipv4_hdr_t *ipHdr;
|
||||
|
||||
ipHdr = (struct ipv4_hdr_t *)(qdf_nbuf_data(tx_nbuf) +
|
||||
htt->info.l3_hdr_offset);
|
||||
if (ipHdr->protocol == IP_PROTOCOL_TCP)
|
||||
candi_frm = 1;
|
||||
}
|
||||
|
||||
qdf_nbuf_set_tx_parallel_dnload_frm(tx_nbuf, candi_frm);
|
||||
}
|
||||
|
||||
#define OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, netbuf, msdu_info) \
|
||||
ol_tx_classify_htt2_frm(vdev, netbuf, msdu_info);
|
||||
#else
|
||||
#define OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, netbuf, msdu_info) /* no-op */
|
||||
#endif /* QCA_TX_HTT2_SUPPORT */
|
||||
/* DHCP go with voice priority; WMM_AC_VO_TID1();*/
|
||||
#define TX_DHCP_TID 6
|
||||
|
||||
#if defined(QCA_BAD_PEER_TX_FLOW_CL)
|
||||
static inline A_BOOL
|
||||
ol_if_tx_bad_peer_txq_overflow(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_peer_t *peer,
|
||||
struct ol_tx_frms_queue_t *txq)
|
||||
{
|
||||
if (peer && pdev && txq && (peer->tx_limit_flag) &&
|
||||
(txq->frms >= pdev->tx_peer_bal.peer_bal_txq_limit))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
static inline A_BOOL ol_if_tx_bad_peer_txq_overflow(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_peer_t *peer,
|
||||
struct ol_tx_frms_queue_t *txq)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* EAPOL go with voice priority: WMM_AC_TO_TID1(WMM_AC_VO);*/
|
||||
#define TX_EAPOL_TID 6
|
||||
|
||||
/* ARP go with voice priority: WMM_AC_TO_TID1(pdev->arp_ac_override)*/
|
||||
#define TX_ARP_TID 6
|
||||
|
||||
/* For non-IP case, use default TID */
|
||||
#define TX_DEFAULT_TID 0
|
||||
|
||||
/*
|
||||
* Determine IP TOS priority
|
||||
* IP Tos format :
|
||||
* (Refer Pg 57 WMM-test-plan-v1.2)
|
||||
* IP-TOS - 8bits
|
||||
* : DSCP(6-bits) ECN(2-bits)
|
||||
* : DSCP - P2 P1 P0 X X X
|
||||
* where (P2 P1 P0) form 802.1D
|
||||
*/
|
||||
static inline A_UINT8
|
||||
ol_tx_tid_by_ipv4(A_UINT8 *pkt)
|
||||
{
|
||||
A_UINT8 ipPri, tid;
|
||||
struct ipv4_hdr_t *ipHdr = (struct ipv4_hdr_t *)pkt;
|
||||
|
||||
ipPri = ipHdr->tos >> 5;
|
||||
tid = ipPri & 0x7;
|
||||
|
||||
return tid;
|
||||
}
|
||||
|
||||
static inline A_UINT8
|
||||
ol_tx_tid_by_ipv6(A_UINT8 *pkt)
|
||||
{
|
||||
return (ipv6_traffic_class((struct ipv6_hdr_t *)pkt) >> 5) & 0x7;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_set_ether_type(
|
||||
A_UINT8 *datap,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
A_UINT16 typeorlength;
|
||||
A_UINT8 *ptr;
|
||||
A_UINT8 *l3_data_ptr;
|
||||
|
||||
if (tx_msdu_info->htt.info.l2_hdr_type == htt_pkt_type_raw) {
|
||||
/* adjust hdr_ptr to RA */
|
||||
struct ieee80211_frame *wh = (struct ieee80211_frame *)datap;
|
||||
|
||||
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
|
||||
IEEE80211_FC0_TYPE_DATA) {
|
||||
struct llc_snap_hdr_t *llc;
|
||||
/* dot11 encapsulated frame */
|
||||
struct ieee80211_qosframe *whqos =
|
||||
(struct ieee80211_qosframe *)datap;
|
||||
if (whqos->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) {
|
||||
tx_msdu_info->htt.info.l3_hdr_offset =
|
||||
sizeof(struct ieee80211_qosframe);
|
||||
} else {
|
||||
tx_msdu_info->htt.info.l3_hdr_offset =
|
||||
sizeof(struct ieee80211_frame);
|
||||
}
|
||||
llc = (struct llc_snap_hdr_t *)
|
||||
(datap + tx_msdu_info->htt.info.l3_hdr_offset);
|
||||
tx_msdu_info->htt.info.ethertype =
|
||||
(llc->ethertype[0] << 8) | llc->ethertype[1];
|
||||
/*
|
||||
* l3_hdr_offset refers to the end of the 802.3 or
|
||||
* 802.11 header, which may be a LLC/SNAP header rather
|
||||
* than the IP header.
|
||||
* Thus, don't increment l3_hdr_offset += sizeof(*llc);
|
||||
* rather,leave it as is.
|
||||
*/
|
||||
} else {
|
||||
/*
|
||||
* This function should only be applied to data frames.
|
||||
* For management frames, we already know to use
|
||||
* HTT_TX_EXT_TID_MGMT.
|
||||
*/
|
||||
TXRX_ASSERT2(0);
|
||||
}
|
||||
} else if (tx_msdu_info->htt.info.l2_hdr_type ==
|
||||
htt_pkt_type_ethernet) {
|
||||
ptr = (datap + ETHERNET_ADDR_LEN * 2);
|
||||
typeorlength = (ptr[0] << 8) | ptr[1];
|
||||
/*ETHERNET_HDR_LEN;*/
|
||||
l3_data_ptr = datap + sizeof(struct ethernet_hdr_t);
|
||||
|
||||
if (typeorlength == ETHERTYPE_VLAN) {
|
||||
ptr = (datap + ETHERNET_ADDR_LEN * 2
|
||||
+ ETHERTYPE_VLAN_LEN);
|
||||
typeorlength = (ptr[0] << 8) | ptr[1];
|
||||
l3_data_ptr += ETHERTYPE_VLAN_LEN;
|
||||
}
|
||||
|
||||
if (!IS_ETHERTYPE(typeorlength)) {
|
||||
/* 802.3 header*/
|
||||
struct llc_snap_hdr_t *llc_hdr =
|
||||
(struct llc_snap_hdr_t *)l3_data_ptr;
|
||||
typeorlength = (llc_hdr->ethertype[0] << 8) |
|
||||
llc_hdr->ethertype[1];
|
||||
l3_data_ptr += sizeof(struct llc_snap_hdr_t);
|
||||
}
|
||||
|
||||
tx_msdu_info->htt.info.l3_hdr_offset = (A_UINT8)(l3_data_ptr -
|
||||
datap);
|
||||
tx_msdu_info->htt.info.ethertype = typeorlength;
|
||||
}
|
||||
}
|
||||
|
||||
static inline A_UINT8
|
||||
ol_tx_tid_by_ether_type(
|
||||
A_UINT8 *datap,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
A_UINT8 tid;
|
||||
A_UINT8 *l3_data_ptr;
|
||||
A_UINT16 typeorlength;
|
||||
|
||||
l3_data_ptr = datap + tx_msdu_info->htt.info.l3_hdr_offset;
|
||||
typeorlength = tx_msdu_info->htt.info.ethertype;
|
||||
|
||||
/* IP packet, do packet inspection for TID */
|
||||
if (typeorlength == ETHERTYPE_IPV4) {
|
||||
tid = ol_tx_tid_by_ipv4(l3_data_ptr);
|
||||
} else if (typeorlength == ETHERTYPE_IPV6) {
|
||||
tid = ol_tx_tid_by_ipv6(l3_data_ptr);
|
||||
} else if (ETHERTYPE_IS_EAPOL_WAPI(typeorlength)) {
|
||||
/* EAPOL go with voice priority*/
|
||||
tid = TX_EAPOL_TID;
|
||||
} else if (typeorlength == ETHERTYPE_ARP) {
|
||||
tid = TX_ARP_TID;
|
||||
} else {
|
||||
/* For non-IP case, use default TID */
|
||||
tid = TX_DEFAULT_TID;
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
|
||||
static inline A_UINT8
|
||||
ol_tx_tid_by_raw_type(
|
||||
A_UINT8 *datap,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
A_UINT8 tid = HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
||||
|
||||
/* adjust hdr_ptr to RA */
|
||||
struct ieee80211_frame *wh = (struct ieee80211_frame *)datap;
|
||||
|
||||
/* FIXME: This code does not handle 4 address formats. The QOS field
|
||||
* is not at usual location.
|
||||
*/
|
||||
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
|
||||
IEEE80211_FC0_TYPE_DATA) {
|
||||
/* dot11 encapsulated frame */
|
||||
struct ieee80211_qosframe *whqos =
|
||||
(struct ieee80211_qosframe *)datap;
|
||||
if (whqos->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS)
|
||||
tid = whqos->i_qos[0] & IEEE80211_QOS_TID;
|
||||
else
|
||||
tid = HTT_NON_QOS_TID;
|
||||
} else {
|
||||
/*
|
||||
* This function should only be applied to data frames.
|
||||
* For management frames, we already know to use
|
||||
* HTT_TX_EXT_TID_MGMT.
|
||||
*/
|
||||
qdf_assert(0);
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
|
||||
static A_UINT8
|
||||
ol_tx_tid(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t tx_nbuf,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
A_UINT8 *datap = qdf_nbuf_data(tx_nbuf);
|
||||
A_UINT8 tid;
|
||||
|
||||
if (pdev->frame_format == wlan_frm_fmt_raw) {
|
||||
tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_raw;
|
||||
|
||||
ol_tx_set_ether_type(datap, tx_msdu_info);
|
||||
tid = tx_msdu_info->htt.info.ext_tid ==
|
||||
QDF_NBUF_TX_EXT_TID_INVALID ?
|
||||
ol_tx_tid_by_raw_type(datap, tx_msdu_info) :
|
||||
tx_msdu_info->htt.info.ext_tid;
|
||||
} else if (pdev->frame_format == wlan_frm_fmt_802_3) {
|
||||
tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_ethernet;
|
||||
|
||||
ol_tx_set_ether_type(datap, tx_msdu_info);
|
||||
tid =
|
||||
tx_msdu_info->htt.info.ext_tid ==
|
||||
QDF_NBUF_TX_EXT_TID_INVALID ?
|
||||
ol_tx_tid_by_ether_type(datap, tx_msdu_info) :
|
||||
tx_msdu_info->htt.info.ext_tid;
|
||||
} else if (pdev->frame_format == wlan_frm_fmt_native_wifi) {
|
||||
struct llc_snap_hdr_t *llc;
|
||||
|
||||
tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_native_wifi;
|
||||
tx_msdu_info->htt.info.l3_hdr_offset =
|
||||
sizeof(struct ieee80211_frame);
|
||||
llc = (struct llc_snap_hdr_t *)
|
||||
(datap + tx_msdu_info->htt.info.l3_hdr_offset);
|
||||
tx_msdu_info->htt.info.ethertype =
|
||||
(llc->ethertype[0] << 8) | llc->ethertype[1];
|
||||
/*
|
||||
* Native WiFi is a special case of "raw" 802.11 header format.
|
||||
* However, we expect that for all cases that use native WiFi,
|
||||
* the TID will be directly specified out of band.
|
||||
*/
|
||||
tid = tx_msdu_info->htt.info.ext_tid;
|
||||
} else {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL,
|
||||
"Invalid standard frame type: %d\n",
|
||||
pdev->frame_format);
|
||||
qdf_assert(0);
|
||||
tid = HTT_TX_EXT_TID_INVALID;
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS)
|
||||
static inline
|
||||
struct ol_txrx_peer_t *ol_tx_tdls_peer_find(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
uint8_t *peer_id)
|
||||
{
|
||||
struct ol_txrx_peer_t *peer = NULL;
|
||||
|
||||
if (vdev->hlTdlsFlag) {
|
||||
peer = ol_txrx_find_peer_by_addr(pdev,
|
||||
vdev->hl_tdls_ap_mac_addr.raw,
|
||||
peer_id);
|
||||
if (peer && (peer->peer_ids[0] == HTT_INVALID_PEER_ID)) {
|
||||
peer = NULL;
|
||||
} else {
|
||||
if (peer)
|
||||
qdf_atomic_inc(&peer->ref_cnt);
|
||||
}
|
||||
}
|
||||
if (!peer)
|
||||
peer = ol_txrx_assoc_peer_find(vdev);
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
#else
|
||||
struct ol_txrx_peer_t *ol_tx_tdls_peer_find(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
uint8_t *peer_id)
|
||||
{
|
||||
struct ol_txrx_peer_t *peer = NULL;
|
||||
peer = ol_txrx_assoc_peer_find(vdev);
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
struct ol_tx_frms_queue_t *
|
||||
ol_tx_classify(
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
qdf_nbuf_t tx_nbuf,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
struct ol_txrx_pdev_t *pdev = vdev->pdev;
|
||||
struct ol_txrx_peer_t *peer = NULL;
|
||||
struct ol_tx_frms_queue_t *txq = NULL;
|
||||
A_UINT8 *dest_addr;
|
||||
A_UINT8 tid;
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS)
|
||||
u_int8_t peer_id;
|
||||
#endif
|
||||
|
||||
TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__);
|
||||
dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf);
|
||||
if ((IEEE80211_IS_MULTICAST(dest_addr)) ||
|
||||
(vdev->opmode == wlan_op_mode_ocb)) {
|
||||
txq = &vdev->txqs[OL_TX_VDEV_MCAST_BCAST];
|
||||
tx_msdu_info->htt.info.ext_tid =
|
||||
HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
||||
if (vdev->opmode == wlan_op_mode_sta) {
|
||||
/*
|
||||
* The STA sends a frame with a broadcast
|
||||
* dest addr (DA) as a
|
||||
* unicast frame to the AP's receive addr (RA).
|
||||
* Find the peer object that represents the AP
|
||||
* that the STA is associated with.
|
||||
*/
|
||||
peer = ol_txrx_assoc_peer_find(vdev);
|
||||
if (!peer) {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
"Error: STA %p (%02x:%02x:%02x:%02x:%02x:%02x) trying to send bcast DA tx data frame w/o association\n",
|
||||
vdev,
|
||||
vdev->mac_addr.raw[0],
|
||||
vdev->mac_addr.raw[1],
|
||||
vdev->mac_addr.raw[2],
|
||||
vdev->mac_addr.raw[3],
|
||||
vdev->mac_addr.raw[4],
|
||||
vdev->mac_addr.raw[5]);
|
||||
return NULL; /* error */
|
||||
} else if ((peer->security[
|
||||
OL_TXRX_PEER_SECURITY_MULTICAST].sec_type
|
||||
!= htt_sec_type_wapi) &&
|
||||
(qdf_nbuf_is_ipv4_pkt(tx_nbuf) == true)) {
|
||||
if (true == qdf_nbuf_is_ipv4_dhcp_pkt(
|
||||
tx_nbuf)) {
|
||||
/* DHCP frame to go with
|
||||
* voice priority
|
||||
*/
|
||||
txq = &peer->txqs[TX_DHCP_TID];
|
||||
tx_msdu_info->htt.info.ext_tid =
|
||||
TX_DHCP_TID;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The following line assumes each peer object has a
|
||||
* single ID. This is currently true, and is expected
|
||||
* to remain true.
|
||||
*/
|
||||
tx_msdu_info->htt.info.peer_id = peer->peer_ids[0];
|
||||
} else if (vdev->opmode == wlan_op_mode_ocb) {
|
||||
tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID;
|
||||
/* In OCB mode, don't worry about the peer.
|
||||
*We don't need it. */
|
||||
peer = NULL;
|
||||
} else {
|
||||
tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID;
|
||||
/*
|
||||
* Look up the vdev's BSS peer, so that the
|
||||
* classify_extension function can check whether to
|
||||
* encrypt multicast / broadcast frames.
|
||||
*/
|
||||
peer = ol_txrx_peer_find_hash_find(pdev,
|
||||
vdev->mac_addr.raw,
|
||||
0, 1);
|
||||
if (!peer) {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
"Error: vdev %p (%02x:%02x:%02x:%02x:%02x:%02x) trying to send bcast/mcast, but no self-peer found\n",
|
||||
vdev,
|
||||
vdev->mac_addr.raw[0],
|
||||
vdev->mac_addr.raw[1],
|
||||
vdev->mac_addr.raw[2],
|
||||
vdev->mac_addr.raw[3],
|
||||
vdev->mac_addr.raw[4],
|
||||
vdev->mac_addr.raw[5]);
|
||||
return NULL; /* error */
|
||||
}
|
||||
}
|
||||
tx_msdu_info->htt.info.is_unicast = false;
|
||||
} else {
|
||||
/* tid would be overwritten for non QoS case*/
|
||||
tid = ol_tx_tid(pdev, tx_nbuf, tx_msdu_info);
|
||||
if ((HTT_TX_EXT_TID_INVALID == tid) ||
|
||||
(tid >= OL_TX_NUM_TIDS)) {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
"%s Error: could not classify packet into valid TID(%d).\n",
|
||||
__func__, tid);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef ATH_SUPPORT_WAPI
|
||||
/* Check to see if a frame is a WAI frame */
|
||||
if (tx_msdu_info->htt.info.ethertype == ETHERTYPE_WAI) {
|
||||
/* WAI frames should not be encrypted */
|
||||
tx_msdu_info->htt.action.do_encrypt = 0;
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
|
||||
"Tx Frame is a WAI frame\n");
|
||||
}
|
||||
#endif /* ATH_SUPPORT_WAPI */
|
||||
|
||||
/*
|
||||
* Find the peer and increment its reference count.
|
||||
* If this vdev is an AP, use the dest addr (DA) to determine
|
||||
* which peer STA this unicast data frame is for.
|
||||
* If this vdev is a STA, the unicast data frame is for the
|
||||
* AP the STA is associated with.
|
||||
*/
|
||||
if (vdev->opmode == wlan_op_mode_sta) {
|
||||
/*
|
||||
* TO DO:
|
||||
* To support TDLS, first check if there is a TDLS
|
||||
* peer STA,
|
||||
* and if so, check if the DA matches the TDLS peer
|
||||
* STA's MAC address. If there is no peer TDLS STA,
|
||||
* or if the DA is not the TDLS STA's address,
|
||||
* then the frame is either for the AP itself, or is
|
||||
* supposed to be sent to the AP for forwarding.
|
||||
*/
|
||||
#if 0
|
||||
if (vdev->num_tdls_peers > 0) {
|
||||
peer = NULL;
|
||||
for (i = 0; i < vdev->num_tdls_peers; i++) {
|
||||
int differs = adf_os_mem_cmp(
|
||||
vdev->tdls_peers[i]->
|
||||
mac_addr.raw,
|
||||
dest_addr,
|
||||
OL_TXRX_MAC_ADDR_LEN);
|
||||
if (!differs) {
|
||||
peer = vdev->tdls_peers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* send to AP */
|
||||
peer = ol_txrx_assoc_peer_find(vdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
peer = ol_tx_tdls_peer_find(pdev, vdev, &peer_id);
|
||||
} else {
|
||||
peer = ol_txrx_peer_find_hash_find(pdev, dest_addr,
|
||||
0, 1);
|
||||
}
|
||||
tx_msdu_info->htt.info.is_unicast = true;
|
||||
if (!peer) {
|
||||
/*
|
||||
* Unicast data xfer can only happen to an
|
||||
* associated peer. It is illegitimate to send unicast
|
||||
* data if there is no peer to send it to.
|
||||
*/
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
"Error: vdev %p (%02x:%02x:%02x:%02x:%02x:%02x) trying to send unicast tx data frame to an unknown peer\n",
|
||||
vdev,
|
||||
vdev->mac_addr.raw[0], vdev->mac_addr.raw[1],
|
||||
vdev->mac_addr.raw[2], vdev->mac_addr.raw[3],
|
||||
vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]);
|
||||
return NULL; /* error */
|
||||
}
|
||||
TX_SCHED_DEBUG_PRINT("Peer found\n");
|
||||
if (!peer->qos_capable) {
|
||||
tid = OL_TX_NON_QOS_TID;
|
||||
} else if ((peer->security[
|
||||
OL_TXRX_PEER_SECURITY_UNICAST].sec_type
|
||||
!= htt_sec_type_wapi) &&
|
||||
(qdf_nbuf_is_ipv4_pkt(tx_nbuf) == true)) {
|
||||
if (true == qdf_nbuf_is_ipv4_dhcp_pkt(tx_nbuf))
|
||||
/* DHCP frame to go with voice priority */
|
||||
tid = TX_DHCP_TID;
|
||||
}
|
||||
|
||||
/* Only allow encryption when in authenticated state */
|
||||
if (OL_TXRX_PEER_STATE_AUTH != peer->state)
|
||||
tx_msdu_info->htt.action.do_encrypt = 0;
|
||||
|
||||
txq = &peer->txqs[tid];
|
||||
tx_msdu_info->htt.info.ext_tid = tid;
|
||||
/*
|
||||
* The following line assumes each peer object has a single ID.
|
||||
* This is currently true, and is expected to remain true.
|
||||
*/
|
||||
tx_msdu_info->htt.info.peer_id = peer->peer_ids[0];
|
||||
/*
|
||||
* WORKAROUND - check that the peer ID is valid.
|
||||
* If tx data is provided before ol_rx_peer_map_handler is
|
||||
* called to record the peer ID specified by the target,
|
||||
* then we could end up here with an invalid peer ID.
|
||||
* TO DO: rather than dropping the tx frame, pause the txq it
|
||||
* goes into, then fill in the peer ID for the entries in the
|
||||
* txq when the peer_map event provides the peer ID, and then
|
||||
* unpause the txq.
|
||||
*/
|
||||
if (tx_msdu_info->htt.info.peer_id == HTT_INVALID_PEER_ID) {
|
||||
if (peer) {
|
||||
TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
|
||||
"%s: remove the peer for invalid peer_id %p\n",
|
||||
__func__, peer);
|
||||
/* remove the peer reference added above */
|
||||
ol_txrx_peer_unref_delete(peer);
|
||||
tx_msdu_info->peer = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
tx_msdu_info->peer = peer;
|
||||
if (ol_if_tx_bad_peer_txq_overflow(pdev, peer, txq))
|
||||
return NULL;
|
||||
/*
|
||||
* If relevant, do a deeper inspection to determine additional
|
||||
* characteristics of the tx frame.
|
||||
* If the frame is invalid, then the txq will be set to NULL to
|
||||
* indicate an error.
|
||||
*/
|
||||
OL_TX_CLASSIFY_EXTENSION(vdev, tx_desc, tx_nbuf, tx_msdu_info, txq);
|
||||
if (IEEE80211_IS_MULTICAST(dest_addr) && vdev->opmode !=
|
||||
wlan_op_mode_sta && tx_msdu_info->peer !=
|
||||
NULL) {
|
||||
TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
|
||||
"%s: remove the peer reference %p\n",
|
||||
__func__, peer);
|
||||
/* remove the peer reference added above */
|
||||
ol_txrx_peer_unref_delete(tx_msdu_info->peer);
|
||||
/* Making peer NULL in case if multicast non STA mode */
|
||||
tx_msdu_info->peer = NULL;
|
||||
}
|
||||
|
||||
/* Whether this frame can download though HTT2 data pipe or not. */
|
||||
OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, tx_nbuf, tx_msdu_info);
|
||||
|
||||
/* Update Tx Queue info */
|
||||
tx_desc->txq = txq;
|
||||
|
||||
TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__);
|
||||
return txq;
|
||||
}
|
||||
|
||||
struct ol_tx_frms_queue_t *
|
||||
ol_tx_classify_mgmt(
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
qdf_nbuf_t tx_nbuf,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
struct ol_txrx_pdev_t *pdev = vdev->pdev;
|
||||
struct ol_txrx_peer_t *peer = NULL;
|
||||
struct ol_tx_frms_queue_t *txq = NULL;
|
||||
A_UINT8 *dest_addr;
|
||||
union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr;
|
||||
|
||||
TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__);
|
||||
dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf);
|
||||
if (IEEE80211_IS_MULTICAST(dest_addr)) {
|
||||
/*
|
||||
* AP: beacons are broadcast,
|
||||
* public action frames (e.g. extended channel
|
||||
* switch announce) may be broadcast
|
||||
* STA: probe requests can be either broadcast or unicast
|
||||
*/
|
||||
txq = &vdev->txqs[OL_TX_VDEV_DEFAULT_MGMT];
|
||||
tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID;
|
||||
tx_msdu_info->peer = NULL;
|
||||
tx_msdu_info->htt.info.is_unicast = 0;
|
||||
} else {
|
||||
/*
|
||||
* Find the peer and increment its reference count.
|
||||
* If this vdev is an AP, use the receiver addr (RA) to
|
||||
* determine which peer STA this unicast mgmt frame is for.
|
||||
* If this vdev is a STA, the unicast mgmt frame is for the
|
||||
* AP the STA is associated with.
|
||||
* Probe request / response and Assoc request / response are
|
||||
* sent before the peer exists - in this case, use the
|
||||
* vdev's default tx queue.
|
||||
*/
|
||||
if (vdev->opmode == wlan_op_mode_sta) {
|
||||
/*
|
||||
* TO DO:
|
||||
* To support TDLS, first check if there is a TDLS
|
||||
* peer STA, and if so, check if the DA matches
|
||||
* the TDLS peer STA's MAC address.
|
||||
*/
|
||||
peer = ol_txrx_assoc_peer_find(vdev);
|
||||
/*
|
||||
* Some special case(preauth for example) needs to send
|
||||
* unicast mgmt frame to unassociated AP. In such case,
|
||||
* we need to check if dest addr match the associated
|
||||
* peer addr. If not, we set peer as NULL to queue this
|
||||
* frame to vdev queue.
|
||||
*/
|
||||
if (peer) {
|
||||
qdf_mem_copy(
|
||||
&local_mac_addr_aligned.raw[0],
|
||||
dest_addr, OL_TXRX_MAC_ADDR_LEN);
|
||||
mac_addr = &local_mac_addr_aligned;
|
||||
if (ol_txrx_peer_find_mac_addr_cmp(
|
||||
mac_addr,
|
||||
&peer->mac_addr) != 0) {
|
||||
qdf_atomic_dec(&peer->ref_cnt);
|
||||
peer = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* find the peer and increment its reference count */
|
||||
peer = ol_txrx_peer_find_hash_find(pdev, dest_addr,
|
||||
0, 1);
|
||||
}
|
||||
tx_msdu_info->peer = peer;
|
||||
if (!peer) {
|
||||
txq = &vdev->txqs[OL_TX_VDEV_DEFAULT_MGMT];
|
||||
tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID;
|
||||
} else {
|
||||
txq = &peer->txqs[HTT_TX_EXT_TID_MGMT];
|
||||
tx_msdu_info->htt.info.ext_tid = HTT_TX_EXT_TID_MGMT;
|
||||
/*
|
||||
* The following line assumes each peer object has a
|
||||
* single ID. This is currently true, and is expected
|
||||
* to remain true.
|
||||
*/
|
||||
tx_msdu_info->htt.info.peer_id = peer->peer_ids[0];
|
||||
}
|
||||
tx_msdu_info->htt.info.is_unicast = 1;
|
||||
}
|
||||
/*
|
||||
* If relevant, do a deeper inspection to determine additional
|
||||
* characteristics of the tx frame.
|
||||
* If the frame is invalid, then the txq will be set to NULL to
|
||||
* indicate an error.
|
||||
*/
|
||||
OL_TX_CLASSIFY_MGMT_EXTENSION(vdev, tx_desc, tx_nbuf,
|
||||
tx_msdu_info, txq);
|
||||
|
||||
/* Whether this frame can download though HTT2 data pipe or not. */
|
||||
OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, tx_nbuf, tx_msdu_info);
|
||||
|
||||
/* Update Tx Queue info */
|
||||
tx_desc->txq = txq;
|
||||
|
||||
TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__);
|
||||
return txq;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
ol_tx_classify_extension(
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
qdf_nbuf_t tx_msdu,
|
||||
struct ol_txrx_msdu_info_t *msdu_info)
|
||||
{
|
||||
A_UINT8 *datap = qdf_nbuf_data(tx_msdu);
|
||||
struct ol_txrx_peer_t *peer;
|
||||
int which_key;
|
||||
|
||||
/*
|
||||
* The following msdu_info fields were already filled in by the
|
||||
* ol_tx entry function or the regular ol_tx_classify function:
|
||||
* htt.info.vdev_id (ol_tx_hl or ol_tx_non_std_hl)
|
||||
* htt.info.ext_tid (ol_tx_non_std_hl or ol_tx_classify)
|
||||
* htt.info.frame_type (ol_tx_hl or ol_tx_non_std_hl)
|
||||
* htt.info.l2_hdr_type (ol_tx_hl or ol_tx_non_std_hl)
|
||||
* htt.info.is_unicast (ol_tx_classify)
|
||||
* htt.info.peer_id (ol_tx_classify)
|
||||
* peer (ol_tx_classify)
|
||||
* if (is_unicast) {
|
||||
* htt.info.ethertype (ol_tx_classify)
|
||||
* htt.info.l3_hdr_offset (ol_tx_classify)
|
||||
* }
|
||||
* The following fields need to be filled in by this function:
|
||||
* if (!is_unicast) {
|
||||
* htt.info.ethertype
|
||||
* htt.info.l3_hdr_offset
|
||||
* }
|
||||
* htt.action.band (NOT CURRENTLY USED)
|
||||
* htt.action.do_encrypt
|
||||
* htt.action.do_tx_complete
|
||||
* The following fields are not needed for data frames, and can
|
||||
* be left uninitialized:
|
||||
* htt.info.frame_subtype
|
||||
*/
|
||||
|
||||
if (!msdu_info->htt.info.is_unicast) {
|
||||
int l2_hdr_size;
|
||||
A_UINT16 ethertype;
|
||||
|
||||
if (msdu_info->htt.info.l2_hdr_type == htt_pkt_type_ethernet) {
|
||||
struct ethernet_hdr_t *eh;
|
||||
|
||||
eh = (struct ethernet_hdr_t *)datap;
|
||||
l2_hdr_size = sizeof(*eh);
|
||||
ethertype = (eh->ethertype[0] << 8) | eh->ethertype[1];
|
||||
|
||||
if (ethertype == ETHERTYPE_VLAN) {
|
||||
struct ethernet_vlan_hdr_t *evh;
|
||||
|
||||
evh = (struct ethernet_vlan_hdr_t *)datap;
|
||||
l2_hdr_size = sizeof(*evh);
|
||||
ethertype = (evh->ethertype[0] << 8) |
|
||||
evh->ethertype[1];
|
||||
}
|
||||
|
||||
if (!IS_ETHERTYPE(ethertype)) {
|
||||
/* 802.3 header*/
|
||||
struct llc_snap_hdr_t *llc =
|
||||
(struct llc_snap_hdr_t *)(datap +
|
||||
l2_hdr_size);
|
||||
ethertype = (llc->ethertype[0] << 8) |
|
||||
llc->ethertype[1];
|
||||
l2_hdr_size += sizeof(*llc);
|
||||
}
|
||||
msdu_info->htt.info.l3_hdr_offset = l2_hdr_size;
|
||||
msdu_info->htt.info.ethertype = ethertype;
|
||||
} else { /* 802.11 */
|
||||
struct llc_snap_hdr_t *llc;
|
||||
l2_hdr_size = ol_txrx_ieee80211_hdrsize(datap);
|
||||
llc = (struct llc_snap_hdr_t *)(datap + l2_hdr_size);
|
||||
ethertype = (llc->ethertype[0] << 8) |
|
||||
llc->ethertype[1];
|
||||
/*
|
||||
* Don't include the LLC/SNAP header in l2_hdr_size,
|
||||
* because l3_hdr_offset is actually supposed to refer
|
||||
* to the header after the 802.3 or 802.11 header,
|
||||
* which could be a LLC/SNAP header rather
|
||||
* than the L3 header.
|
||||
*/
|
||||
}
|
||||
msdu_info->htt.info.l3_hdr_offset = l2_hdr_size;
|
||||
msdu_info->htt.info.ethertype = ethertype;
|
||||
which_key = txrx_sec_mcast;
|
||||
} else {
|
||||
which_key = txrx_sec_ucast;
|
||||
}
|
||||
peer = msdu_info->peer;
|
||||
/*
|
||||
* msdu_info->htt.action.do_encrypt is initially set in ol_tx_desc_hl.
|
||||
* Add more check here.
|
||||
*/
|
||||
msdu_info->htt.action.do_encrypt = (!peer) ? 0 :
|
||||
(peer->security[which_key].sec_type == htt_sec_type_none) ? 0 :
|
||||
msdu_info->htt.action.do_encrypt;
|
||||
/*
|
||||
* For systems that have a frame by frame spec for whether to receive
|
||||
* a tx completion notification, use the tx completion notification
|
||||
* only for certain management frames, not for data frames.
|
||||
* (In the future, this may be changed slightly, e.g. to request a
|
||||
* tx completion notification for the final EAPOL message sent by a
|
||||
* STA during the key delivery handshake.)
|
||||
*/
|
||||
msdu_info->htt.action.do_tx_complete = 0;
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
A_STATUS
|
||||
ol_tx_classify_mgmt_extension(
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
qdf_nbuf_t tx_msdu,
|
||||
struct ol_txrx_msdu_info_t *msdu_info)
|
||||
{
|
||||
struct ieee80211_frame *wh;
|
||||
|
||||
/*
|
||||
* The following msdu_info fields were already filled in by the
|
||||
* ol_tx entry function or the regular ol_tx_classify_mgmt function:
|
||||
* htt.info.vdev_id (ol_txrx_mgmt_send)
|
||||
* htt.info.frame_type (ol_txrx_mgmt_send)
|
||||
* htt.info.l2_hdr_type (ol_txrx_mgmt_send)
|
||||
* htt.action.do_tx_complete (ol_txrx_mgmt_send)
|
||||
* htt.info.peer_id (ol_tx_classify_mgmt)
|
||||
* htt.info.ext_tid (ol_tx_classify_mgmt)
|
||||
* htt.info.is_unicast (ol_tx_classify_mgmt)
|
||||
* peer (ol_tx_classify_mgmt)
|
||||
* The following fields need to be filled in by this function:
|
||||
* htt.info.frame_subtype
|
||||
* htt.info.l3_hdr_offset
|
||||
* htt.action.band (NOT CURRENTLY USED)
|
||||
* The following fields are not needed for mgmt frames, and can
|
||||
* be left uninitialized:
|
||||
* htt.info.ethertype
|
||||
* htt.action.do_encrypt
|
||||
* (This will be filled in by other SW, which knows whether
|
||||
* the peer has robust-managment-frames enabled.)
|
||||
*/
|
||||
wh = (struct ieee80211_frame *)qdf_nbuf_data(tx_msdu);
|
||||
msdu_info->htt.info.frame_subtype =
|
||||
(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >>
|
||||
IEEE80211_FC0_SUBTYPE_SHIFT;
|
||||
msdu_info->htt.info.l3_hdr_offset = sizeof(struct ieee80211_frame);
|
||||
|
||||
return A_OK;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_HL_SUPPORT) */
|
103
core/dp/txrx/ol_tx_classify.h
Normal file
103
core/dp/txrx/ol_tx_classify.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2014, 2016 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
|
||||
*
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file was originally distributed by Qualcomm Atheros, Inc.
|
||||
* under proprietary terms before Copyright ownership was assigned
|
||||
* to the Linux Foundation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ol_tx_classify.h
|
||||
* @brief API definitions for the tx classify module within the data SW.
|
||||
*/
|
||||
#ifndef _OL_TX_CLASSIFY__H_
|
||||
#define _OL_TX_CLASSIFY__H_
|
||||
|
||||
#include <qdf_nbuf.h> /* qdf_nbuf_t */
|
||||
#include <ol_txrx_types.h> /* ol_txrx_vdev_t, etc. */
|
||||
|
||||
static inline u_int8_t *
|
||||
ol_tx_dest_addr_find(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t tx_nbuf)
|
||||
{
|
||||
u_int8_t *hdr_ptr;
|
||||
void *datap = qdf_nbuf_data(tx_nbuf);
|
||||
|
||||
if (pdev->frame_format == wlan_frm_fmt_raw) {
|
||||
/* adjust hdr_ptr to RA */
|
||||
struct ieee80211_frame *wh =
|
||||
(struct ieee80211_frame *)datap;
|
||||
hdr_ptr = wh->i_addr1;
|
||||
} else if (pdev->frame_format ==
|
||||
wlan_frm_fmt_native_wifi) {
|
||||
/* adjust hdr_ptr to RA */
|
||||
struct ieee80211_frame *wh = (
|
||||
struct ieee80211_frame *)datap;
|
||||
hdr_ptr = wh->i_addr1;
|
||||
} else if (pdev->frame_format == wlan_frm_fmt_802_3) {
|
||||
hdr_ptr = datap;
|
||||
} else {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
"Invalid standard frame type: %d\n",
|
||||
pdev->frame_format);
|
||||
qdf_assert(0);
|
||||
hdr_ptr = NULL;
|
||||
}
|
||||
return hdr_ptr;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
/**
|
||||
* @brief Classify a tx frame to which tid queue.
|
||||
*
|
||||
* @param vdev - the virtual device sending the data
|
||||
* (for specifying the transmitter address for multicast / broadcast data)
|
||||
* @param tx_desc - descriptor object with meta-data about the tx frame
|
||||
* @param netbuf - the tx frame
|
||||
* @param tx_msdu_info - characteristics of the tx frame
|
||||
*/
|
||||
struct ol_tx_frms_queue_t *
|
||||
ol_tx_classify(
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
qdf_nbuf_t netbuf,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info);
|
||||
|
||||
struct ol_tx_frms_queue_t *
|
||||
ol_tx_classify_mgmt(
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
qdf_nbuf_t netbuf,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info);
|
||||
|
||||
#else
|
||||
|
||||
#define ol_tx_classify(vdev, tx_desc, netbuf, tx_msdu_info) NULL
|
||||
#define ol_tx_classify_mgmt(vdev, tx_desc, netbuf, tx_msdu_info) NULL
|
||||
|
||||
#endif /* defined(CONFIG_HL_SUPPORT) */
|
||||
|
||||
|
||||
#endif /* _OL_TX_CLASSIFY__H_ */
|
@@ -105,7 +105,56 @@ static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HL_SUPPORT
|
||||
|
||||
/**
|
||||
* ol_tx_desc_vdev_update() - vedv assign.
|
||||
* @tx_desc: tx descriptor pointer
|
||||
* @vdev: vdev handle
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static inline void
|
||||
ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc,
|
||||
struct ol_txrx_vdev_t *vdev)
|
||||
{
|
||||
tx_desc->vdev = vdev;
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc,
|
||||
struct ol_txrx_vdev_t *vdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PER_VDEV_TX_DESC_POOL
|
||||
|
||||
/**
|
||||
* ol_tx_desc_count_inc() - tx desc count increment for desc allocation.
|
||||
* @vdev: vdev handle
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static inline void
|
||||
ol_tx_desc_count_inc(struct ol_txrx_vdev_t *vdev)
|
||||
{
|
||||
qdf_atomic_inc(&vdev->tx_desc_count);
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_tx_desc_count_inc(struct ol_txrx_vdev_t *vdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef QCA_LL_TX_FLOW_CONTROL_V2
|
||||
|
||||
/**
|
||||
* ol_tx_desc_alloc() - allocate descriptor from freelist
|
||||
* @pdev: pdev handle
|
||||
@@ -127,6 +176,13 @@ struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev,
|
||||
ol_tx_desc_compute_delay(tx_desc);
|
||||
}
|
||||
qdf_spin_unlock_bh(&pdev->tx_mutex);
|
||||
|
||||
if (!tx_desc)
|
||||
return NULL;
|
||||
|
||||
ol_tx_desc_vdev_update(tx_desc, vdev);
|
||||
ol_tx_desc_count_inc(vdev);
|
||||
|
||||
return tx_desc;
|
||||
}
|
||||
|
||||
@@ -220,6 +276,53 @@ ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ol_tx_desc_alloc_hl() - allocate tx descriptor
|
||||
* @pdev: pdev handle
|
||||
* @vdev: vdev handle
|
||||
* @msdu_info: tx msdu info
|
||||
*
|
||||
* Return: tx descriptor pointer/ NULL in case of error
|
||||
*/
|
||||
static struct ol_tx_desc_t *
|
||||
ol_tx_desc_alloc_hl(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
struct ol_txrx_msdu_info_t *msdu_info)
|
||||
{
|
||||
struct ol_tx_desc_t *tx_desc;
|
||||
|
||||
tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info);
|
||||
if (!tx_desc)
|
||||
return NULL;
|
||||
|
||||
qdf_atomic_dec(&pdev->tx_queue.rsrc_cnt);
|
||||
|
||||
return tx_desc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) && defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
/**
|
||||
* ol_tx_desc_vdev_rm() - decrement the tx desc count for vdev.
|
||||
* @tx_desc: tx desc
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static inline void
|
||||
ol_tx_desc_vdev_rm(struct ol_tx_desc_t *tx_desc)
|
||||
{
|
||||
qdf_atomic_dec(&tx_desc->vdev->tx_desc_count);
|
||||
tx_desc->vdev = NULL;
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_tx_desc_vdev_rm(struct ol_tx_desc_t *tx_desc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef QCA_LL_TX_FLOW_CONTROL_V2
|
||||
/**
|
||||
* ol_tx_desc_free() - put descriptor to freelist
|
||||
@@ -246,6 +349,8 @@ void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc)
|
||||
ol_tx_desc_reset_timestamp(tx_desc);
|
||||
|
||||
ol_tx_put_desc_global_pool(pdev, tx_desc);
|
||||
ol_tx_desc_vdev_rm(tx_desc);
|
||||
|
||||
qdf_spin_unlock_bh(&pdev->tx_mutex);
|
||||
}
|
||||
|
||||
@@ -313,7 +418,7 @@ void
|
||||
dump_pkt(qdf_nbuf_t nbuf, qdf_dma_addr_t nbuf_paddr, int len)
|
||||
{
|
||||
qdf_print("%s: Pkt: VA 0x%p PA 0x%llx len %d\n", __func__,
|
||||
qdf_nbuf_data(nbuf), nbuf_paddr, len);
|
||||
qdf_nbuf_data(nbuf), (long long unsigned int)nbuf_paddr, len);
|
||||
print_hex_dump(KERN_DEBUG, "Pkt: ", DUMP_PREFIX_ADDRESS, 16, 4,
|
||||
qdf_nbuf_data(nbuf), len, true);
|
||||
}
|
||||
@@ -491,6 +596,52 @@ struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev,
|
||||
return tx_desc;
|
||||
}
|
||||
|
||||
struct ol_tx_desc_t *
|
||||
ol_tx_desc_hl(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
qdf_nbuf_t netbuf,
|
||||
struct ol_txrx_msdu_info_t *msdu_info)
|
||||
{
|
||||
struct ol_tx_desc_t *tx_desc;
|
||||
|
||||
/* FIX THIS: these inits should probably be done by tx classify */
|
||||
msdu_info->htt.info.vdev_id = vdev->vdev_id;
|
||||
msdu_info->htt.info.frame_type = pdev->htt_pkt_type;
|
||||
msdu_info->htt.action.cksum_offload = qdf_nbuf_get_tx_cksum(netbuf);
|
||||
switch (qdf_nbuf_get_exemption_type(netbuf)) {
|
||||
case QDF_NBUF_EXEMPT_NO_EXEMPTION:
|
||||
case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE:
|
||||
/* We want to encrypt this frame */
|
||||
msdu_info->htt.action.do_encrypt = 1;
|
||||
break;
|
||||
case QDF_NBUF_EXEMPT_ALWAYS:
|
||||
/* We don't want to encrypt this frame */
|
||||
msdu_info->htt.action.do_encrypt = 0;
|
||||
break;
|
||||
default:
|
||||
qdf_assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* allocate the descriptor */
|
||||
tx_desc = ol_tx_desc_alloc_hl(pdev, vdev, msdu_info);
|
||||
if (!tx_desc)
|
||||
return NULL;
|
||||
|
||||
/* initialize the SW tx descriptor */
|
||||
tx_desc->netbuf = netbuf;
|
||||
/* fix this - get pkt_type from msdu_info */
|
||||
tx_desc->pkt_type = OL_TX_FRM_STD;
|
||||
|
||||
#ifdef QCA_SUPPORT_SW_TXRX_ENCAP
|
||||
tx_desc->orig_l2_hdr_bytes = 0;
|
||||
#endif
|
||||
/* the HW tx descriptor will be initialized later by the caller */
|
||||
|
||||
return tx_desc;
|
||||
}
|
||||
|
||||
void ol_tx_desc_frame_list_free(struct ol_txrx_pdev_t *pdev,
|
||||
ol_tx_desc_list *tx_descs, int had_error)
|
||||
{
|
||||
|
@@ -72,6 +72,31 @@ struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t netbuf,
|
||||
struct ol_txrx_msdu_info_t *msdu_info);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize a tx descriptor for a HL system.
|
||||
* @details
|
||||
* Allocate a tx descriptor pair for a new tx frame - a SW tx descriptor
|
||||
* for private use within the host data SW, and a HTT tx descriptor for
|
||||
* downloading tx meta-data to the target FW/HW.
|
||||
* Fill in the fields of this pair of tx descriptors based on the
|
||||
* information in the netbuf.
|
||||
*
|
||||
* @param pdev - the data physical device sending the data
|
||||
* (for accessing the tx desc pool)
|
||||
* @param vdev - the virtual device sending the data
|
||||
* (for specifying the transmitter address for multicast / broadcast data)
|
||||
* @param netbuf - the tx frame
|
||||
* @param msdu_info - tx meta-data
|
||||
*/
|
||||
struct ol_tx_desc_t *
|
||||
ol_tx_desc_hl(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_vdev_t *vdev,
|
||||
qdf_nbuf_t netbuf,
|
||||
struct ol_txrx_msdu_info_t *msdu_info);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Use a tx descriptor ID to find the corresponding desriptor object.
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -37,46 +37,405 @@
|
||||
#include <qdf_types.h> /* bool */
|
||||
|
||||
/*--- function prototypes for optional queue log feature --------------------*/
|
||||
#if defined(ENABLE_TX_QUEUE_LOG)
|
||||
#if defined(ENABLE_TX_QUEUE_LOG) || \
|
||||
(defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT))
|
||||
|
||||
/**
|
||||
* ol_tx_queue_log_enqueue() - enqueue tx queue logs
|
||||
* @pdev: physical device object
|
||||
* @msdu_info: tx msdu meta data
|
||||
* @frms: number of frames for which logs need to be enqueued
|
||||
* @bytes: number of bytes
|
||||
*
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_tx_queue_log_enqueue(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_msdu_info_t *msdu_info,
|
||||
int frms, int bytes);
|
||||
|
||||
/**
|
||||
* ol_tx_queue_log_dequeue() - dequeue tx queue logs
|
||||
* @pdev: physical device object
|
||||
* @txq: tx queue
|
||||
* @frms: number of frames for which logs need to be dequeued
|
||||
* @bytes: number of bytes
|
||||
*
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_tx_queue_log_dequeue(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq, int frms, int bytes);
|
||||
|
||||
/**
|
||||
* ol_tx_queue_log_free() - free tx queue logs
|
||||
* @pdev: physical device object
|
||||
* @txq: tx queue
|
||||
* @tid: tid value
|
||||
* @frms: number of frames for which logs need to be freed
|
||||
* @bytes: number of bytes
|
||||
*
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_tx_queue_log_free(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
int tid, int frms, int bytes);
|
||||
#define OL_TX_QUEUE_LOG_ENQUEUE ol_tx_queue_log_enqueue
|
||||
#define OL_TX_QUEUE_LOG_DEQUEUE ol_tx_queue_log_dequeue
|
||||
#define OL_TX_QUEUE_LOG_FREE ol_tx_queue_log_free
|
||||
|
||||
#else
|
||||
|
||||
#define OL_TX_QUEUE_LOG_ENQUEUE(pdev, msdu_info, frms, bytes) /* no-op */
|
||||
#define OL_TX_QUEUE_LOG_DEQUEUE(pdev, txq, frms, bytes) /* no-op */
|
||||
#define OL_TX_QUEUE_LOG_FREE(pdev, txq, tid, frms, bytes) /* no-op */
|
||||
static inline void
|
||||
ol_tx_queue_log_enqueue(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_txrx_msdu_info_t *msdu_info,
|
||||
int frms, int bytes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* TXRX_DEBUG_LEVEL > 5 */
|
||||
static inline void
|
||||
ol_tx_queue_log_dequeue(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq, int frms, int bytes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#define ol_tx_enqueue(pdev, txq, tx_desc, tx_msdu_info) /* no-op */
|
||||
#define ol_tx_dequeue(pdev, ext_tid, txq, head, num_frames, credit, bytes) 0
|
||||
#define ol_tx_queue_free(pdev, txq, tid) /* no-op */
|
||||
#define ol_tx_queue_discard(pdev, flush, tx_descs) /* no-op */
|
||||
static inline void
|
||||
ol_tx_queue_log_free(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
int tid, int frms, int bytes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
/**
|
||||
* @brief Queue a tx frame to the tid queue.
|
||||
*
|
||||
* @param pdev - the data virtual device sending the data
|
||||
* (for storing the tx desc in the virtual dev's tx_target_list,
|
||||
* and for accessing the phy dev)
|
||||
* @param txq - which queue the tx frame gets stored in
|
||||
* @param tx_desc - tx meta-data, including prev and next ptrs
|
||||
* @param tx_msdu_info - characteristics of the tx frame
|
||||
*/
|
||||
void
|
||||
ol_tx_enqueue(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info);
|
||||
|
||||
/**
|
||||
* @brief - remove the specified number of frames from the head of a tx queue
|
||||
* @details
|
||||
* This function removes frames from the head of a tx queue,
|
||||
* and returns them as a NULL-terminated linked list.
|
||||
* The function will remove frames until one of the following happens:
|
||||
* 1. The tx queue is empty
|
||||
* 2. The specified number of frames have been removed
|
||||
* 3. Removal of more frames would exceed the specified credit limit
|
||||
*
|
||||
* @param pdev - the physical device object
|
||||
* @param txq - which tx queue to remove frames from
|
||||
* @param head - which contains return linked-list of tx frames (descriptors)
|
||||
* @param num_frames - maximum number of frames to remove
|
||||
* @param[in/out] credit -
|
||||
* input: max credit the dequeued frames can consume
|
||||
* output: how much credit the dequeued frames consume
|
||||
* @param[out] bytes - the sum of the sizes of the dequeued frames
|
||||
* @return number of frames dequeued
|
||||
*/
|
||||
u_int16_t
|
||||
ol_tx_dequeue(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
ol_tx_desc_list *head,
|
||||
u_int16_t num_frames,
|
||||
u_int32_t *credit,
|
||||
int *bytes);
|
||||
|
||||
/**
|
||||
* @brief - free all of frames from the tx queue while deletion
|
||||
* @details
|
||||
* This function frees all of frames from the tx queue.
|
||||
* This function is called during peer or vdev deletion.
|
||||
* This function notifies the scheduler, so the scheduler can update
|
||||
* its state to account for the absence of the queue.
|
||||
*
|
||||
* @param pdev - the physical device object, which stores the txqs
|
||||
* @param txq - which tx queue to free frames from
|
||||
* @param tid - the extended TID that the queue belongs to
|
||||
*/
|
||||
void
|
||||
ol_tx_queue_free(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
int tid);
|
||||
|
||||
/**
|
||||
* @brief - discard pending tx frames from the tx queue
|
||||
* @details
|
||||
* This function is called if there are too many queues in tx scheduler.
|
||||
* This function is called if we wants to flush all pending tx
|
||||
* queues in tx scheduler.
|
||||
*
|
||||
* @param pdev - the physical device object, which stores the txqs
|
||||
* @param flush_all - flush all pending tx queues if set to true
|
||||
* @param tx_descs - List Of tx_descs to be discarded will be returned by this function
|
||||
*/
|
||||
|
||||
void
|
||||
ol_tx_queue_discard(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
bool flush_all,
|
||||
ol_tx_desc_list *tx_descs);
|
||||
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_tx_enqueue(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
struct ol_tx_desc_t *tx_desc,
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline u_int16_t
|
||||
ol_tx_dequeue(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
ol_tx_desc_list *head,
|
||||
u_int16_t num_frames,
|
||||
u_int32_t *credit,
|
||||
int *bytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_queue_free(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
int tid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_queue_discard(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
bool flush_all,
|
||||
ol_tx_desc_list *tx_descs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* defined(CONFIG_HL_SUPPORT) */
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL)
|
||||
|
||||
void
|
||||
ol_txrx_peer_bal_add_limit_peer(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
u_int16_t peer_id,
|
||||
u_int16_t peer_limit);
|
||||
|
||||
void
|
||||
ol_txrx_peer_bal_remove_limit_peer(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
u_int16_t peer_id);
|
||||
|
||||
/**
|
||||
* ol_txrx_peer_pause_but_no_mgmt_q() - suspend/pause all txqs except
|
||||
* management queue for a given peer
|
||||
* @peer: peer device object
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer);
|
||||
|
||||
/**
|
||||
* ol_txrx_peer_unpause_but_no_mgmt_q() - unpause all txqs except management
|
||||
* queue for a given peer
|
||||
* @peer: peer device object
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer);
|
||||
|
||||
/**
|
||||
* ol_tx_bad_peer_dequeue_check() - retrieve the send limit
|
||||
* of the tx queue category
|
||||
* @txq: tx queue of the head of the category list
|
||||
* @max_frames: send limit of the txq category
|
||||
* @tx_limit_flag: set true is tx limit is reached
|
||||
*
|
||||
* Return: send limit
|
||||
*/
|
||||
u_int16_t
|
||||
ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq,
|
||||
u_int16_t max_frames,
|
||||
u_int16_t *tx_limit_flag);
|
||||
|
||||
/**
|
||||
* ol_tx_bad_peer_update_tx_limit() - update the send limit of the
|
||||
* tx queue category
|
||||
* @pdev: the physical device object
|
||||
* @txq: tx queue of the head of the category list
|
||||
* @frames: frames that has been dequeued
|
||||
* @tx_limit_flag: tx limit reached flag
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
u_int16_t frames,
|
||||
u_int16_t tx_limit_flag);
|
||||
|
||||
/**
|
||||
* ol_txrx_set_txq_peer() - set peer to the tx queue's peer
|
||||
* @txq: tx queue for a given tid
|
||||
* @peer: the peer device object
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_txrx_set_txq_peer(
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
struct ol_txrx_peer_t *peer);
|
||||
|
||||
/**
|
||||
* @brief - initialize the peer balance context
|
||||
* @param pdev - the physical device object, which stores the txqs
|
||||
*/
|
||||
void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev);
|
||||
|
||||
/**
|
||||
* @brief - deinitialize the peer balance context
|
||||
* @param pdev - the physical device object, which stores the txqs
|
||||
*/
|
||||
void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev);
|
||||
|
||||
#else
|
||||
|
||||
static inline void ol_txrx_peer_bal_add_limit_peer(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
u_int16_t peer_id,
|
||||
u_int16_t peer_limit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_txrx_peer_bal_remove_limit_peer(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
u_int16_t peer_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline u_int16_t
|
||||
ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq,
|
||||
u_int16_t max_frames,
|
||||
u_int16_t *tx_limit_flag)
|
||||
{
|
||||
/* just return max_frames */
|
||||
return max_frames;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
u_int16_t frames,
|
||||
u_int16_t tx_limit_flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_txrx_set_txq_peer(
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
struct ol_txrx_peer_t *peer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING)
|
||||
|
||||
/**
|
||||
* ol_tx_queue_log_sched() - start logging of tx queues for HL
|
||||
* @pdev: physical device object
|
||||
* @credit: number of credits
|
||||
* @num_active_tids: number of active tids for which logging needs to be done
|
||||
* @active_bitmap:bitmap
|
||||
* @data: buffer
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_tx_queue_log_sched(struct ol_txrx_pdev_t *pdev,
|
||||
int credit,
|
||||
int *num_active_tids,
|
||||
uint32_t **active_bitmap, uint8_t **data);
|
||||
#else
|
||||
|
||||
#define OL_TX_QUEUE_LOG_SCHED( \
|
||||
pdev, credit, num_active_tids, active_bitmap, data)
|
||||
static inline void
|
||||
ol_tx_queue_log_sched(struct ol_txrx_pdev_t *pdev,
|
||||
int credit,
|
||||
int *num_active_tids,
|
||||
uint32_t **active_bitmap, uint8_t **data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) */
|
||||
|
||||
#define ol_tx_queues_display(pdev) /* no-op */
|
||||
#if defined(CONFIG_HL_SUPPORT) && TXRX_DEBUG_LEVEL > 5
|
||||
/**
|
||||
* @brief - show current state of all tx queues
|
||||
* @param pdev - the physical device object, which stores the txqs
|
||||
*/
|
||||
void
|
||||
ol_tx_queues_display(struct ol_txrx_pdev_t *pdev);
|
||||
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_tx_queues_display(struct ol_txrx_pdev_t *pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ol_tx_queue_decs_reinit(peer, peer_id) /* no-op */
|
||||
|
||||
@@ -89,4 +448,134 @@ void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev);
|
||||
#else
|
||||
#define ol_tx_throttle_init(pdev) /*no op */
|
||||
#endif
|
||||
|
||||
#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL
|
||||
|
||||
static inline bool
|
||||
ol_tx_is_txq_last_serviced_queue(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq)
|
||||
{
|
||||
return txq == pdev->tx_sched.last_used_txq;
|
||||
}
|
||||
|
||||
/**
|
||||
* ol_tx_txq_group_credit_limit() - check for credit limit of a given tx queue
|
||||
* @pdev: physical device object
|
||||
* @txq: tx queue for which credit limit needs be to checked
|
||||
* @credit: number of credits of the selected category
|
||||
*
|
||||
* Return: updated credits
|
||||
*/
|
||||
u_int32_t ol_tx_txq_group_credit_limit(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
u_int32_t credit);
|
||||
|
||||
/**
|
||||
* ol_tx_txq_group_credit_update() - update group credits of the
|
||||
* selected catoegory
|
||||
* @pdev: physical device object
|
||||
* @txq: tx queue for which credit needs to be updated
|
||||
* @credit: number of credits by which selected category needs to be updated
|
||||
* @absolute: TXQ group absolute value
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void ol_tx_txq_group_credit_update(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
int32_t credit,
|
||||
u_int8_t absolute);
|
||||
|
||||
/**
|
||||
* ol_tx_set_vdev_group_ptr() - update vdev queues group pointer
|
||||
* @pdev: physical device object
|
||||
* @vdev_id: vdev id for which group pointer needs to update
|
||||
* @grp_ptr: pointer to ol tx queue group which needs to be set for vdev queues
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_tx_set_vdev_group_ptr(
|
||||
ol_txrx_pdev_handle pdev,
|
||||
u_int8_t vdev_id,
|
||||
struct ol_tx_queue_group_t *grp_ptr);
|
||||
|
||||
/**
|
||||
* ol_tx_txq_set_group_ptr() - update tx queue group pointer
|
||||
* @txq: tx queue of which group pointer needs to update
|
||||
* @grp_ptr: pointer to ol tx queue group which needs to be
|
||||
* set for given tx queue
|
||||
*
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_tx_txq_set_group_ptr(
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
struct ol_tx_queue_group_t *grp_ptr);
|
||||
|
||||
/**
|
||||
* ol_tx_set_peer_group_ptr() - update peer tx queues group pointer
|
||||
* for a given tid
|
||||
* @pdev: physical device object
|
||||
* @peer: peer device object
|
||||
* @vdev_id: vdev id
|
||||
* @tid: tid for which group pointer needs to update
|
||||
*
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void
|
||||
ol_tx_set_peer_group_ptr(
|
||||
ol_txrx_pdev_handle pdev,
|
||||
struct ol_txrx_peer_t *peer,
|
||||
u_int8_t vdev_id,
|
||||
u_int8_t tid);
|
||||
#else
|
||||
|
||||
static inline bool
|
||||
ol_tx_is_txq_last_serviced_queue(struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
u_int32_t ol_tx_txq_group_credit_limit(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
u_int32_t credit)
|
||||
{
|
||||
return credit;
|
||||
}
|
||||
|
||||
static inline void ol_tx_txq_group_credit_update(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
int32_t credit,
|
||||
u_int8_t absolute)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_txq_set_group_ptr(
|
||||
struct ol_tx_frms_queue_t *txq,
|
||||
struct ol_tx_queue_group_t *grp_ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_set_peer_group_ptr(
|
||||
ol_txrx_pdev_handle pdev,
|
||||
struct ol_txrx_peer_t *peer,
|
||||
u_int8_t vdev_id,
|
||||
u_int8_t tid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _OL_TX_QUEUE__H_ */
|
||||
|
1482
core/dp/txrx/ol_tx_sched.c
Normal file
1482
core/dp/txrx/ol_tx_sched.c
Normal file
File diff suppressed because it is too large
Load Diff
198
core/dp/txrx/ol_tx_sched.h
Normal file
198
core/dp/txrx/ol_tx_sched.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
|
||||
*
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
* copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file was originally distributed by Qualcomm Atheros, Inc.
|
||||
* under proprietary terms before Copyright ownership was assigned
|
||||
* to the Linux Foundation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ol_tx_sched.h
|
||||
* @brief API definitions for the tx scheduler module within the data SW.
|
||||
*/
|
||||
#ifndef _OL_TX_SCHED__H_
|
||||
#define _OL_TX_SCHED__H_
|
||||
|
||||
#include <qdf_types.h>
|
||||
|
||||
enum ol_tx_queue_action {
|
||||
OL_TX_ENQUEUE_FRAME,
|
||||
OL_TX_DELETE_QUEUE,
|
||||
OL_TX_PAUSE_QUEUE,
|
||||
OL_TX_UNPAUSE_QUEUE,
|
||||
OL_TX_DISCARD_FRAMES,
|
||||
};
|
||||
|
||||
struct ol_tx_sched_notify_ctx_t {
|
||||
int event;
|
||||
struct ol_tx_frms_queue_t *txq;
|
||||
union {
|
||||
int ext_tid;
|
||||
struct ol_txrx_msdu_info_t *tx_msdu_info;
|
||||
} info;
|
||||
int frames;
|
||||
int bytes;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
void
|
||||
ol_tx_sched_notify(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_sched_notify_ctx_t *ctx);
|
||||
|
||||
void
|
||||
ol_tx_sched(struct ol_txrx_pdev_t *pdev);
|
||||
|
||||
u_int16_t
|
||||
ol_tx_sched_discard_select(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
u_int16_t frms,
|
||||
ol_tx_desc_list *tx_descs,
|
||||
bool force);
|
||||
|
||||
void *
|
||||
ol_tx_sched_attach(struct ol_txrx_pdev_t *pdev);
|
||||
|
||||
void
|
||||
ol_tx_sched_detach(struct ol_txrx_pdev_t *pdev);
|
||||
|
||||
void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev);
|
||||
|
||||
void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev);
|
||||
|
||||
void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev);
|
||||
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_tx_sched_notify(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
struct ol_tx_sched_notify_ctx_t *ctx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_sched(struct ol_txrx_pdev_t *pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline u_int16_t
|
||||
ol_tx_sched_discard_select(
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
u_int16_t frms,
|
||||
ol_tx_desc_list *tx_descs,
|
||||
bool force)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
ol_tx_sched_attach(struct ol_txrx_pdev_t *pdev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_sched_detach(struct ol_txrx_pdev_t *pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_HL_SUPPORT) */
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) || defined(TX_CREDIT_RECLAIM_SUPPORT)
|
||||
/*
|
||||
* HL needs to keep track of the amount of credit available to download
|
||||
* tx frames to the target - the download scheduler decides when to
|
||||
* download frames, and which frames to download, based on the credit
|
||||
* availability.
|
||||
* LL systems that use TX_CREDIT_RECLAIM_SUPPORT also need to keep track
|
||||
* of the target_tx_credit, to determine when to poll for tx completion
|
||||
* messages.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
ol_tx_target_credit_adjust(int factor,
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t msdu)
|
||||
{
|
||||
qdf_atomic_add(factor * htt_tx_msdu_credit(msdu),
|
||||
&pdev->target_tx_credit);
|
||||
}
|
||||
|
||||
static inline void ol_tx_target_credit_decr(struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t msdu)
|
||||
{
|
||||
ol_tx_target_credit_adjust(-1, pdev, msdu);
|
||||
}
|
||||
|
||||
static inline void ol_tx_target_credit_incr(struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t msdu)
|
||||
{
|
||||
ol_tx_target_credit_adjust(1, pdev, msdu);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* LL does not need to keep track of target credit.
|
||||
* Since the host tx descriptor pool size matches the target's,
|
||||
* we know the target has space for the new tx frame if the host's
|
||||
* tx descriptor allocation succeeded.
|
||||
*/
|
||||
static inline void
|
||||
ol_tx_target_credit_adjust(int factor,
|
||||
struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t msdu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_tx_target_credit_decr(struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t msdu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void ol_tx_target_credit_incr(struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t msdu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif /* _OL_TX_SCHED__H_ */
|
@@ -47,15 +47,20 @@
|
||||
#include <ol_txrx_types.h> /* ol_txrx_vdev_t, etc */
|
||||
#include <ol_tx_desc.h> /* ol_tx_desc_find, ol_tx_desc_frame_free */
|
||||
#ifdef QCA_COMPUTE_TX_DELAY
|
||||
#include <ol_tx_classify.h> /* ol_tx_dest_addr_find */
|
||||
#endif
|
||||
#include <ol_txrx_internal.h> /* OL_TX_DESC_NO_REFS, etc. */
|
||||
#include <ol_osif_txrx_api.h>
|
||||
#include <ol_tx.h> /* ol_tx_reinject */
|
||||
|
||||
#include <ol_cfg.h> /* ol_cfg_is_high_latency */
|
||||
#include <ol_tx_sched.h>
|
||||
#ifdef QCA_SUPPORT_SW_TXRX_ENCAP
|
||||
#include <ol_txrx_encap.h> /* OL_TX_RESTORE_HDR, etc */
|
||||
#endif
|
||||
#include <ol_tx_queue.h>
|
||||
#include <ol_txrx.h>
|
||||
|
||||
|
||||
#ifdef TX_CREDIT_RECLAIM_SUPPORT
|
||||
|
||||
@@ -73,7 +78,8 @@
|
||||
|
||||
#endif /* TX_CREDIT_RECLAIM_SUPPORT */
|
||||
|
||||
#if defined(TX_CREDIT_RECLAIM_SUPPORT)
|
||||
#if defined(CONFIG_HL_SUPPORT) || defined(TX_CREDIT_RECLAIM_SUPPORT)
|
||||
|
||||
/*
|
||||
* HL needs to keep track of the amount of credit available to download
|
||||
* tx frames to the target - the download scheduler decides when to
|
||||
@@ -83,53 +89,87 @@
|
||||
* of the target_tx_credit, to determine when to poll for tx completion
|
||||
* messages.
|
||||
*/
|
||||
#define OL_TX_TARGET_CREDIT_ADJUST(factor, pdev, msdu) \
|
||||
qdf_atomic_add( \
|
||||
factor * htt_tx_msdu_credit(msdu), &pdev->target_tx_credit)
|
||||
#define OL_TX_TARGET_CREDIT_DECR(pdev, msdu) \
|
||||
OL_TX_TARGET_CREDIT_ADJUST(-1, pdev, msdu)
|
||||
#define OL_TX_TARGET_CREDIT_INCR(pdev, msdu) \
|
||||
OL_TX_TARGET_CREDIT_ADJUST(1, pdev, msdu)
|
||||
#define OL_TX_TARGET_CREDIT_DECR_INT(pdev, delta) \
|
||||
qdf_atomic_add(-1 * delta, &pdev->target_tx_credit)
|
||||
#define OL_TX_TARGET_CREDIT_INCR_INT(pdev, delta) \
|
||||
qdf_atomic_add(delta, &pdev->target_tx_credit)
|
||||
static inline void
|
||||
ol_tx_target_credit_decr_int(struct ol_txrx_pdev_t *pdev, int delta)
|
||||
{
|
||||
qdf_atomic_add(-1 * delta, &pdev->target_tx_credit);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_target_credit_incr_int(struct ol_txrx_pdev_t *pdev, int delta)
|
||||
{
|
||||
qdf_atomic_add(delta, &pdev->target_tx_credit);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* LL does not need to keep track of target credit.
|
||||
* Since the host tx descriptor pool size matches the target's,
|
||||
* we know the target has space for the new tx frame if the host's
|
||||
* tx descriptor allocation succeeded.
|
||||
*/
|
||||
#define OL_TX_TARGET_CREDIT_ADJUST(factor, pdev, msdu) /* no-op */
|
||||
#define OL_TX_TARGET_CREDIT_DECR(pdev, msdu) /* no-op */
|
||||
#define OL_TX_TARGET_CREDIT_INCR(pdev, msdu) /* no-op */
|
||||
#define OL_TX_TARGET_CREDIT_DECR_INT(pdev, delta) /* no-op */
|
||||
#define OL_TX_TARGET_CREDIT_INCR_INT(pdev, delta) /* no-op */
|
||||
|
||||
static inline void
|
||||
ol_tx_target_credit_decr_int(struct ol_txrx_pdev_t *pdev, int delta)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_tx_target_credit_incr_int(struct ol_txrx_pdev_t *pdev, int delta)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
|
||||
#define OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev) \
|
||||
do { \
|
||||
struct ol_txrx_vdev_t *vdev; \
|
||||
TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { \
|
||||
if (qdf_atomic_read(&vdev->os_q_paused) && \
|
||||
(vdev->tx_fl_hwm != 0)) { \
|
||||
qdf_spin_lock(&pdev->tx_mutex); \
|
||||
if (pdev->tx_desc.num_free > \
|
||||
vdev->tx_fl_hwm) { \
|
||||
qdf_atomic_set(&vdev->os_q_paused, 0); \
|
||||
qdf_spin_unlock(&pdev->tx_mutex); \
|
||||
ol_txrx_flow_control_cb(vdev, true);\
|
||||
} \
|
||||
else { \
|
||||
qdf_spin_unlock(&pdev->tx_mutex); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL)
|
||||
|
||||
/**
|
||||
* ol_tx_flow_ct_unpause_os_q() - Unpause OS Q
|
||||
* @pdev: physical device object
|
||||
*
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
static void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev)
|
||||
{
|
||||
struct ol_txrx_vdev_t *vdev;
|
||||
TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
|
||||
if (qdf_atomic_read(&vdev->os_q_paused) &&
|
||||
(vdev->tx_fl_hwm != 0)) {
|
||||
qdf_spin_lock(&pdev->tx_mutex);
|
||||
if (pdev->tx_desc.num_free > vdev->tx_fl_hwm) {
|
||||
qdf_atomic_set(&vdev->os_q_paused, 0);
|
||||
qdf_spin_unlock(&pdev->tx_mutex);
|
||||
ol_txrx_flow_control_cb(vdev, true);
|
||||
} else {
|
||||
qdf_spin_unlock(&pdev->tx_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(CONFIG_HL_SUPPORT) && defined(CONFIG_PER_VDEV_TX_DESC_POOL)
|
||||
|
||||
static void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev)
|
||||
{
|
||||
struct ol_txrx_vdev_t *vdev;
|
||||
TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
|
||||
if (qdf_atomic_read(&vdev->os_q_paused) &&
|
||||
(vdev->tx_fl_hwm != 0)) {
|
||||
qdf_spin_lock(&pdev->tx_mutex);
|
||||
if (((ol_tx_desc_pool_size_hl(
|
||||
vdev->pdev->ctrl_pdev) >> 1)
|
||||
- TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED)
|
||||
- qdf_atomic_read(&vdev->tx_desc_count)
|
||||
> vdev->tx_fl_hwm) {
|
||||
qdf_atomic_set(&vdev->os_q_paused, 0);
|
||||
qdf_spin_unlock(&pdev->tx_mutex);
|
||||
vdev->osif_flow_control_cb(vdev, true);
|
||||
} else {
|
||||
qdf_spin_unlock(&pdev->tx_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev)
|
||||
|
||||
static inline void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
|
||||
|
||||
static inline uint16_t
|
||||
@@ -145,7 +185,7 @@ ol_tx_send_base(struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_len(msdu));
|
||||
|
||||
msdu_credit_consumed = htt_tx_msdu_credit(msdu);
|
||||
OL_TX_TARGET_CREDIT_DECR_INT(pdev, msdu_credit_consumed);
|
||||
ol_tx_target_credit_decr_int(pdev, msdu_credit_consumed);
|
||||
OL_TX_CREDIT_RECLAIM(pdev);
|
||||
|
||||
/*
|
||||
@@ -190,7 +230,7 @@ ol_tx_send(struct ol_txrx_pdev_t *pdev,
|
||||
vdev_id));
|
||||
failed = htt_tx_send_std(pdev->htt_pdev, msdu, id);
|
||||
if (qdf_unlikely(failed)) {
|
||||
OL_TX_TARGET_CREDIT_INCR_INT(pdev, msdu_credit_consumed);
|
||||
ol_tx_target_credit_incr_int(pdev, msdu_credit_consumed);
|
||||
ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */);
|
||||
}
|
||||
}
|
||||
@@ -212,7 +252,7 @@ ol_tx_send_batch(struct ol_txrx_pdev_t *pdev,
|
||||
msdu_id_storage = ol_tx_msdu_id_storage(rejected);
|
||||
tx_desc = ol_tx_desc_find(pdev, *msdu_id_storage);
|
||||
|
||||
OL_TX_TARGET_CREDIT_INCR(pdev, rejected);
|
||||
ol_tx_target_credit_incr(pdev, rejected);
|
||||
ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */);
|
||||
|
||||
rejected = next;
|
||||
@@ -235,7 +275,7 @@ ol_tx_send_nonstd(struct ol_txrx_pdev_t *pdev,
|
||||
if (failed) {
|
||||
TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
|
||||
"Error: freeing tx frame after htt_tx failed");
|
||||
OL_TX_TARGET_CREDIT_INCR_INT(pdev, msdu_credit_consumed);
|
||||
ol_tx_target_credit_incr_int(pdev, msdu_credit_consumed);
|
||||
ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */);
|
||||
}
|
||||
}
|
||||
@@ -266,7 +306,7 @@ ol_tx_download_done_base(struct ol_txrx_pdev_t *pdev,
|
||||
}
|
||||
|
||||
if (status != A_OK) {
|
||||
OL_TX_TARGET_CREDIT_INCR(pdev, msdu);
|
||||
ol_tx_target_credit_incr(pdev, msdu);
|
||||
ol_tx_desc_frame_free_nonstd(pdev, tx_desc,
|
||||
1 /* download err */);
|
||||
} else {
|
||||
@@ -340,9 +380,15 @@ static void
|
||||
ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev,
|
||||
enum htt_tx_status status,
|
||||
uint16_t *desc_ids, int num_msdus);
|
||||
#define OL_TX_DELAY_COMPUTE ol_tx_delay_compute
|
||||
|
||||
#else
|
||||
#define OL_TX_DELAY_COMPUTE(pdev, status, desc_ids, num_msdus) /* no-op */
|
||||
static inline void
|
||||
ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev,
|
||||
enum htt_tx_status status,
|
||||
uint16_t *desc_ids, int num_msdus)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* QCA_COMPUTE_TX_DELAY */
|
||||
|
||||
#ifndef OL_TX_RESTORE_HDR
|
||||
@@ -469,8 +515,11 @@ void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits)
|
||||
{
|
||||
ol_tx_target_credit_update(pdev, credits);
|
||||
|
||||
if (pdev->cfg.is_high_latency)
|
||||
ol_tx_sched(pdev);
|
||||
|
||||
/* UNPAUSE OS Q */
|
||||
OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev);
|
||||
ol_tx_flow_ct_unpause_os_q(pdev);
|
||||
}
|
||||
|
||||
/* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of
|
||||
@@ -495,7 +544,7 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
|
||||
ol_tx_desc_list tx_descs;
|
||||
TAILQ_INIT(&tx_descs);
|
||||
|
||||
OL_TX_DELAY_COMPUTE(pdev, status, desc_ids, num_msdus);
|
||||
ol_tx_delay_compute(pdev, status, desc_ids, num_msdus);
|
||||
|
||||
for (i = 0; i < num_msdus; i++) {
|
||||
tx_desc_id = desc_ids[i];
|
||||
@@ -507,6 +556,7 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
|
||||
qdf_nbuf_data_addr(netbuf),
|
||||
sizeof(qdf_nbuf_data(netbuf)), tx_desc->id, status));
|
||||
qdf_runtime_pm_put();
|
||||
ol_tx_desc_update_group_credit(pdev, tx_desc_id, 1, 0, status);
|
||||
/* Per SDU update of byte count */
|
||||
byte_cnt += qdf_nbuf_len(netbuf);
|
||||
if (OL_TX_DESC_NO_REFS(tx_desc)) {
|
||||
@@ -540,14 +590,158 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev,
|
||||
status != htt_tx_status_ok);
|
||||
}
|
||||
|
||||
OL_TX_TARGET_CREDIT_ADJUST(num_msdus, pdev, NULL);
|
||||
if (pdev->cfg.is_high_latency) {
|
||||
/*
|
||||
* Credit was already explicitly updated by HTT,
|
||||
* but update the number of available tx descriptors,
|
||||
* then invoke the scheduler, since new credit is probably
|
||||
* available now.
|
||||
*/
|
||||
qdf_atomic_add(num_msdus, &pdev->tx_queue.rsrc_cnt);
|
||||
ol_tx_sched(pdev);
|
||||
} else {
|
||||
ol_tx_target_credit_adjust(num_msdus, pdev, NULL);
|
||||
}
|
||||
|
||||
/* UNPAUSE OS Q */
|
||||
OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev);
|
||||
ol_tx_flow_ct_unpause_os_q(pdev);
|
||||
/* Do one shot statistics */
|
||||
TXRX_STATS_UPDATE_TX_STATS(pdev, status, num_msdus, byte_cnt);
|
||||
}
|
||||
|
||||
#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL
|
||||
|
||||
void ol_tx_desc_update_group_credit(ol_txrx_pdev_handle pdev,
|
||||
u_int16_t tx_desc_id, int credit, u_int8_t absolute,
|
||||
enum htt_tx_status status)
|
||||
{
|
||||
uint8_t i, is_member;
|
||||
uint16_t vdev_id_mask;
|
||||
struct ol_tx_desc_t *tx_desc;
|
||||
|
||||
tx_desc = ol_tx_desc_find(pdev, tx_desc_id);
|
||||
for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) {
|
||||
vdev_id_mask =
|
||||
OL_TXQ_GROUP_VDEV_ID_MASK_GET(
|
||||
pdev->txq_grps[i].membership);
|
||||
is_member = OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(vdev_id_mask,
|
||||
tx_desc->vdev->vdev_id);
|
||||
if (is_member) {
|
||||
ol_txrx_update_group_credit(&pdev->txq_grps[i],
|
||||
credit, absolute);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ol_tx_update_group_credit_stats(pdev);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_HL_LOGGING
|
||||
|
||||
void ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev)
|
||||
{
|
||||
uint16_t curr_index;
|
||||
uint8_t i;
|
||||
|
||||
qdf_spin_lock_bh(&pdev->grp_stat_spinlock);
|
||||
pdev->grp_stats.last_valid_index++;
|
||||
if (pdev->grp_stats.last_valid_index > (OL_TX_GROUP_STATS_LOG_SIZE
|
||||
- 1)) {
|
||||
pdev->grp_stats.last_valid_index -= OL_TX_GROUP_STATS_LOG_SIZE;
|
||||
pdev->grp_stats.wrap_around = 1;
|
||||
}
|
||||
curr_index = pdev->grp_stats.last_valid_index;
|
||||
|
||||
for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) {
|
||||
pdev->grp_stats.stats[curr_index].grp[i].member_vdevs =
|
||||
OL_TXQ_GROUP_VDEV_ID_MASK_GET(
|
||||
pdev->txq_grps[i].membership);
|
||||
pdev->grp_stats.stats[curr_index].grp[i].credit =
|
||||
qdf_atomic_read(&pdev->txq_grps[i].credit);
|
||||
}
|
||||
|
||||
qdf_spin_unlock_bh(&pdev->grp_stat_spinlock);
|
||||
}
|
||||
|
||||
void ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev)
|
||||
{
|
||||
uint16_t i, j, is_break = 0;
|
||||
int16_t curr_index, old_index, wrap_around;
|
||||
uint16_t curr_credit, old_credit, mem_vdevs;
|
||||
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
||||
"Group credit stats:");
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
||||
" No: GrpID: Credit: Change: vdev_map");
|
||||
|
||||
qdf_spin_lock_bh(&pdev->grp_stat_spinlock);
|
||||
curr_index = pdev->grp_stats.last_valid_index;
|
||||
wrap_around = pdev->grp_stats.wrap_around;
|
||||
qdf_spin_unlock_bh(&pdev->grp_stat_spinlock);
|
||||
|
||||
if (curr_index < 0) {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
||||
"Not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < OL_TX_GROUP_STATS_LOG_SIZE; i++) {
|
||||
old_index = curr_index - 1;
|
||||
if (old_index < 0) {
|
||||
if (wrap_around == 0)
|
||||
is_break = 1;
|
||||
else
|
||||
old_index = OL_TX_GROUP_STATS_LOG_SIZE - 1;
|
||||
}
|
||||
|
||||
for (j = 0; j < OL_TX_MAX_TXQ_GROUPS; j++) {
|
||||
qdf_spin_lock_bh(&pdev->grp_stat_spinlock);
|
||||
curr_credit =
|
||||
pdev->grp_stats.stats[curr_index].
|
||||
grp[j].credit;
|
||||
if (!is_break)
|
||||
old_credit =
|
||||
pdev->grp_stats.stats[old_index].
|
||||
grp[j].credit;
|
||||
|
||||
mem_vdevs =
|
||||
pdev->grp_stats.stats[curr_index].grp[j].
|
||||
member_vdevs;
|
||||
qdf_spin_unlock_bh(&pdev->grp_stat_spinlock);
|
||||
|
||||
if (!is_break)
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
"%4d: %5d: %6d %6d %8x",
|
||||
curr_index, j,
|
||||
curr_credit,
|
||||
(curr_credit - old_credit),
|
||||
mem_vdevs);
|
||||
else
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
"%4d: %5d: %6d %6s %8x",
|
||||
curr_index, j,
|
||||
curr_credit, "NA", mem_vdevs);
|
||||
}
|
||||
|
||||
if (is_break)
|
||||
break;
|
||||
|
||||
curr_index = old_index;
|
||||
}
|
||||
}
|
||||
|
||||
void ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev)
|
||||
{
|
||||
qdf_spin_lock_bh(&pdev->grp_stat_spinlock);
|
||||
qdf_mem_zero(&pdev->grp_stats, sizeof(pdev->grp_stats));
|
||||
pdev->grp_stats.last_valid_index = -1;
|
||||
pdev->grp_stats.wrap_around = 0;
|
||||
qdf_spin_unlock_bh(&pdev->grp_stat_spinlock);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ol_tx_single_completion_handler performs the same tx completion
|
||||
* processing as ol_tx_completion_handler, but for a single frame.
|
||||
@@ -581,8 +775,18 @@ ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev,
|
||||
qdf_atomic_read(&pdev->target_tx_credit),
|
||||
1, qdf_atomic_read(&pdev->target_tx_credit) + 1);
|
||||
|
||||
|
||||
qdf_atomic_add(1, &pdev->target_tx_credit);
|
||||
if (pdev->cfg.is_high_latency) {
|
||||
/*
|
||||
* Credit was already explicitly updated by HTT,
|
||||
* but update the number of available tx descriptors,
|
||||
* then invoke the scheduler, since new credit is probably
|
||||
* available now.
|
||||
*/
|
||||
qdf_atomic_add(1, &pdev->tx_queue.rsrc_cnt);
|
||||
ol_tx_sched(pdev);
|
||||
} else {
|
||||
qdf_atomic_add(1, &pdev->target_tx_credit);
|
||||
}
|
||||
}
|
||||
|
||||
/* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of
|
||||
@@ -649,7 +853,12 @@ ol_tx_inspect_handler(ol_txrx_pdev_handle pdev,
|
||||
qdf_atomic_read(&pdev->target_tx_credit) +
|
||||
num_msdus);
|
||||
|
||||
OL_TX_TARGET_CREDIT_ADJUST(num_msdus, pdev, NULL);
|
||||
if (pdev->cfg.is_high_latency) {
|
||||
/* credit was already explicitly updated by HTT */
|
||||
ol_tx_sched(pdev);
|
||||
} else {
|
||||
ol_tx_target_credit_adjust(num_msdus, pdev, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef QCA_COMPUTE_TX_DELAY
|
||||
@@ -777,31 +986,6 @@ ol_tx_delay_hist(ol_txrx_pdev_handle pdev,
|
||||
}
|
||||
|
||||
#ifdef QCA_COMPUTE_TX_DELAY_PER_TID
|
||||
static inline uint8_t *ol_tx_dest_addr_find(struct ol_txrx_pdev_t *pdev,
|
||||
qdf_nbuf_t tx_nbuf)
|
||||
{
|
||||
uint8_t *hdr_ptr;
|
||||
void *datap = qdf_nbuf_data(tx_nbuf);
|
||||
|
||||
if (pdev->frame_format == wlan_frm_fmt_raw) {
|
||||
/* adjust hdr_ptr to RA */
|
||||
struct ieee80211_frame *wh = (struct ieee80211_frame *)datap;
|
||||
hdr_ptr = wh->i_addr1;
|
||||
} else if (pdev->frame_format == wlan_frm_fmt_native_wifi) {
|
||||
/* adjust hdr_ptr to RA */
|
||||
struct ieee80211_frame *wh = (struct ieee80211_frame *)datap;
|
||||
hdr_ptr = wh->i_addr1;
|
||||
} else if (pdev->frame_format == wlan_frm_fmt_802_3) {
|
||||
hdr_ptr = datap;
|
||||
} else {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
||||
"Invalid standard frame type: %d",
|
||||
pdev->frame_format);
|
||||
qdf_assert(0);
|
||||
hdr_ptr = NULL;
|
||||
}
|
||||
return hdr_ptr;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
ol_tx_delay_tid_from_l3_hdr(struct ol_txrx_pdev_t *pdev,
|
||||
|
@@ -35,11 +35,20 @@
|
||||
#include <qdf_nbuf.h> /* qdf_nbuf_t */
|
||||
#include <cdp_txrx_cmn.h> /* ol_txrx_vdev_t, etc. */
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
static inline void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
|
||||
/**
|
||||
* @flush the ol tx when surprise remove.
|
||||
*
|
||||
*/
|
||||
void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Send a tx frame to the target.
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -34,10 +34,100 @@
|
||||
|
||||
void ol_txrx_peer_unref_delete(struct ol_txrx_peer_t *peer);
|
||||
|
||||
/**
|
||||
* ol_tx_desc_pool_size_hl() - allocate tx descriptor pool size for HL systems
|
||||
* @ctrl_pdev: the control pdev handle
|
||||
*
|
||||
* Return: allocated pool size
|
||||
*/
|
||||
u_int16_t
|
||||
ol_tx_desc_pool_size_hl(ol_pdev_handle ctrl_pdev);
|
||||
|
||||
#ifndef OL_TX_AVG_FRM_BYTES
|
||||
#define OL_TX_AVG_FRM_BYTES 1000
|
||||
#endif
|
||||
|
||||
#ifndef OL_TX_DESC_POOL_SIZE_MIN_HL
|
||||
#define OL_TX_DESC_POOL_SIZE_MIN_HL 500
|
||||
#endif
|
||||
|
||||
#ifndef OL_TX_DESC_POOL_SIZE_MAX_HL
|
||||
#define OL_TX_DESC_POOL_SIZE_MAX_HL 5000
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_PER_VDEV_TX_DESC_POOL
|
||||
#define TXRX_HL_TX_FLOW_CTRL_VDEV_LOW_WATER_MARK 400
|
||||
#define TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED 100
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TX_DESC_HI_PRIO_RESERVE
|
||||
#define TXRX_HL_TX_DESC_HI_PRIO_RESERVED 20
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS)
|
||||
|
||||
void
|
||||
ol_txrx_hl_tdls_flag_reset(struct ol_txrx_vdev_t *vdev, bool flag);
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_txrx_hl_tdls_flag_reset(struct ol_txrx_vdev_t *vdev, bool flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HL_SUPPORT
|
||||
|
||||
void
|
||||
ol_txrx_copy_mac_addr_raw(ol_txrx_vdev_handle vdev, uint8_t *bss_addr);
|
||||
|
||||
void
|
||||
ol_txrx_add_last_real_peer(ol_txrx_pdev_handle pdev,
|
||||
ol_txrx_vdev_handle vdev,
|
||||
uint8_t *peer_id);
|
||||
|
||||
bool
|
||||
is_vdev_restore_last_peer(struct ol_txrx_peer_t *peer);
|
||||
|
||||
void
|
||||
ol_txrx_update_last_real_peer(
|
||||
ol_txrx_pdev_handle pdev,
|
||||
struct ol_txrx_peer_t *peer,
|
||||
uint8_t *peer_id, bool restore_last_peer);
|
||||
#else
|
||||
|
||||
static inline void
|
||||
ol_txrx_copy_mac_addr_raw(ol_txrx_vdev_handle vdev, uint8_t *bss_addr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_txrx_add_last_real_peer(ol_txrx_pdev_handle pdev,
|
||||
ol_txrx_vdev_handle vdev, uint8_t *peer_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_vdev_restore_last_peer(struct ol_txrx_peer_t *peer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ol_txrx_update_last_real_peer(
|
||||
ol_txrx_pdev_handle pdev,
|
||||
struct ol_txrx_peer_t *peer,
|
||||
uint8_t *peer_id, bool restore_last_peer)
|
||||
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ol_txrx_vdev_handle ol_txrx_get_vdev_from_vdev_id(uint8_t vdev_id);
|
||||
|
||||
void htt_pkt_log_init(struct ol_txrx_pdev_t *handle, void *scn);
|
||||
|
@@ -559,6 +559,36 @@ NOT_IP_TCP:
|
||||
is_mcast); \
|
||||
} while (false)
|
||||
|
||||
#ifdef CONFIG_HL_SUPPORT
|
||||
|
||||
/**
|
||||
* ol_rx_err_inv_get_wifi_header() - retrieve wifi header
|
||||
* @pdev: handle to the physical device
|
||||
* @rx_msdu: msdu of which header needs to be retrieved
|
||||
*
|
||||
* Return: wifi header
|
||||
*/
|
||||
static inline
|
||||
struct ieee80211_frame *ol_rx_err_inv_get_wifi_header(
|
||||
struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
|
||||
static inline
|
||||
struct ieee80211_frame *ol_rx_err_inv_get_wifi_header(
|
||||
struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu)
|
||||
{
|
||||
struct ieee80211_frame *wh = NULL;
|
||||
if (ol_cfg_frame_type(pdev) == wlan_frm_fmt_native_wifi)
|
||||
/* For windows, it is always native wifi header .*/
|
||||
wh = (struct ieee80211_frame *)qdf_nbuf_data(rx_msdu);
|
||||
|
||||
return wh;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu) \
|
||||
do { \
|
||||
struct ieee80211_frame *wh = NULL; \
|
||||
@@ -568,11 +598,7 @@ NOT_IP_TCP:
|
||||
/*wh = (struct ieee80211_frame *) */ \
|
||||
/*htt_rx_mpdu_wifi_hdr_retrieve(pdev->htt_pdev, rx_desc);*/ \
|
||||
/* this only apply to LL device.*/ \
|
||||
if (ol_cfg_frame_type(pdev->ctrl_pdev) == \
|
||||
wlan_frm_fmt_native_wifi) { \
|
||||
/* For windows, it is always native wifi header .*/ \
|
||||
wh = (struct ieee80211_frame *)qdf_nbuf_data(rx_msdu); \
|
||||
} \
|
||||
wh = ol_rx_err_inv_get_wifi_header(pdev->ctrl_pdev, rx_msdu); \
|
||||
ol_rx_err_inv_peer_statistics(pdev->ctrl_pdev, \
|
||||
wh, OL_RX_ERR_UNKNOWN_PEER); \
|
||||
} while (false)
|
||||
@@ -734,4 +760,13 @@ NOT_IP_TCP:
|
||||
|
||||
#endif /* FEATURE_TSO_DEBUG */
|
||||
|
||||
#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL
|
||||
|
||||
void
|
||||
ol_txrx_update_group_credit(
|
||||
struct ol_tx_queue_group_t *group,
|
||||
int32_t credit,
|
||||
u_int8_t absolute);
|
||||
#endif
|
||||
|
||||
#endif /* _OL_TXRX_INTERNAL__H_ */
|
||||
|
@@ -398,17 +398,85 @@ void ol_txrx_peer_find_detach(struct ol_txrx_pdev_t *pdev)
|
||||
|
||||
/*=== function definitions for message handling =============================*/
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
|
||||
void
|
||||
ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev,
|
||||
uint16_t peer_id,
|
||||
uint8_t vdev_id, uint8_t *peer_mac_addr, int tx_ready)
|
||||
{
|
||||
ol_txrx_peer_find_add_id(pdev, peer_mac_addr, peer_id);
|
||||
if (!tx_ready) {
|
||||
struct ol_txrx_peer_t *peer;
|
||||
peer = ol_txrx_peer_find_by_id(pdev, peer_id);
|
||||
if (!peer) {
|
||||
/* ol_txrx_peer_detach called before peer map arrived*/
|
||||
return;
|
||||
} else {
|
||||
if (tx_ready) {
|
||||
int i;
|
||||
/* unpause all tx queues now, since the
|
||||
* target is ready
|
||||
*/
|
||||
for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs);
|
||||
i++)
|
||||
ol_txrx_peer_tid_unpause(peer, i);
|
||||
|
||||
} else {
|
||||
/* walk through paused mgmt queue,
|
||||
* update tx descriptors
|
||||
*/
|
||||
ol_tx_queue_decs_reinit(peer, peer_id);
|
||||
|
||||
/* keep non-mgmt tx queues paused until assoc
|
||||
* is finished tx queues were paused in
|
||||
* ol_txrx_peer_attach*/
|
||||
/* unpause tx mgmt queue */
|
||||
ol_txrx_peer_tid_unpause(peer,
|
||||
HTT_TX_EXT_TID_MGMT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id)
|
||||
{
|
||||
struct ol_txrx_peer_t *peer;
|
||||
peer = ol_txrx_peer_find_by_id(pdev, peer_id);
|
||||
if (peer) {
|
||||
int i;
|
||||
/*
|
||||
* Unpause all data tx queues now that the target is ready.
|
||||
* The mgmt tx queue was not paused, so skip it.
|
||||
*/
|
||||
for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) {
|
||||
if (i == HTT_TX_EXT_TID_MGMT)
|
||||
continue; /* mgmt tx queue was not paused */
|
||||
|
||||
ol_txrx_peer_tid_unpause(peer, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
void
|
||||
ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev,
|
||||
uint16_t peer_id,
|
||||
uint8_t vdev_id,
|
||||
uint8_t *peer_mac_addr,
|
||||
int tx_ready)
|
||||
{
|
||||
ol_txrx_peer_find_add_id(pdev, peer_mac_addr, peer_id);
|
||||
|
||||
}
|
||||
|
||||
void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id)
|
||||
{
|
||||
|
@@ -123,6 +123,42 @@ enum ol_tx_frm_type {
|
||||
OL_TX_FRM_NO_FREE, /* frame requires special tx completion callback */
|
||||
};
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL)
|
||||
|
||||
#define MAX_NO_PEERS_IN_LIMIT (2*10 + 2)
|
||||
|
||||
enum ol_tx_peer_bal_state {
|
||||
ol_tx_peer_bal_enable = 0,
|
||||
ol_tx_peer_bal_disable,
|
||||
};
|
||||
|
||||
enum ol_tx_peer_bal_timer_state {
|
||||
ol_tx_peer_bal_timer_disable = 0,
|
||||
ol_tx_peer_bal_timer_active,
|
||||
ol_tx_peer_bal_timer_inactive,
|
||||
};
|
||||
|
||||
struct ol_tx_limit_peer_t {
|
||||
u_int16_t limit_flag;
|
||||
u_int16_t peer_id;
|
||||
u_int16_t limit;
|
||||
};
|
||||
|
||||
enum tx_peer_level {
|
||||
TXRX_IEEE11_B = 0,
|
||||
TXRX_IEEE11_A_G,
|
||||
TXRX_IEEE11_N,
|
||||
TXRX_IEEE11_AC,
|
||||
TXRX_IEEE11_MAX,
|
||||
};
|
||||
|
||||
struct tx_peer_threshold {
|
||||
u_int32_t tput_thresh;
|
||||
u_int32_t tx_limit;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct ol_tx_desc_t {
|
||||
qdf_nbuf_t netbuf;
|
||||
void *htt_tx_desc;
|
||||
@@ -151,11 +187,17 @@ struct ol_tx_desc_t {
|
||||
* This field is filled in with the ol_tx_frm_type enum.
|
||||
*/
|
||||
uint8_t pkt_type;
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
struct ol_txrx_vdev_t *vdev;
|
||||
#endif
|
||||
void *txq;
|
||||
|
||||
#ifdef QCA_SUPPORT_SW_TXRX_ENCAP
|
||||
/* used by tx encap, to restore the os buf start offset
|
||||
after tx complete */
|
||||
uint8_t orig_l2_hdr_bytes;
|
||||
#endif
|
||||
|
||||
#ifdef QCA_LL_TX_FLOW_CONTROL_V2
|
||||
struct ol_tx_flow_pool_t *pool;
|
||||
#endif
|
||||
@@ -197,6 +239,19 @@ struct ol_rx_reorder_timeout_list_elem_t {
|
||||
(((_tid) ^ ((_tid) >> 1)) & 0x1) ? TXRX_WMM_AC_BK : \
|
||||
TXRX_WMM_AC_BE)
|
||||
|
||||
enum {
|
||||
OL_TX_SCHED_WRR_ADV_CAT_BE,
|
||||
OL_TX_SCHED_WRR_ADV_CAT_BK,
|
||||
OL_TX_SCHED_WRR_ADV_CAT_VI,
|
||||
OL_TX_SCHED_WRR_ADV_CAT_VO,
|
||||
OL_TX_SCHED_WRR_ADV_CAT_NON_QOS_DATA,
|
||||
OL_TX_SCHED_WRR_ADV_CAT_UCAST_MGMT,
|
||||
OL_TX_SCHED_WRR_ADV_CAT_MCAST_DATA,
|
||||
OL_TX_SCHED_WRR_ADV_CAT_MCAST_MGMT,
|
||||
|
||||
OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES /* must be last */
|
||||
};
|
||||
|
||||
struct ol_tx_reorder_cat_timeout_t {
|
||||
TAILQ_HEAD(, ol_rx_reorder_timeout_list_elem_t) virtual_timer_list;
|
||||
qdf_timer_t timer;
|
||||
@@ -204,6 +259,11 @@ struct ol_tx_reorder_cat_timeout_t {
|
||||
struct ol_txrx_pdev_t *pdev;
|
||||
};
|
||||
|
||||
enum ol_tx_scheduler_status {
|
||||
ol_tx_scheduler_idle = 0,
|
||||
ol_tx_scheduler_running,
|
||||
};
|
||||
|
||||
enum ol_tx_queue_status {
|
||||
ol_tx_queue_empty = 0,
|
||||
ol_tx_queue_active,
|
||||
@@ -224,6 +284,19 @@ enum {
|
||||
ol_tx_aggr_in_progress,
|
||||
};
|
||||
|
||||
#define OL_TX_MAX_GROUPS_PER_QUEUE 1
|
||||
#define OL_TX_MAX_VDEV_ID 16
|
||||
#define OL_TXQ_GROUP_VDEV_ID_MASK_GET(_membership) \
|
||||
(((_membership) & 0xffff0000) >> 16)
|
||||
#define OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(_mask, _vdev_id) \
|
||||
((_mask >> _vdev_id) & 0x01)
|
||||
#define OL_TXQ_GROUP_AC_MASK_GET(_membership) \
|
||||
((_membership) & 0x0000ffff)
|
||||
#define OL_TXQ_GROUP_AC_BIT_MASK_GET(_mask, _ac_mask) \
|
||||
((_mask >> _ac_mask) & 0x01)
|
||||
#define OL_TXQ_GROUP_MEMBERSHIP_GET(_vdev_mask, _ac_mask) \
|
||||
((_vdev_mask << 16) | _ac_mask)
|
||||
|
||||
struct ol_tx_frms_queue_t {
|
||||
/* list_elem -
|
||||
* Allow individual tx frame queues to be linked together into
|
||||
@@ -241,6 +314,10 @@ struct ol_tx_frms_queue_t {
|
||||
uint32_t bytes;
|
||||
ol_tx_desc_list head;
|
||||
enum ol_tx_queue_status flag;
|
||||
struct ol_tx_queue_group_t *group_ptrs[OL_TX_MAX_GROUPS_PER_QUEUE];
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL)
|
||||
struct ol_txrx_peer_t *peer;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -272,6 +349,9 @@ struct ol_mac_addr {
|
||||
uint8_t mac_addr[OL_TXRX_MAC_ADDR_LEN];
|
||||
};
|
||||
|
||||
struct ol_tx_sched_t;
|
||||
|
||||
|
||||
#ifndef OL_TXRX_NUM_LOCAL_PEER_IDS
|
||||
#define OL_TXRX_NUM_LOCAL_PEER_IDS 33 /* default */
|
||||
#endif
|
||||
@@ -322,6 +402,24 @@ enum throttle_phase {
|
||||
|
||||
typedef void (*ipa_uc_op_cb_type)(uint8_t *op_msg, void *osif_ctxt);
|
||||
|
||||
struct ol_tx_queue_group_t {
|
||||
qdf_atomic_t credit;
|
||||
u_int32_t membership;
|
||||
};
|
||||
#define OL_TX_MAX_TXQ_GROUPS 2
|
||||
|
||||
#define OL_TX_GROUP_STATS_LOG_SIZE 128
|
||||
struct ol_tx_group_credit_stats_t {
|
||||
struct {
|
||||
struct {
|
||||
u_int16_t member_vdevs;
|
||||
u_int16_t credit;
|
||||
} grp[OL_TX_MAX_TXQ_GROUPS];
|
||||
} stats[OL_TX_GROUP_STATS_LOG_SIZE];
|
||||
u_int16_t last_valid_index;
|
||||
u_int16_t wrap_around;
|
||||
};
|
||||
|
||||
#ifdef QCA_LL_TX_FLOW_CONTROL_V2
|
||||
|
||||
/**
|
||||
@@ -558,6 +656,7 @@ struct ol_txrx_pdev_t {
|
||||
struct {
|
||||
uint16_t pool_size;
|
||||
uint16_t num_free;
|
||||
union ol_tx_desc_list_elem_t *array;
|
||||
union ol_tx_desc_list_elem_t *freelist;
|
||||
#ifdef QCA_LL_TX_FLOW_CONTROL_V2
|
||||
uint8_t num_invalid_bin;
|
||||
@@ -676,6 +775,24 @@ struct ol_txrx_pdev_t {
|
||||
bool host_80211_enable;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* tx_sched only applies for HL, but is defined unconditionally
|
||||
* rather than only if defined(CONFIG_HL_SUPPORT).
|
||||
* This is because the struct only
|
||||
* occupies a few bytes, and to avoid the complexity of
|
||||
* wrapping references
|
||||
* to the struct members in "defined(CONFIG_HL_SUPPORT)" conditional
|
||||
* compilation.
|
||||
* If this struct gets expanded to a non-trivial size,
|
||||
* then it should be
|
||||
* conditionally compiled to only apply if defined(CONFIG_HL_SUPPORT).
|
||||
*/
|
||||
qdf_spinlock_t tx_queue_spinlock;
|
||||
struct {
|
||||
enum ol_tx_scheduler_status tx_sched_status;
|
||||
struct ol_tx_sched_t *scheduler;
|
||||
struct ol_tx_frms_queue_t *last_used_txq;
|
||||
} tx_sched;
|
||||
/*
|
||||
* tx_queue only applies for HL, but is defined unconditionally to avoid
|
||||
* wrapping references to tx_queue in "defined(CONFIG_HL_SUPPORT)"
|
||||
@@ -690,6 +807,20 @@ struct ol_txrx_pdev_t {
|
||||
uint16_t rsrc_threshold_hi;
|
||||
} tx_queue;
|
||||
|
||||
#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)
|
||||
#define OL_TXQ_LOG_SIZE 512
|
||||
qdf_spinlock_t txq_log_spinlock;
|
||||
struct {
|
||||
int size;
|
||||
int oldest_record_offset;
|
||||
int offset;
|
||||
int allow_wrap;
|
||||
u_int32_t wrapped;
|
||||
/* aligned to u_int32_t boundary */
|
||||
u_int8_t data[OL_TXQ_LOG_SIZE];
|
||||
} txq_log;
|
||||
#endif
|
||||
|
||||
#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS
|
||||
qdf_spinlock_t peer_stat_mutex;
|
||||
#endif
|
||||
@@ -767,6 +898,35 @@ struct ol_txrx_pdev_t {
|
||||
OL_TX_MUTEX_TYPE tso_mutex;
|
||||
} tso_seg_pool;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL)
|
||||
struct {
|
||||
enum ol_tx_peer_bal_state enabled;
|
||||
qdf_spinlock_t mutex;
|
||||
/* timer used to trigger more frames for bad peers */
|
||||
qdf_timer_t peer_bal_timer;
|
||||
/*This is the time in ms of the peer balance timer period */
|
||||
u_int32_t peer_bal_period_ms;
|
||||
/*This is the txq limit */
|
||||
u_int32_t peer_bal_txq_limit;
|
||||
/*This is the state of the peer balance timer */
|
||||
enum ol_tx_peer_bal_timer_state peer_bal_timer_state;
|
||||
/*This is the counter about active peers which are under
|
||||
*tx flow control */
|
||||
u_int32_t peer_num;
|
||||
/*This is peer list which are under tx flow control */
|
||||
struct ol_tx_limit_peer_t limit_list[MAX_NO_PEERS_IN_LIMIT];
|
||||
/*This is threshold configurationl */
|
||||
struct tx_peer_threshold ctl_thresh[TXRX_IEEE11_MAX];
|
||||
} tx_peer_bal;
|
||||
#endif /* CONFIG_Hl_SUPPORT && QCA_BAD_PEER_TX_FLOW_CL */
|
||||
|
||||
struct ol_tx_queue_group_t txq_grps[OL_TX_MAX_TXQ_GROUPS];
|
||||
#ifdef DEBUG_HL_LOGGING
|
||||
qdf_spinlock_t grp_stat_spinlock;
|
||||
struct ol_tx_group_credit_stats_t grp_stats;
|
||||
#endif
|
||||
int tid_to_ac[OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES];
|
||||
uint8_t ocb_peer_valid;
|
||||
struct ol_txrx_peer_t *ocb_peer;
|
||||
ol_tx_pause_callback_fp pause_cb;
|
||||
@@ -831,6 +991,10 @@ struct ol_txrx_vdev_t {
|
||||
int16_t ibss_peer_heart_beat_timer; /* for detecting peer departure */
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
struct ol_tx_frms_queue_t txqs[OL_TX_VDEV_NUM_QUEUES];
|
||||
#endif
|
||||
|
||||
struct {
|
||||
struct {
|
||||
qdf_nbuf_t head;
|
||||
@@ -854,6 +1018,16 @@ struct ol_txrx_vdev_t {
|
||||
qdf_spinlock_t flow_control_lock;
|
||||
ol_txrx_tx_flow_control_fp osif_flow_control_cb;
|
||||
void *osif_fc_ctx;
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS)
|
||||
union ol_txrx_align_mac_addr_t hl_tdls_ap_mac_addr;
|
||||
bool hlTdlsFlag;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PER_VDEV_TX_DESC_POOL)
|
||||
qdf_atomic_t tx_desc_count;
|
||||
#endif
|
||||
|
||||
uint16_t wait_on_peer_id;
|
||||
qdf_event_t wait_delete_comp;
|
||||
#if defined(FEATURE_TSO)
|
||||
@@ -917,6 +1091,10 @@ enum {
|
||||
typedef A_STATUS (*ol_tx_filter_func)(struct ol_txrx_msdu_info_t *
|
||||
tx_msdu_info);
|
||||
|
||||
#define OL_TXRX_PEER_SECURITY_MULTICAST 0
|
||||
#define OL_TXRX_PEER_SECURITY_UNICAST 1
|
||||
#define OL_TXRX_PEER_SECURITY_MAX 2
|
||||
|
||||
struct ol_txrx_peer_t {
|
||||
struct ol_txrx_vdev_t *vdev;
|
||||
|
||||
@@ -978,6 +1156,10 @@ struct ol_txrx_peer_t {
|
||||
struct ol_txrx_peer_t *peer,
|
||||
unsigned tid, qdf_nbuf_t msdu_list);
|
||||
|
||||
#if defined(CONFIG_HL_SUPPORT)
|
||||
struct ol_tx_frms_queue_t txqs[OL_TX_NUM_TIDS];
|
||||
#endif
|
||||
|
||||
#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS
|
||||
ol_txrx_peer_stats_t stats;
|
||||
#endif
|
||||
@@ -1013,6 +1195,11 @@ struct ol_txrx_peer_t {
|
||||
uint32_t last_pkt_tsf;
|
||||
uint8_t last_pkt_tid;
|
||||
uint16_t last_pkt_center_freq;
|
||||
#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL)
|
||||
u_int16_t tx_limit;
|
||||
u_int16_t tx_limit_flag;
|
||||
u_int16_t tx_pause_flag;
|
||||
#endif
|
||||
qdf_time_t last_assoc_rcvd;
|
||||
qdf_time_t last_disassoc_rcvd;
|
||||
qdf_time_t last_deauth_rcvd;
|
||||
|
@@ -1,9 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
|
||||
*
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for
|
||||
* any purpose with or without fee is hereby granted, provided that the
|
||||
* above copyright notice and this permission notice appear in all
|
||||
|
Reference in New Issue
Block a user