aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwifiex
diff options
context:
space:
mode:
authorAvinash Patil <patila@marvell.com>2014-09-12 10:38:59 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-09-15 15:00:52 -0400
commit6e251174c77a28a4ebaad9be963843898b658039 (patch)
tree2f52e5110018cb9189f5149ad50893485d6cd947 /drivers/net/wireless/mwifiex
parentd8d91253ba11bb6e98105c2bc88a40d08fac06ff (diff)
mwifiex: add rx workqueue support
This patch adds RX work queue support to mwifiex. Packets received are queued to internal queue which are then processed by scheduling a work item for RX process. RX work is enabled only on SMP systems. Reviewed-by: James Cameron <quozl@laptop.org> Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Marc Yang <yangyang@marvell.com> Signed-off-by: Cathy Luo <cluo@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c14
-rw-r--r--drivers/net/wireless/mwifiex/init.c19
-rw-r--r--drivers/net/wireless/mwifiex/main.c91
-rw-r--r--drivers/net/wireless/mwifiex/main.h14
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c12
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c11
6 files changed, 159 insertions, 2 deletions
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index 06a2c215ef5e..40057079ffb9 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -183,6 +183,15 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
183 if (!tbl) 183 if (!tbl)
184 return; 184 return;
185 185
186 spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
187 priv->adapter->rx_locked = true;
188 if (priv->adapter->rx_processing) {
189 spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
190 flush_workqueue(priv->adapter->rx_workqueue);
191 } else {
192 spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
193 }
194
186 start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1); 195 start_win = (tbl->start_win + tbl->win_size) & (MAX_TID_VALUE - 1);
187 mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win); 196 mwifiex_11n_dispatch_pkt_until_start_win(priv, tbl, start_win);
188 197
@@ -194,6 +203,11 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
194 203
195 kfree(tbl->rx_reorder_ptr); 204 kfree(tbl->rx_reorder_ptr);
196 kfree(tbl); 205 kfree(tbl);
206
207 spin_lock_irqsave(&priv->adapter->rx_proc_lock, flags);
208 priv->adapter->rx_locked = false;
209 spin_unlock_irqrestore(&priv->adapter->rx_proc_lock, flags);
210
197} 211}
198 212
199/* 213/*
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index cd9baad60595..f7c97cf3840b 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -447,8 +447,11 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
447 spin_lock_init(&adapter->cmd_free_q_lock); 447 spin_lock_init(&adapter->cmd_free_q_lock);
448 spin_lock_init(&adapter->cmd_pending_q_lock); 448 spin_lock_init(&adapter->cmd_pending_q_lock);
449 spin_lock_init(&adapter->scan_pending_q_lock); 449 spin_lock_init(&adapter->scan_pending_q_lock);
450 spin_lock_init(&adapter->rx_q_lock);
451 spin_lock_init(&adapter->rx_proc_lock);
450 452
451 skb_queue_head_init(&adapter->usb_rx_data_q); 453 skb_queue_head_init(&adapter->usb_rx_data_q);
454 skb_queue_head_init(&adapter->rx_data_q);
452 455
453 for (i = 0; i < adapter->priv_num; ++i) { 456 for (i = 0; i < adapter->priv_num; ++i) {
454 INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); 457 INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
@@ -614,6 +617,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
614 int ret = -EINPROGRESS; 617 int ret = -EINPROGRESS;
615 struct mwifiex_private *priv; 618 struct mwifiex_private *priv;
616 s32 i; 619 s32 i;
620 unsigned long flags;
617 struct sk_buff *skb; 621 struct sk_buff *skb;
618 622
619 /* mwifiex already shutdown */ 623 /* mwifiex already shutdown */
@@ -648,6 +652,21 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
648 } 652 }
649 } 653 }
650 654
655 spin_lock_irqsave(&adapter->rx_proc_lock, flags);
656
657 while ((skb = skb_dequeue(&adapter->rx_data_q))) {
658 struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
659
660 atomic_dec(&adapter->rx_pending);
661 priv = adapter->priv[rx_info->bss_num];
662 if (priv)
663 priv->stats.rx_dropped++;
664
665 dev_kfree_skb_any(skb);
666 }
667
668 spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
669
651 spin_lock(&adapter->mwifiex_lock); 670 spin_lock(&adapter->mwifiex_lock);
652 671
653 if (adapter->if_ops.data_complete) { 672 if (adapter->if_ops.data_complete) {
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index f1393868d04c..b522f7c36901 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -126,6 +126,42 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
126 return 0; 126 return 0;
127} 127}
128 128
129static int mwifiex_process_rx(struct mwifiex_adapter *adapter)
130{
131 unsigned long flags;
132 struct sk_buff *skb;
133 bool delay_main_work = adapter->delay_main_work;
134
135 spin_lock_irqsave(&adapter->rx_proc_lock, flags);
136 if (adapter->rx_processing || adapter->rx_locked) {
137 spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
138 goto exit_rx_proc;
139 } else {
140 adapter->rx_processing = true;
141 spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
142 }
143
144 /* Check for Rx data */
145 while ((skb = skb_dequeue(&adapter->rx_data_q))) {
146 atomic_dec(&adapter->rx_pending);
147 if (adapter->delay_main_work &&
148 (atomic_dec_return(&adapter->rx_pending) <
149 LOW_RX_PENDING)) {
150 adapter->delay_main_work = false;
151 queue_work(adapter->rx_workqueue, &adapter->rx_work);
152 }
153 mwifiex_handle_rx_packet(adapter, skb);
154 }
155 spin_lock_irqsave(&adapter->rx_proc_lock, flags);
156 adapter->rx_processing = false;
157 spin_unlock_irqrestore(&adapter->rx_proc_lock, flags);
158
159 if (delay_main_work)
160 queue_work(adapter->workqueue, &adapter->main_work);
161exit_rx_proc:
162 return 0;
163}
164
129/* 165/*
130 * The main process. 166 * The main process.
131 * 167 *
@@ -163,6 +199,19 @@ process_start:
163 (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) 199 (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
164 break; 200 break;
165 201
202 /* If we process interrupts first, it would increase RX pending
203 * even further. Avoid this by checking if rx_pending has
204 * crossed high threshold and schedule rx work queue
205 * and then process interrupts
206 */
207 if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING) {
208 adapter->delay_main_work = true;
209 if (!adapter->rx_processing)
210 queue_work(adapter->rx_workqueue,
211 &adapter->rx_work);
212 break;
213 }
214
166 /* Handle pending interrupt if any */ 215 /* Handle pending interrupt if any */
167 if (adapter->int_status) { 216 if (adapter->int_status) {
168 if (adapter->hs_activated) 217 if (adapter->hs_activated)
@@ -171,6 +220,9 @@ process_start:
171 adapter->if_ops.process_int_status(adapter); 220 adapter->if_ops.process_int_status(adapter);
172 } 221 }
173 222
223 if (adapter->rx_work_enabled && adapter->data_received)
224 queue_work(adapter->rx_workqueue, &adapter->rx_work);
225
174 /* Need to wake up the card ? */ 226 /* Need to wake up the card ? */
175 if ((adapter->ps_state == PS_STATE_SLEEP) && 227 if ((adapter->ps_state == PS_STATE_SLEEP) &&
176 (adapter->pm_wakeup_card_req && 228 (adapter->pm_wakeup_card_req &&
@@ -183,6 +235,7 @@ process_start:
183 } 235 }
184 236
185 if (IS_CARD_RX_RCVD(adapter)) { 237 if (IS_CARD_RX_RCVD(adapter)) {
238 adapter->data_received = false;
186 adapter->pm_wakeup_fw_try = false; 239 adapter->pm_wakeup_fw_try = false;
187 if (adapter->ps_state == PS_STATE_SLEEP) 240 if (adapter->ps_state == PS_STATE_SLEEP)
188 adapter->ps_state = PS_STATE_AWAKE; 241 adapter->ps_state = PS_STATE_AWAKE;
@@ -318,6 +371,12 @@ static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
318 flush_workqueue(adapter->workqueue); 371 flush_workqueue(adapter->workqueue);
319 destroy_workqueue(adapter->workqueue); 372 destroy_workqueue(adapter->workqueue);
320 adapter->workqueue = NULL; 373 adapter->workqueue = NULL;
374
375 if (adapter->rx_workqueue) {
376 flush_workqueue(adapter->rx_workqueue);
377 destroy_workqueue(adapter->rx_workqueue);
378 adapter->rx_workqueue = NULL;
379 }
321} 380}
322 381
323/* 382/*
@@ -732,6 +791,21 @@ int is_command_pending(struct mwifiex_adapter *adapter)
732} 791}
733 792
734/* 793/*
794 * This is the RX work queue function.
795 *
796 * It handles the RX operations.
797 */
798static void mwifiex_rx_work_queue(struct work_struct *work)
799{
800 struct mwifiex_adapter *adapter =
801 container_of(work, struct mwifiex_adapter, rx_work);
802
803 if (adapter->surprise_removed)
804 return;
805 mwifiex_process_rx(adapter);
806}
807
808/*
735 * This is the main work queue function. 809 * This is the main work queue function.
736 * 810 *
737 * It handles the main process, which in turn handles the complete 811 * It handles the main process, which in turn handles the complete
@@ -787,6 +861,11 @@ mwifiex_add_card(void *card, struct semaphore *sem,
787 adapter->cmd_wait_q.status = 0; 861 adapter->cmd_wait_q.status = 0;
788 adapter->scan_wait_q_woken = false; 862 adapter->scan_wait_q_woken = false;
789 863
864 if (num_possible_cpus() > 1) {
865 adapter->rx_work_enabled = true;
866 pr_notice("rx work enabled, cpus %d\n", num_possible_cpus());
867 }
868
790 adapter->workqueue = 869 adapter->workqueue =
791 alloc_workqueue("MWIFIEX_WORK_QUEUE", 870 alloc_workqueue("MWIFIEX_WORK_QUEUE",
792 WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1); 871 WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
@@ -794,6 +873,18 @@ mwifiex_add_card(void *card, struct semaphore *sem,
794 goto err_kmalloc; 873 goto err_kmalloc;
795 874
796 INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); 875 INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
876
877 if (adapter->rx_work_enabled) {
878 adapter->rx_workqueue = alloc_workqueue("MWIFIEX_RX_WORK_QUEUE",
879 WQ_HIGHPRI |
880 WQ_MEM_RECLAIM |
881 WQ_UNBOUND, 1);
882 if (!adapter->rx_workqueue)
883 goto err_kmalloc;
884
885 INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue);
886 }
887
797 if (adapter->if_ops.iface_work) 888 if (adapter->if_ops.iface_work)
798 INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work); 889 INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work);
799 890
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index e9cd4ab4902d..1a999999b391 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -58,6 +58,9 @@ enum {
58#define MAX_TX_PENDING 100 58#define MAX_TX_PENDING 100
59#define LOW_TX_PENDING 80 59#define LOW_TX_PENDING 80
60 60
61#define HIGH_RX_PENDING 50
62#define LOW_RX_PENDING 20
63
61#define MWIFIEX_UPLD_SIZE (2312) 64#define MWIFIEX_UPLD_SIZE (2312)
62 65
63#define MAX_EVENT_SIZE 2048 66#define MAX_EVENT_SIZE 2048
@@ -714,6 +717,12 @@ struct mwifiex_adapter {
714 atomic_t cmd_pending; 717 atomic_t cmd_pending;
715 struct workqueue_struct *workqueue; 718 struct workqueue_struct *workqueue;
716 struct work_struct main_work; 719 struct work_struct main_work;
720 struct workqueue_struct *rx_workqueue;
721 struct work_struct rx_work;
722 bool rx_work_enabled;
723 bool rx_processing;
724 bool delay_main_work;
725 bool rx_locked;
717 struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; 726 struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
718 /* spin lock for init/shutdown */ 727 /* spin lock for init/shutdown */
719 spinlock_t mwifiex_lock; 728 spinlock_t mwifiex_lock;
@@ -754,6 +763,10 @@ struct mwifiex_adapter {
754 struct list_head scan_pending_q; 763 struct list_head scan_pending_q;
755 /* spin lock for scan_pending_q */ 764 /* spin lock for scan_pending_q */
756 spinlock_t scan_pending_q_lock; 765 spinlock_t scan_pending_q_lock;
766 /* spin lock for RX queue */
767 spinlock_t rx_q_lock;
768 /* spin lock for RX processing routine */
769 spinlock_t rx_proc_lock;
757 struct sk_buff_head usb_rx_data_q; 770 struct sk_buff_head usb_rx_data_q;
758 u32 scan_processing; 771 u32 scan_processing;
759 u16 region_code; 772 u16 region_code;
@@ -831,6 +844,7 @@ struct mwifiex_adapter {
831 u8 num_mem_types; 844 u8 num_mem_types;
832 u8 curr_mem_idx; 845 u8 curr_mem_idx;
833 bool scan_chan_gap_enabled; 846 bool scan_chan_gap_enabled;
847 struct sk_buff_head rx_data_q;
834}; 848};
835 849
836int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); 850int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index 2ada1b709778..1504b16e248e 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -1233,6 +1233,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
1233 struct sk_buff *skb_tmp = NULL; 1233 struct sk_buff *skb_tmp = NULL;
1234 struct mwifiex_pcie_buf_desc *desc; 1234 struct mwifiex_pcie_buf_desc *desc;
1235 struct mwifiex_pfu_buf_desc *desc2; 1235 struct mwifiex_pfu_buf_desc *desc2;
1236 unsigned long flags;
1236 1237
1237 if (!mwifiex_pcie_ok_to_access_hw(adapter)) 1238 if (!mwifiex_pcie_ok_to_access_hw(adapter))
1238 mwifiex_pm_wakeup_card(adapter); 1239 mwifiex_pm_wakeup_card(adapter);
@@ -1283,7 +1284,16 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
1283 "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n", 1284 "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
1284 card->rxbd_rdptr, wrptr, rx_len); 1285 card->rxbd_rdptr, wrptr, rx_len);
1285 skb_pull(skb_data, INTF_HEADER_LEN); 1286 skb_pull(skb_data, INTF_HEADER_LEN);
1286 mwifiex_handle_rx_packet(adapter, skb_data); 1287 if (adapter->rx_work_enabled) {
1288 spin_lock_irqsave(&adapter->rx_q_lock, flags);
1289 skb_queue_tail(&adapter->rx_data_q, skb_data);
1290 spin_unlock_irqrestore(&adapter->rx_q_lock,
1291 flags);
1292 adapter->data_received = true;
1293 atomic_inc(&adapter->rx_pending);
1294 } else {
1295 mwifiex_handle_rx_packet(adapter, skb_data);
1296 }
1287 } 1297 }
1288 1298
1289 skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); 1299 skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index bdab122db5cf..ea8fc587e90f 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -1039,6 +1039,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
1039 struct sk_buff *skb, u32 upld_typ) 1039 struct sk_buff *skb, u32 upld_typ)
1040{ 1040{
1041 u8 *cmd_buf; 1041 u8 *cmd_buf;
1042 unsigned long flags;
1042 __le16 *curr_ptr = (__le16 *)skb->data; 1043 __le16 *curr_ptr = (__le16 *)skb->data;
1043 u16 pkt_len = le16_to_cpu(*curr_ptr); 1044 u16 pkt_len = le16_to_cpu(*curr_ptr);
1044 1045
@@ -1048,7 +1049,15 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
1048 switch (upld_typ) { 1049 switch (upld_typ) {
1049 case MWIFIEX_TYPE_DATA: 1050 case MWIFIEX_TYPE_DATA:
1050 dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); 1051 dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
1051 mwifiex_handle_rx_packet(adapter, skb); 1052 if (adapter->rx_work_enabled) {
1053 spin_lock_irqsave(&adapter->rx_q_lock, flags);
1054 skb_queue_tail(&adapter->rx_data_q, skb);
1055 spin_unlock_irqrestore(&adapter->rx_q_lock, flags);
1056 adapter->data_received = true;
1057 atomic_inc(&adapter->rx_pending);
1058 } else {
1059 mwifiex_handle_rx_packet(adapter, skb);
1060 }
1052 break; 1061 break;
1053 1062
1054 case MWIFIEX_TYPE_CMD: 1063 case MWIFIEX_TYPE_CMD: