diff options
author | Avinash Patil <patila@marvell.com> | 2015-06-22 16:36:07 +0300 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-07-21 16:40:12 +0300 |
commit | 4e6ee91bb728a268b37c74e2dd083481bf5ebb98 (patch) | |
tree | 9fe2b55b8fe1e81a478031183a12154db5dd7a15 /drivers/net/wireless/mwifiex/sta_event.c | |
parent | 80b2089b4a0b08ff34619a8e07fc74a63b4e2d24 (diff) | |
download | linux-4e6ee91bb728a268b37c74e2dd083481bf5ebb98.tar.xz |
mwifiex: add tx data pause support
This patch adds support to enable TX data pause feature for mwifiex.
Whenever FW TX buffers reach threshold, FW would send TX pause event
to driver. Driver in turn would block data traffic to that particular
receiver address.
Signed-off-by: Avinash Patil <patila@marvell.com>
Signed-off-by: Xinming Hu <huxm@marvell.com>
Signed-off-by: Cathy Luo <cluo@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/mwifiex/sta_event.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_event.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 848de2621958..0a80814ddbb0 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -182,6 +182,67 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, return ret; } +static void +mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_header *tlv; + struct mwifiex_tx_pause_tlv *tp_tlv; + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + u16 tlv_type, tlv_len; + int tlv_buf_left, status; + + if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return; + + if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) + return; + + tlv_buf_left = event_skb->len - sizeof(u32); + tlv = (void *)event_skb->data + sizeof(u32); + while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_len = le16_to_cpu(tlv->len); + if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) > + tlv_buf_left) { + mwifiex_dbg(priv->adapter, ERROR, + "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", + tlv_len, tlv_buf_left); + break; + } + if (tlv_type == TLV_TYPE_TX_PAUSE) { + tp_tlv = (void *)tlv; + mwifiex_dbg(priv->adapter, ERROR, + "TxPause: %pM pause=%d, pkts=%d\n", + tp_tlv->peermac, tp_tlv->tx_pause, + tp_tlv->pkt_cnt); + status = mwifiex_get_tdls_link_status + (priv, tp_tlv->peermac); + if (status == TDLS_SETUP_COMPLETE) { + spin_lock_irqsave(&priv->sta_list_spinlock, + flags); + sta_ptr = mwifiex_get_sta_entry + (priv, tp_tlv->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, + flags); + if (sta_ptr && sta_ptr->tx_pause != + tp_tlv->tx_pause) { + sta_ptr->tx_pause = tp_tlv->tx_pause; + mwifiex_update_ralist_tx_pause + (priv, tp_tlv->peermac, + tp_tlv->tx_pause); + } + } + } + + tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) + + tlv_len; + tlv = (void *)((u8 *)tlv + tlv_len + + sizeof(struct mwifiex_ie_types_header)); + } +} + /* * This function handles coex events generated by firmware */ @@ -573,6 +634,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) ret = mwifiex_parse_tdls_event(priv, adapter->event_skb); break; + case EVENT_TX_DATA_PAUSE: + mwifiex_process_sta_tx_pause_event(priv, adapter->event_skb); + mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + break; + case EVENT_TX_STATUS_REPORT: mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n"); mwifiex_parse_tx_status_event(priv, adapter->event_body); |