ath9k: fix warning in client mode (GH#195)
[oweals/openwrt.git] / package / kernel / mac80211 / patches / 332-ath10k-implement-NAPI-support.patch
1 From: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
2 Date: Thu, 21 Jul 2016 11:50:00 +0530
3 Subject: [PATCH] ath10k: implement NAPI support
4
5 Add NAPI support for rx and tx completion. NAPI poll is scheduled
6 from interrupt handler. The design is as below
7
8  - on interrupt
9      - schedule napi and mask interrupts
10  - on poll
11    - process all pipes (no actual Tx/Rx)
12    - process Rx within budget
13    - if quota exceeds budget reschedule napi poll by returning budget
14    - process Tx completions and update budget if necessary
15    - process Tx fetch indications (pull-push)
16    - push any other pending Tx (if possible)
17    - before resched or napi completion replenish htt rx ring buffer
18    - if work done < budget, complete napi poll and unmask interrupts
19
20 This change also get rid of two tasklets (intr_tq and txrx_compl_task).
21
22 Measured peak throughput with NAPI on IPQ4019 platform in controlled
23 environment. No noticeable reduction in throughput is seen and also
24 observed improvements in CPU usage. Approx. 15% CPU usage got reduced
25 in UDP uplink case.
26
27 DL: AP DUT Tx
28 UL: AP DUT Rx
29
30 IPQ4019 (avg. cpu usage %)
31 ========
32                 TOT              +NAPI
33               ===========      =============
34 TCP DL       644 Mbps (42%)    645 Mbps (36%)
35 TCP UL       673 Mbps (30%)    675 Mbps (26%)
36 UDP DL       682 Mbps (49%)    680 Mbps (49%)
37 UDP UL       720 Mbps (28%)    717 Mbps (11%)
38
39 Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
40 ---
41
42 --- a/drivers/net/wireless/ath/ath10k/ahb.c
43 +++ b/drivers/net/wireless/ath/ath10k/ahb.c
44 @@ -462,13 +462,13 @@ static void ath10k_ahb_halt_chip(struct
45  static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg)
46  {
47         struct ath10k *ar = arg;
48 -       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
49  
50         if (!ath10k_pci_irq_pending(ar))
51                 return IRQ_NONE;
52  
53         ath10k_pci_disable_and_clear_legacy_irq(ar);
54 -       tasklet_schedule(&ar_pci->intr_tq);
55 +       ath10k_pci_irq_msi_fw_mask(ar);
56 +       napi_schedule(&ar->napi);
57  
58         return IRQ_HANDLED;
59  }
60 @@ -831,7 +831,7 @@ static int ath10k_ahb_probe(struct platf
61                 goto err_resource_deinit;
62         }
63  
64 -       ath10k_pci_init_irq_tasklets(ar);
65 +       ath10k_pci_init_napi(ar);
66  
67         ret = ath10k_ahb_request_irq_legacy(ar);
68         if (ret)
69 --- a/drivers/net/wireless/ath/ath10k/core.c
70 +++ b/drivers/net/wireless/ath/ath10k/core.c
71 @@ -2226,6 +2226,8 @@ struct ath10k *ath10k_core_create(size_t
72         INIT_WORK(&ar->register_work, ath10k_core_register_work);
73         INIT_WORK(&ar->restart_work, ath10k_core_restart);
74  
75 +       init_dummy_netdev(&ar->napi_dev);
76 +
77         ret = ath10k_debug_create(ar);
78         if (ret)
79                 goto err_free_aux_wq;
80 --- a/drivers/net/wireless/ath/ath10k/core.h
81 +++ b/drivers/net/wireless/ath/ath10k/core.h
82 @@ -65,6 +65,10 @@
83  #define ATH10K_KEEPALIVE_MAX_IDLE 3895
84  #define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900
85  
86 +/* NAPI poll budget */
87 +#define ATH10K_NAPI_BUDGET      64
88 +#define ATH10K_NAPI_QUOTA_LIMIT 60
89 +
90  struct ath10k;
91  
92  enum ath10k_bus {
93 @@ -933,6 +937,10 @@ struct ath10k {
94         struct ath10k_thermal thermal;
95         struct ath10k_wow wow;
96  
97 +       /* NAPI */
98 +       struct net_device napi_dev;
99 +       struct napi_struct napi;
100 +
101         /* must be last */
102         u8 drv_priv[0] __aligned(sizeof(void *));
103  };
104 --- a/drivers/net/wireless/ath/ath10k/htt.h
105 +++ b/drivers/net/wireless/ath/ath10k/htt.h
106 @@ -1666,7 +1666,6 @@ struct ath10k_htt {
107  
108         /* This is used to group tx/rx completions separately and process them
109          * in batches to reduce cache stalls */
110 -       struct tasklet_struct txrx_compl_task;
111         struct sk_buff_head rx_compl_q;
112         struct sk_buff_head rx_in_ord_compl_q;
113         struct sk_buff_head tx_fetch_ind_q;
114 @@ -1799,5 +1798,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt
115                   struct sk_buff *msdu);
116  void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
117                                              struct sk_buff *skb);
118 +int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget);
119  
120  #endif
121 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c
122 +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
123 @@ -34,7 +34,6 @@
124  #define HTT_RX_RING_REFILL_RESCHED_MS 5
125  
126  static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
127 -static void ath10k_htt_txrx_compl_task(unsigned long ptr);
128  
129  static struct sk_buff *
130  ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u32 paddr)
131 @@ -226,7 +225,6 @@ int ath10k_htt_rx_ring_refill(struct ath
132  void ath10k_htt_rx_free(struct ath10k_htt *htt)
133  {
134         del_timer_sync(&htt->rx_ring.refill_retry_timer);
135 -       tasklet_kill(&htt->txrx_compl_task);
136  
137         skb_queue_purge(&htt->rx_compl_q);
138         skb_queue_purge(&htt->rx_in_ord_compl_q);
139 @@ -520,9 +518,6 @@ int ath10k_htt_rx_alloc(struct ath10k_ht
140         skb_queue_head_init(&htt->tx_fetch_ind_q);
141         atomic_set(&htt->num_mpdus_ready, 0);
142  
143 -       tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
144 -                    (unsigned long)htt);
145 -
146         ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
147                    htt->rx_ring.size, htt->rx_ring.fill_level);
148         return 0;
149 @@ -958,7 +953,7 @@ static void ath10k_process_rx(struct ath
150         trace_ath10k_rx_hdr(ar, skb->data, skb->len);
151         trace_ath10k_rx_payload(ar, skb->data, skb->len);
152  
153 -       ieee80211_rx(ar->hw, skb);
154 +       ieee80211_rx_napi(ar->hw, NULL, skb, &ar->napi);
155  }
156  
157  static int ath10k_htt_rx_nwifi_hdrlen(struct ath10k *ar,
158 @@ -1527,7 +1522,7 @@ static int ath10k_htt_rx_handle_amsdu(st
159         struct ath10k *ar = htt->ar;
160         struct ieee80211_rx_status *rx_status = &htt->rx_status;
161         struct sk_buff_head amsdu;
162 -       int ret;
163 +       int ret, num_msdus;
164  
165         __skb_queue_head_init(&amsdu);
166  
167 @@ -1549,13 +1544,14 @@ static int ath10k_htt_rx_handle_amsdu(st
168                 return ret;
169         }
170  
171 +       num_msdus = skb_queue_len(&amsdu);
172         ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
173         ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
174         ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
175         ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
176         ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
177  
178 -       return 0;
179 +       return num_msdus;
180  }
181  
182  static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
183 @@ -1579,15 +1575,6 @@ static void ath10k_htt_rx_proc_rx_ind(st
184                 mpdu_count += mpdu_ranges[i].mpdu_count;
185  
186         atomic_add(mpdu_count, &htt->num_mpdus_ready);
187 -
188 -       tasklet_schedule(&htt->txrx_compl_task);
189 -}
190 -
191 -static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt)
192 -{
193 -       atomic_inc(&htt->num_mpdus_ready);
194 -
195 -       tasklet_schedule(&htt->txrx_compl_task);
196  }
197  
198  static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
199 @@ -1772,14 +1759,15 @@ static void ath10k_htt_rx_h_rx_offload_p
200                         RX_FLAG_MMIC_STRIPPED;
201  }
202  
203 -static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
204 -                                      struct sk_buff_head *list)
205 +static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
206 +                                     struct sk_buff_head *list)
207  {
208         struct ath10k_htt *htt = &ar->htt;
209         struct ieee80211_rx_status *status = &htt->rx_status;
210         struct htt_rx_offload_msdu *rx;
211         struct sk_buff *msdu;
212         size_t offset;
213 +       int num_msdu = 0;
214  
215         while ((msdu = __skb_dequeue(list))) {
216                 /* Offloaded frames don't have Rx descriptor. Instead they have
217 @@ -1819,10 +1807,12 @@ static void ath10k_htt_rx_h_rx_offload(s
218                 ath10k_htt_rx_h_rx_offload_prot(status, msdu);
219                 ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
220                 ath10k_process_rx(ar, status, msdu);
221 +               num_msdu++;
222         }
223 +       return num_msdu;
224  }
225  
226 -static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
227 +static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
228  {
229         struct ath10k_htt *htt = &ar->htt;
230         struct htt_resp *resp = (void *)skb->data;
231 @@ -1835,12 +1825,12 @@ static void ath10k_htt_rx_in_ord_ind(str
232         u8 tid;
233         bool offload;
234         bool frag;
235 -       int ret;
236 +       int ret, num_msdus = 0;
237  
238         lockdep_assert_held(&htt->rx_ring.lock);
239  
240         if (htt->rx_confused)
241 -               return;
242 +               return -EIO;
243  
244         skb_pull(skb, sizeof(resp->hdr));
245         skb_pull(skb, sizeof(resp->rx_in_ord_ind));
246 @@ -1859,7 +1849,7 @@ static void ath10k_htt_rx_in_ord_ind(str
247  
248         if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs)) {
249                 ath10k_warn(ar, "dropping invalid in order rx indication\n");
250 -               return;
251 +               return -EINVAL;
252         }
253  
254         /* The event can deliver more than 1 A-MSDU. Each A-MSDU is later
255 @@ -1870,14 +1860,14 @@ static void ath10k_htt_rx_in_ord_ind(str
256         if (ret < 0) {
257                 ath10k_warn(ar, "failed to pop paddr list: %d\n", ret);
258                 htt->rx_confused = true;
259 -               return;
260 +               return -EIO;
261         }
262  
263         /* Offloaded frames are very different and need to be handled
264          * separately.
265          */
266         if (offload)
267 -               ath10k_htt_rx_h_rx_offload(ar, &list);
268 +               num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list);
269  
270         while (!skb_queue_empty(&list)) {
271                 __skb_queue_head_init(&amsdu);
272 @@ -1890,6 +1880,7 @@ static void ath10k_htt_rx_in_ord_ind(str
273                          * better to report something than nothing though. This
274                          * should still give an idea about rx rate to the user.
275                          */
276 +                       num_msdus += skb_queue_len(&amsdu);
277                         ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
278                         ath10k_htt_rx_h_filter(ar, &amsdu, status);
279                         ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
280 @@ -1902,9 +1893,10 @@ static void ath10k_htt_rx_in_ord_ind(str
281                         ath10k_warn(ar, "failed to extract amsdu: %d\n", ret);
282                         htt->rx_confused = true;
283                         __skb_queue_purge(&list);
284 -                       return;
285 +                       return -EIO;
286                 }
287         }
288 +       return num_msdus;
289  }
290  
291  static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar,
292 @@ -2267,7 +2259,6 @@ bool ath10k_htt_t2h_msg_handler(struct a
293         }
294         case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
295                 ath10k_htt_rx_tx_compl_ind(htt->ar, skb);
296 -               tasklet_schedule(&htt->txrx_compl_task);
297                 break;
298         case HTT_T2H_MSG_TYPE_SEC_IND: {
299                 struct ath10k *ar = htt->ar;
300 @@ -2284,7 +2275,7 @@ bool ath10k_htt_t2h_msg_handler(struct a
301         case HTT_T2H_MSG_TYPE_RX_FRAG_IND: {
302                 ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
303                                 skb->data, skb->len);
304 -               ath10k_htt_rx_frag_handler(htt);
305 +               atomic_inc(&htt->num_mpdus_ready);
306                 break;
307         }
308         case HTT_T2H_MSG_TYPE_TEST:
309 @@ -2322,8 +2313,7 @@ bool ath10k_htt_t2h_msg_handler(struct a
310                 break;
311         }
312         case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: {
313 -               skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
314 -               tasklet_schedule(&htt->txrx_compl_task);
315 +               __skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
316                 return false;
317         }
318         case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
319 @@ -2349,7 +2339,6 @@ bool ath10k_htt_t2h_msg_handler(struct a
320                         break;
321                 }
322                 skb_queue_tail(&htt->tx_fetch_ind_q, tx_fetch_ind);
323 -               tasklet_schedule(&htt->txrx_compl_task);
324                 break;
325         }
326         case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM:
327 @@ -2378,27 +2367,77 @@ void ath10k_htt_rx_pktlog_completion_han
328  }
329  EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
330  
331 -static void ath10k_htt_txrx_compl_task(unsigned long ptr)
332 +int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
333  {
334 -       struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
335 -       struct ath10k *ar = htt->ar;
336 +       struct ath10k_htt *htt = &ar->htt;
337         struct htt_tx_done tx_done = {};
338 -       struct sk_buff_head rx_ind_q;
339         struct sk_buff_head tx_ind_q;
340         struct sk_buff *skb;
341         unsigned long flags;
342 -       int num_mpdus;
343 +       int quota = 0, done, num_rx_msdus;
344 +       bool resched_napi = false;
345  
346 -       __skb_queue_head_init(&rx_ind_q);
347         __skb_queue_head_init(&tx_ind_q);
348  
349 -       spin_lock_irqsave(&htt->rx_in_ord_compl_q.lock, flags);
350 -       skb_queue_splice_init(&htt->rx_in_ord_compl_q, &rx_ind_q);
351 -       spin_unlock_irqrestore(&htt->rx_in_ord_compl_q.lock, flags);
352 +       /* Since in-ord-ind can deliver more than 1 A-MSDU in single event,
353 +        * process it first to utilize full available quota.
354 +        */
355 +       while (quota < budget) {
356 +               if (skb_queue_empty(&htt->rx_in_ord_compl_q))
357 +                       break;
358  
359 -       spin_lock_irqsave(&htt->tx_fetch_ind_q.lock, flags);
360 -       skb_queue_splice_init(&htt->tx_fetch_ind_q, &tx_ind_q);
361 -       spin_unlock_irqrestore(&htt->tx_fetch_ind_q.lock, flags);
362 +               skb = __skb_dequeue(&htt->rx_in_ord_compl_q);
363 +               if (!skb) {
364 +                       resched_napi = true;
365 +                       goto exit;
366 +               }
367 +
368 +               spin_lock_bh(&htt->rx_ring.lock);
369 +               num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb);
370 +               spin_unlock_bh(&htt->rx_ring.lock);
371 +               if (num_rx_msdus < 0) {
372 +                       resched_napi = true;
373 +                       goto exit;
374 +               }
375 +
376 +               dev_kfree_skb_any(skb);
377 +               if (num_rx_msdus > 0)
378 +                       quota += num_rx_msdus;
379 +
380 +               if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
381 +                   !skb_queue_empty(&htt->rx_in_ord_compl_q)) {
382 +                       resched_napi = true;
383 +                       goto exit;
384 +               }
385 +       }
386 +
387 +       while (quota < budget) {
388 +               /* no more data to receive */
389 +               if (!atomic_read(&htt->num_mpdus_ready))
390 +                       break;
391 +
392 +               num_rx_msdus = ath10k_htt_rx_handle_amsdu(htt);
393 +               if (num_rx_msdus < 0) {
394 +                       resched_napi = true;
395 +                       goto exit;
396 +               }
397 +
398 +               quota += num_rx_msdus;
399 +               atomic_dec(&htt->num_mpdus_ready);
400 +               if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
401 +                   atomic_read(&htt->num_mpdus_ready)) {
402 +                       resched_napi = true;
403 +                       goto exit;
404 +               }
405 +       }
406 +
407 +       /* From NAPI documentation:
408 +        *  The napi poll() function may also process TX completions, in which
409 +        *  case if it processes the entire TX ring then it should count that
410 +        *  work as the rest of the budget.
411 +        */
412 +       if ((quota < budget) && !kfifo_is_empty(&htt->txdone_fifo))
413 +               quota = budget;
414  
415         /* kfifo_get: called only within txrx_tasklet so it's neatly serialized.
416          * From kfifo_get() documentation:
417 @@ -2408,27 +2447,22 @@ static void ath10k_htt_txrx_compl_task(u
418         while (kfifo_get(&htt->txdone_fifo, &tx_done))
419                 ath10k_txrx_tx_unref(htt, &tx_done);
420  
421 +       spin_lock_irqsave(&htt->tx_fetch_ind_q.lock, flags);
422 +       skb_queue_splice_init(&htt->tx_fetch_ind_q, &tx_ind_q);
423 +       spin_unlock_irqrestore(&htt->tx_fetch_ind_q.lock, flags);
424 +
425         while ((skb = __skb_dequeue(&tx_ind_q))) {
426                 ath10k_htt_rx_tx_fetch_ind(ar, skb);
427                 dev_kfree_skb_any(skb);
428         }
429  
430 -       num_mpdus = atomic_read(&htt->num_mpdus_ready);
431 -
432 -       while (num_mpdus) {
433 -               if (ath10k_htt_rx_handle_amsdu(htt))
434 -                       break;
435 -
436 -               num_mpdus--;
437 -               atomic_dec(&htt->num_mpdus_ready);
438 -       }
439 -
440 -       while ((skb = __skb_dequeue(&rx_ind_q))) {
441 -               spin_lock_bh(&htt->rx_ring.lock);
442 -               ath10k_htt_rx_in_ord_ind(ar, skb);
443 -               spin_unlock_bh(&htt->rx_ring.lock);
444 -               dev_kfree_skb_any(skb);
445 -       }
446 -
447 +exit:
448         ath10k_htt_rx_msdu_buff_replenish(htt);
449 +       /* In case of rx failure or more data to read, report budget
450 +        * to reschedule NAPI poll
451 +        */
452 +       done = resched_napi ? budget : quota;
453 +
454 +       return done;
455  }
456 +EXPORT_SYMBOL(ath10k_htt_txrx_compl_task);
457 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c
458 +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
459 @@ -388,8 +388,6 @@ void ath10k_htt_tx_free(struct ath10k_ht
460  {
461         int size;
462  
463 -       tasklet_kill(&htt->txrx_compl_task);
464 -
465         idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
466         idr_destroy(&htt->pending_tx);
467  
468 --- a/drivers/net/wireless/ath/ath10k/pci.c
469 +++ b/drivers/net/wireless/ath/ath10k/pci.c
470 @@ -1502,12 +1502,10 @@ void ath10k_pci_hif_send_complete_check(
471         ath10k_ce_per_engine_service(ar, pipe);
472  }
473  
474 -void ath10k_pci_kill_tasklet(struct ath10k *ar)
475 +static void ath10k_pci_rx_retry_sync(struct ath10k *ar)
476  {
477         struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
478  
479 -       tasklet_kill(&ar_pci->intr_tq);
480 -
481         del_timer_sync(&ar_pci->rx_post_retry);
482  }
483  
484 @@ -1566,7 +1564,7 @@ void ath10k_pci_hif_get_default_pipe(str
485                                                  ul_pipe, dl_pipe);
486  }
487  
488 -static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
489 +void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
490  {
491         u32 val;
492  
493 @@ -1747,7 +1745,7 @@ void ath10k_pci_ce_deinit(struct ath10k
494  
495  void ath10k_pci_flush(struct ath10k *ar)
496  {
497 -       ath10k_pci_kill_tasklet(ar);
498 +       ath10k_pci_rx_retry_sync(ar);
499         ath10k_pci_buffer_cleanup(ar);
500  }
501  
502 @@ -2754,35 +2752,53 @@ static irqreturn_t ath10k_pci_interrupt_
503                 return IRQ_NONE;
504         }
505  
506 -       if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) {
507 -               if (!ath10k_pci_irq_pending(ar))
508 -                       return IRQ_NONE;
509 -
510 -               ath10k_pci_disable_and_clear_legacy_irq(ar);
511 -       }
512 +       if ((ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) &&
513 +           !ath10k_pci_irq_pending(ar))
514 +               return IRQ_NONE;
515  
516 -       tasklet_schedule(&ar_pci->intr_tq);
517 +       ath10k_pci_disable_and_clear_legacy_irq(ar);
518 +       ath10k_pci_irq_msi_fw_mask(ar);
519 +       napi_schedule(&ar->napi);
520  
521         return IRQ_HANDLED;
522  }
523  
524 -static void ath10k_pci_tasklet(unsigned long data)
525 +static int ath10k_pci_napi_poll(struct napi_struct *ctx, int budget)
526  {
527 -       struct ath10k *ar = (struct ath10k *)data;
528 -       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
529 +       struct ath10k *ar = container_of(ctx, struct ath10k, napi);
530 +       int done = 0;
531  
532         if (ath10k_pci_has_fw_crashed(ar)) {
533 -               ath10k_pci_irq_disable(ar);
534                 ath10k_pci_fw_crashed_clear(ar);
535                 ath10k_pci_fw_crashed_dump(ar);
536 -               return;
537 +               napi_complete(ctx);
538 +               return done;
539         }
540  
541         ath10k_ce_per_engine_service_any(ar);
542  
543 -       /* Re-enable legacy irq that was disabled in the irq handler */
544 -       if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY)
545 +       done = ath10k_htt_txrx_compl_task(ar, budget);
546 +
547 +       if (done < budget) {
548 +               napi_complete(ctx);
549 +               /* In case of MSI, it is possible that interrupts are received
550 +                * while NAPI poll is inprogress. So pending interrupts that are
551 +                * received after processing all copy engine pipes by NAPI poll
552 +                * will not be handled again. This is causing failure to
553 +                * complete boot sequence in x86 platform. So before enabling
554 +                * interrupts safer to check for pending interrupts for
555 +                * immediate servicing.
556 +                */
557 +               if (CE_INTERRUPT_SUMMARY(ar)) {
558 +                       napi_reschedule(&ar->napi);
559 +                       goto out;
560 +               }
561                 ath10k_pci_enable_legacy_irq(ar);
562 +               ath10k_pci_irq_msi_fw_unmask(ar);
563 +       }
564 +
565 +out:
566 +       return done;
567  }
568  
569  static int ath10k_pci_request_irq_msi(struct ath10k *ar)
570 @@ -2840,11 +2856,11 @@ static void ath10k_pci_free_irq(struct a
571         free_irq(ar_pci->pdev->irq, ar);
572  }
573  
574 -void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
575 +void ath10k_pci_init_napi(struct ath10k *ar)
576  {
577 -       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
578 -
579 -       tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
580 +       netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_pci_napi_poll,
581 +                      ATH10K_NAPI_BUDGET);
582 +       napi_enable(&ar->napi);
583  }
584  
585  static int ath10k_pci_init_irq(struct ath10k *ar)
586 @@ -2852,7 +2868,7 @@ static int ath10k_pci_init_irq(struct at
587         struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
588         int ret;
589  
590 -       ath10k_pci_init_irq_tasklets(ar);
591 +       ath10k_pci_init_napi(ar);
592  
593         if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO)
594                 ath10k_info(ar, "limiting irq mode to: %d\n",
595 @@ -3113,7 +3129,8 @@ int ath10k_pci_setup_resource(struct ath
596  
597  void ath10k_pci_release_resource(struct ath10k *ar)
598  {
599 -       ath10k_pci_kill_tasklet(ar);
600 +       ath10k_pci_rx_retry_sync(ar);
601 +       netif_napi_del(&ar->napi);
602         ath10k_pci_ce_deinit(ar);
603         ath10k_pci_free_pipes(ar);
604  }
605 @@ -3274,7 +3291,7 @@ static int ath10k_pci_probe(struct pci_d
606  
607  err_free_irq:
608         ath10k_pci_free_irq(ar);
609 -       ath10k_pci_kill_tasklet(ar);
610 +       ath10k_pci_rx_retry_sync(ar);
611  
612  err_deinit_irq:
613         ath10k_pci_deinit_irq(ar);
614 --- a/drivers/net/wireless/ath/ath10k/pci.h
615 +++ b/drivers/net/wireless/ath/ath10k/pci.h
616 @@ -177,8 +177,6 @@ struct ath10k_pci {
617         /* Operating interrupt mode */
618         enum ath10k_pci_irq_mode oper_irq_mode;
619  
620 -       struct tasklet_struct intr_tq;
621 -
622         struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
623  
624         /* Copy Engine used for Diagnostic Accesses */
625 @@ -294,8 +292,7 @@ void ath10k_pci_free_pipes(struct ath10k
626  void ath10k_pci_free_pipes(struct ath10k *ar);
627  void ath10k_pci_rx_replenish_retry(unsigned long ptr);
628  void ath10k_pci_ce_deinit(struct ath10k *ar);
629 -void ath10k_pci_init_irq_tasklets(struct ath10k *ar);
630 -void ath10k_pci_kill_tasklet(struct ath10k *ar);
631 +void ath10k_pci_init_napi(struct ath10k *ar);
632  int ath10k_pci_init_pipes(struct ath10k *ar);
633  int ath10k_pci_init_config(struct ath10k *ar);
634  void ath10k_pci_rx_post(struct ath10k *ar);
635 @@ -303,6 +300,7 @@ void ath10k_pci_flush(struct ath10k *ar)
636  void ath10k_pci_enable_legacy_irq(struct ath10k *ar);
637  bool ath10k_pci_irq_pending(struct ath10k *ar);
638  void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar);
639 +void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar);
640  int ath10k_pci_wait_for_target_init(struct ath10k *ar);
641  int ath10k_pci_setup_resource(struct ath10k *ar);
642  void ath10k_pci_release_resource(struct ath10k *ar);