332-ath10k-implement-NAPI-support.patch 19 KB

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