Commit a1777327 authored by Avinash Patil's avatar Avinash Patil Committed by Kalle Valo

mwifiex: support for bypass tx queue

This patch adds support for another TX queue in driver- bypass
TX queue. This queue is used for sending data/mgmt packets while
in disconnected state i.e. when port is yet not unblocked.
TDLS setup packets would also be queued in this queue.
Signed-off-by: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 65d48e59
...@@ -2789,6 +2789,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -2789,6 +2789,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
{ {
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_adapter *adapter = priv->adapter;
struct sk_buff *skb, *tmp;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_remove(priv); mwifiex_dev_debugfs_remove(priv);
...@@ -2796,6 +2797,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -2796,6 +2797,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
mwifiex_stop_net_dev_queue(priv->netdev, adapter); mwifiex_stop_net_dev_queue(priv->netdev, adapter);
skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
if (netif_carrier_ok(priv->netdev)) if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev); netif_carrier_off(priv->netdev);
......
...@@ -499,6 +499,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) ...@@ -499,6 +499,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
INIT_LIST_HEAD(&priv->sta_list); INIT_LIST_HEAD(&priv->sta_list);
INIT_LIST_HEAD(&priv->auto_tdls_list); INIT_LIST_HEAD(&priv->auto_tdls_list);
skb_queue_head_init(&priv->tdls_txq); skb_queue_head_init(&priv->tdls_txq);
skb_queue_head_init(&priv->bypass_txq);
spin_lock_init(&priv->tx_ba_stream_tbl_lock); spin_lock_init(&priv->tx_ba_stream_tbl_lock);
spin_lock_init(&priv->rx_reorder_tbl_lock); spin_lock_init(&priv->rx_reorder_tbl_lock);
......
...@@ -276,6 +276,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) ...@@ -276,6 +276,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter)
!adapter->pm_wakeup_fw_try) && !adapter->pm_wakeup_fw_try) &&
(is_command_pending(adapter) || (is_command_pending(adapter) ||
!skb_queue_empty(&adapter->tx_data_q) || !skb_queue_empty(&adapter->tx_data_q) ||
!mwifiex_bypass_txlist_empty(adapter) ||
!mwifiex_wmm_lists_empty(adapter))) { !mwifiex_wmm_lists_empty(adapter))) {
adapter->pm_wakeup_fw_try = true; adapter->pm_wakeup_fw_try = true;
mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3));
...@@ -303,6 +304,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) ...@@ -303,6 +304,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter)
(mwifiex_get_priv(adapter, (mwifiex_get_priv(adapter,
MWIFIEX_BSS_ROLE_STA)) || MWIFIEX_BSS_ROLE_STA)) ||
(mwifiex_wmm_lists_empty(adapter) && (mwifiex_wmm_lists_empty(adapter) &&
mwifiex_bypass_txlist_empty(adapter) &&
skb_queue_empty(&adapter->tx_data_q))) { skb_queue_empty(&adapter->tx_data_q))) {
if (adapter->cmd_sent || adapter->curr_cmd || if (adapter->cmd_sent || adapter->curr_cmd ||
!mwifiex_is_send_cmd_allowed !mwifiex_is_send_cmd_allowed
...@@ -371,6 +373,22 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) ...@@ -371,6 +373,22 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter)
} }
} }
if ((adapter->scan_chan_gap_enabled ||
!adapter->scan_processing) &&
!adapter->data_sent &&
!mwifiex_bypass_txlist_empty(adapter) &&
!mwifiex_is_tdls_chan_switching
(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) {
mwifiex_process_bypass_tx(adapter);
if (adapter->hs_activated) {
adapter->is_hs_configured = false;
mwifiex_hs_activated_event
(mwifiex_get_priv
(adapter, MWIFIEX_BSS_ROLE_ANY),
false);
}
}
if ((adapter->scan_chan_gap_enabled || if ((adapter->scan_chan_gap_enabled ||
!adapter->scan_processing) && !adapter->scan_processing) &&
!adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) &&
...@@ -389,6 +407,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) ...@@ -389,6 +407,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter)
if (adapter->delay_null_pkt && !adapter->cmd_sent && if (adapter->delay_null_pkt && !adapter->cmd_sent &&
!adapter->curr_cmd && !is_command_pending(adapter) && !adapter->curr_cmd && !is_command_pending(adapter) &&
(mwifiex_wmm_lists_empty(adapter) && (mwifiex_wmm_lists_empty(adapter) &&
mwifiex_bypass_txlist_empty(adapter) &&
skb_queue_empty(&adapter->tx_data_q))) { skb_queue_empty(&adapter->tx_data_q))) {
if (!mwifiex_send_null_packet if (!mwifiex_send_null_packet
(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
...@@ -659,6 +678,26 @@ mwifiex_close(struct net_device *dev) ...@@ -659,6 +678,26 @@ mwifiex_close(struct net_device *dev)
return 0; return 0;
} }
static bool
mwifiex_bypass_tx_queue(struct mwifiex_private *priv,
struct sk_buff *skb)
{
struct ethhdr *eth_hdr = (struct ethhdr *)skb->data;
if (ntohs(eth_hdr->h_proto) == ETH_P_PAE ||
mwifiex_is_skb_mgmt_frame(skb) ||
(GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA &&
ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
(ntohs(eth_hdr->h_proto) == ETH_P_TDLS))) {
mwifiex_dbg(priv->adapter, DATA,
"bypass txqueue; eth type %#x, mgmt %d\n",
ntohs(eth_hdr->h_proto),
mwifiex_is_skb_mgmt_frame(skb));
return true;
}
return false;
}
/* /*
* Add buffer into wmm tx queue and queue work to transmit it. * Add buffer into wmm tx queue and queue work to transmit it.
*/ */
...@@ -676,8 +715,14 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) ...@@ -676,8 +715,14 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
} }
} }
if (mwifiex_bypass_tx_queue(priv, skb)) {
atomic_inc(&priv->adapter->tx_pending);
atomic_inc(&priv->adapter->bypass_tx_pending);
mwifiex_wmm_add_buf_bypass_txqueue(priv, skb);
} else {
atomic_inc(&priv->adapter->tx_pending); atomic_inc(&priv->adapter->tx_pending);
mwifiex_wmm_add_buf_txqueue(priv, skb); mwifiex_wmm_add_buf_txqueue(priv, skb);
}
mwifiex_queue_main_work(priv->adapter); mwifiex_queue_main_work(priv->adapter);
......
...@@ -664,6 +664,7 @@ struct mwifiex_private { ...@@ -664,6 +664,7 @@ struct mwifiex_private {
struct cfg80211_beacon_data beacon_after; struct cfg80211_beacon_data beacon_after;
struct mwifiex_11h_intf_state state_11h; struct mwifiex_11h_intf_state state_11h;
struct mwifiex_ds_mem_rw mem_rw; struct mwifiex_ds_mem_rw mem_rw;
struct sk_buff_head bypass_txq;
}; };
...@@ -834,6 +835,7 @@ struct mwifiex_adapter { ...@@ -834,6 +835,7 @@ struct mwifiex_adapter {
wait_queue_head_t init_wait_q; wait_queue_head_t init_wait_q;
void *card; void *card;
struct mwifiex_if_ops if_ops; struct mwifiex_if_ops if_ops;
atomic_t bypass_tx_pending;
atomic_t rx_pending; atomic_t rx_pending;
atomic_t tx_pending; atomic_t tx_pending;
atomic_t cmd_pending; atomic_t cmd_pending;
......
...@@ -449,6 +449,11 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) ...@@ -449,6 +449,11 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
} }
} }
int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter)
{
return atomic_read(&adapter->bypass_tx_pending) ? false : true;
}
/* /*
* This function checks if WMM Tx queue is empty. * This function checks if WMM Tx queue is empty.
*/ */
...@@ -581,6 +586,10 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) ...@@ -581,6 +586,10 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) skb_queue_walk_safe(&priv->tdls_txq, skb, tmp)
mwifiex_write_data_complete(priv->adapter, skb, 0, -1); mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
mwifiex_write_data_complete(priv->adapter, skb, 0, -1);
atomic_set(&priv->adapter->bypass_tx_pending, 0);
idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL); idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL);
idr_destroy(&priv->ack_status_frames); idr_destroy(&priv->ack_status_frames);
} }
...@@ -752,6 +761,18 @@ mwifiex_is_ralist_valid(struct mwifiex_private *priv, ...@@ -752,6 +761,18 @@ mwifiex_is_ralist_valid(struct mwifiex_private *priv,
return false; return false;
} }
/*
* This function adds a packet to bypass TX queue.
* This is special TX queue for packets which can be sent even when port_open
* is false.
*/
void
mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv,
struct sk_buff *skb)
{
skb_queue_tail(&priv->bypass_txq, skb);
}
/* /*
* This function adds a packet to WMM queue. * This function adds a packet to WMM queue.
* *
...@@ -1429,6 +1450,38 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) ...@@ -1429,6 +1450,38 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
return 0; return 0;
} }
void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter)
{
struct mwifiex_tx_param tx_param;
struct sk_buff *skb;
struct mwifiex_txinfo *tx_info;
struct mwifiex_private *priv;
int i;
if (adapter->data_sent || adapter->tx_lock_flag)
return;
for (i = 0; i < adapter->priv_num; ++i) {
priv = adapter->priv[i];
if (skb_queue_empty(&priv->bypass_txq))
continue;
skb = skb_dequeue(&priv->bypass_txq);
tx_info = MWIFIEX_SKB_TXCB(skb);
/* no aggregation for bypass packets */
tx_param.next_pkt_len = 0;
if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) {
skb_queue_head(&priv->bypass_txq, skb);
tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
} else {
atomic_dec(&adapter->bypass_tx_pending);
}
}
}
/* /*
* This function transmits the highest priority packet awaiting in the * This function transmits the highest priority packet awaiting in the
* WMM Queues. * WMM Queues.
......
...@@ -99,12 +99,16 @@ mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead) ...@@ -99,12 +99,16 @@ mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead)
void mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, void mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
struct sk_buff *skb); struct sk_buff *skb);
void mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv,
struct sk_buff *skb);
void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra); void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra);
void mwifiex_rotate_priolists(struct mwifiex_private *priv, void mwifiex_rotate_priolists(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ra, int tid); struct mwifiex_ra_list_tbl *ra, int tid);
int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter);
int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter);
void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter);
void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter);
int mwifiex_is_ralist_valid(struct mwifiex_private *priv, int mwifiex_is_ralist_valid(struct mwifiex_private *priv,
struct mwifiex_ra_list_tbl *ra_list, int tid); struct mwifiex_ra_list_tbl *ra_list, int tid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment