summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mwifiex
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c16
-rw-r--r--drivers/net/wireless/mwifiex/decl.h2
-rw-r--r--drivers/net/wireless/mwifiex/init.c5
-rw-r--r--drivers/net/wireless/mwifiex/main.c21
-rw-r--r--drivers/net/wireless/mwifiex/main.h6
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c125
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c21
7 files changed, 185 insertions, 11 deletions
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index 9b983b5..6183e25 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -170,7 +170,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
struct sk_buff *skb_aggr, *skb_src;
struct mwifiex_txinfo *tx_info_aggr, *tx_info_src;
- int pad = 0, ret;
+ int pad = 0, aggr_num = 0, ret;
struct mwifiex_tx_param tx_param;
struct txpd *ptx_pd = NULL;
struct timeval tv;
@@ -184,7 +184,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
}
tx_info_src = MWIFIEX_SKB_TXCB(skb_src);
- skb_aggr = dev_alloc_skb(adapter->tx_buf_size);
+ skb_aggr = mwifiex_alloc_dma_align_buf(adapter->tx_buf_size,
+ GFP_ATOMIC | GFP_DMA);
if (!skb_aggr) {
dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__);
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
@@ -200,6 +201,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
if (tx_info_src->flags & MWIFIEX_BUF_FLAG_TDLS_PKT)
tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
+ tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_AGGR_PKT;
skb_aggr->priority = skb_src->priority;
do_gettimeofday(&tv);
@@ -211,11 +213,9 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
break;
skb_src = skb_dequeue(&pra_list->skb_head);
-
pra_list->total_pkt_count--;
-
atomic_dec(&priv->wmm.tx_pkts_queued);
-
+ aggr_num++;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad);
@@ -251,6 +251,12 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
ptx_pd = (struct txpd *)skb_aggr->data;
skb_push(skb_aggr, headroom);
+ tx_info_aggr->aggr_num = aggr_num * 2;
+ if (adapter->data_sent || adapter->tx_lock_flag) {
+ atomic_add(aggr_num * 2, &adapter->tx_queued);
+ skb_queue_tail(&adapter->tx_data_q, skb_aggr);
+ return 0;
+ }
if (adapter->iface_type == MWIFIEX_USB) {
adapter->data_sent = true;
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index cf2fa11..6ce19be 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -83,6 +83,7 @@
#define MWIFIEX_BUF_FLAG_TDLS_PKT BIT(2)
#define MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS BIT(3)
#define MWIFIEX_BUF_FLAG_ACTION_TX_STATUS BIT(4)
+#define MWIFIEX_BUF_FLAG_AGGR_PKT BIT(5)
#define MWIFIEX_BRIDGED_PKTS_THR_HIGH 1024
#define MWIFIEX_BRIDGED_PKTS_THR_LOW 128
@@ -179,6 +180,7 @@ struct mwifiex_txinfo {
u8 flags;
u8 bss_num;
u8 bss_type;
+ u8 aggr_num;
u32 pkt_len;
u8 ack_frame_id;
u64 cookie;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 0153ce6..6936de8 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -481,6 +481,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
spin_lock_init(&adapter->rx_proc_lock);
skb_queue_head_init(&adapter->rx_data_q);
+ skb_queue_head_init(&adapter->tx_data_q);
for (i = 0; i < adapter->priv_num; ++i) {
INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
@@ -688,6 +689,10 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
}
}
+ atomic_set(&adapter->tx_queued, 0);
+ while ((skb = skb_dequeue(&adapter->tx_data_q)))
+ mwifiex_write_data_complete(adapter, skb, 0, 0);
+
spin_lock_irqsave(&adapter->rx_proc_lock, flags);
while ((skb = skb_dequeue(&adapter->rx_data_q))) {
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index d96d60a..b242c3e 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -262,6 +262,7 @@ process_start:
(adapter->pm_wakeup_card_req &&
!adapter->pm_wakeup_fw_try) &&
(is_command_pending(adapter) ||
+ !skb_queue_empty(&adapter->tx_data_q) ||
!mwifiex_wmm_lists_empty(adapter))) {
adapter->pm_wakeup_fw_try = true;
mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3));
@@ -286,7 +287,8 @@ process_start:
if ((!adapter->scan_chan_gap_enabled &&
adapter->scan_processing) || adapter->data_sent ||
- mwifiex_wmm_lists_empty(adapter)) {
+ (mwifiex_wmm_lists_empty(adapter) &&
+ skb_queue_empty(&adapter->tx_data_q))) {
if (adapter->cmd_sent || adapter->curr_cmd ||
(!is_command_pending(adapter)))
break;
@@ -338,6 +340,20 @@ process_start:
if ((adapter->scan_chan_gap_enabled ||
!adapter->scan_processing) &&
+ !adapter->data_sent &&
+ !skb_queue_empty(&adapter->tx_data_q)) {
+ mwifiex_process_tx_queue(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 ||
+ !adapter->scan_processing) &&
!adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) {
mwifiex_wmm_process_tx(adapter);
if (adapter->hs_activated) {
@@ -351,7 +367,8 @@ process_start:
if (adapter->delay_null_pkt && !adapter->cmd_sent &&
!adapter->curr_cmd && !is_command_pending(adapter) &&
- mwifiex_wmm_lists_empty(adapter)) {
+ (mwifiex_wmm_lists_empty(adapter) &&
+ skb_queue_empty(&adapter->tx_data_q))) {
if (!mwifiex_send_null_packet
(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET |
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 439db17..11db09c 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -59,6 +59,8 @@ enum {
#define MWIFIEX_MAX_AP 64
+#define MWIFIEX_MAX_PKTS_TXQ 16
+
#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
#define MWIFIEX_TIMER_10S 10000
@@ -819,6 +821,8 @@ struct mwifiex_adapter {
spinlock_t scan_pending_q_lock;
/* spin lock for RX processing routine */
spinlock_t rx_proc_lock;
+ struct sk_buff_head tx_data_q;
+ atomic_t tx_queued;
u32 scan_processing;
u16 region_code;
struct mwifiex_802_11d_domain_reg domain_reg;
@@ -905,6 +909,8 @@ struct mwifiex_adapter {
bool auto_tdls;
};
+void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
+
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
void mwifiex_set_trans_start(struct net_device *dev);
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index ea4549f..4d43371 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -92,6 +92,12 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
else
head_ptr = mwifiex_process_sta_txpd(priv, skb);
+ if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) {
+ skb_queue_tail(&adapter->tx_data_q, skb);
+ atomic_inc(&adapter->tx_queued);
+ return 0;
+ }
+
if (head_ptr) {
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
local_tx_pd = (struct txpd *)(head_ptr + hroom);
@@ -142,6 +148,123 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
return ret;
}
+static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb,
+ struct mwifiex_tx_param *tx_param)
+{
+ struct txpd *local_tx_pd = NULL;
+ u8 *head_ptr = skb->data;
+ int ret = 0;
+ struct mwifiex_private *priv;
+ struct mwifiex_txinfo *tx_info;
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num,
+ tx_info->bss_type);
+ if (!priv) {
+ dev_err(adapter->dev, "data: priv not found. Drop TX packet\n");
+ adapter->dbg.num_tx_host_to_card_failure++;
+ mwifiex_write_data_complete(adapter, skb, 0, 0);
+ return ret;
+ }
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
+ if (adapter->iface_type == MWIFIEX_USB)
+ local_tx_pd = (struct txpd *)head_ptr;
+ else
+ local_tx_pd = (struct txpd *) (head_ptr +
+ INTF_HEADER_LEN);
+ }
+
+ if (adapter->iface_type == MWIFIEX_USB) {
+ adapter->data_sent = true;
+ ret = adapter->if_ops.host_to_card(adapter,
+ MWIFIEX_USB_EP_DATA,
+ skb, NULL);
+ } else {
+ ret = adapter->if_ops.host_to_card(adapter,
+ MWIFIEX_TYPE_DATA,
+ skb, tx_param);
+ }
+ switch (ret) {
+ case -ENOSR:
+ dev_err(adapter->dev, "data: -ENOSR is returned\n");
+ break;
+ case -EBUSY:
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ (adapter->pps_uapsd_mode) &&
+ (adapter->tx_lock_flag)) {
+ priv->adapter->tx_lock_flag = false;
+ if (local_tx_pd)
+ local_tx_pd->flags = 0;
+ }
+ skb_queue_head(&adapter->tx_data_q, skb);
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
+ atomic_add(tx_info->aggr_num, &adapter->tx_queued);
+ else
+ atomic_inc(&adapter->tx_queued);
+ dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ break;
+ case -1:
+ if (adapter->iface_type != MWIFIEX_PCIE)
+ adapter->data_sent = false;
+ dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
+ ret);
+ adapter->dbg.num_tx_host_to_card_failure++;
+ mwifiex_write_data_complete(adapter, skb, 0, ret);
+ break;
+ case -EINPROGRESS:
+ if (adapter->iface_type != MWIFIEX_PCIE)
+ adapter->data_sent = false;
+ break;
+ case 0:
+ mwifiex_write_data_complete(adapter, skb, 0, ret);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static int
+mwifiex_dequeue_tx_queue(struct mwifiex_adapter *adapter)
+{
+ struct sk_buff *skb, *skb_next;
+ struct mwifiex_txinfo *tx_info;
+ struct mwifiex_tx_param tx_param;
+
+ skb = skb_dequeue(&adapter->tx_data_q);
+ if (!skb)
+ return -1;
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
+ atomic_sub(tx_info->aggr_num, &adapter->tx_queued);
+ else
+ atomic_dec(&adapter->tx_queued);
+
+ if (!skb_queue_empty(&adapter->tx_data_q))
+ skb_next = skb_peek(&adapter->tx_data_q);
+ else
+ skb_next = NULL;
+ tx_param.next_pkt_len = ((skb_next) ? skb_next->len : 0);
+ if (!tx_param.next_pkt_len) {
+ if (!mwifiex_wmm_lists_empty(adapter))
+ tx_param.next_pkt_len = 1;
+ }
+ return mwifiex_host_to_card(adapter, skb, &tx_param);
+}
+
+void
+mwifiex_process_tx_queue(struct mwifiex_adapter *adapter)
+{
+ do {
+ if (adapter->data_sent || adapter->tx_lock_flag)
+ break;
+ if (mwifiex_dequeue_tx_queue(adapter))
+ break;
+ } while (!skb_queue_empty(&adapter->tx_data_q));
+}
+
/*
* Packet send completion callback handler.
*
@@ -181,6 +304,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
atomic_dec_return(&adapter->pending_bridged_pkts);
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
+ goto done;
if (aggr)
/* For skb_aggr, do not wake up tx queue */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index a6db12c..b2e9956 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -1174,6 +1174,14 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
skb = skb_dequeue(&ptr->skb_head);
+ if (adapter->data_sent || adapter->tx_lock_flag) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ skb_queue_tail(&adapter->tx_data_q, skb);
+ atomic_inc(&adapter->tx_queued);
+ return;
+ }
+
if (!skb_queue_empty(&ptr->skb_head))
skb_next = skb_peek(&ptr->skb_head);
else
@@ -1324,11 +1332,16 @@ void
mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter)
{
do {
- /* Check if busy */
- if (adapter->data_sent || adapter->tx_lock_flag)
- break;
-
if (mwifiex_dequeue_tx_packet(adapter))
break;
+ if (adapter->iface_type != MWIFIEX_SDIO) {
+ if (adapter->data_sent ||
+ adapter->tx_lock_flag)
+ break;
+ } else {
+ if (atomic_read(&adapter->tx_queued) >=
+ MWIFIEX_MAX_PKTS_TXQ)
+ break;
+ }
} while (!mwifiex_wmm_lists_empty(adapter));
}