Merge tag 'iwlwifi-next-for-kalle-2016-03-02' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / drivers / net / wireless / ath / wil6210 / interrupt.c
1 /*
2  * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/interrupt.h>
18
19 #include "wil6210.h"
20 #include "trace.h"
21
22 /**
23  * Theory of operation:
24  *
25  * There is ISR pseudo-cause register,
26  * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE
27  * Its bits represents OR'ed bits from 3 real ISR registers:
28  * TX, RX, and MISC.
29  *
30  * Registers may be configured to either "write 1 to clear" or
31  * "clear on read" mode
32  *
33  * When handling interrupt, one have to mask/unmask interrupts for the
34  * real ISR registers, or hardware may malfunction.
35  *
36  */
37
38 #define WIL6210_IRQ_DISABLE     (0xFFFFFFFFUL)
39 #define WIL6210_IMC_RX          (BIT_DMA_EP_RX_ICR_RX_DONE | \
40                                  BIT_DMA_EP_RX_ICR_RX_HTRSH)
41 #define WIL6210_IMC_TX          (BIT_DMA_EP_TX_ICR_TX_DONE | \
42                                 BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
43 #define WIL6210_IMC_MISC        (ISR_MISC_FW_READY | \
44                                  ISR_MISC_MBOX_EVT | \
45                                  ISR_MISC_FW_ERROR)
46
47 #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
48                                         BIT_DMA_PSEUDO_CAUSE_TX | \
49                                         BIT_DMA_PSEUDO_CAUSE_MISC))
50
51 #if defined(CONFIG_WIL6210_ISR_COR)
52 /* configure to Clear-On-Read mode */
53 #define WIL_ICR_ICC_VALUE       (0xFFFFFFFFUL)
54
55 static inline void wil_icr_clear(u32 x, void __iomem *addr)
56 {
57 }
58 #else /* defined(CONFIG_WIL6210_ISR_COR) */
59 /* configure to Write-1-to-Clear mode */
60 #define WIL_ICR_ICC_VALUE       (0UL)
61
62 static inline void wil_icr_clear(u32 x, void __iomem *addr)
63 {
64         writel(x, addr);
65 }
66 #endif /* defined(CONFIG_WIL6210_ISR_COR) */
67
68 static inline u32 wil_ioread32_and_clear(void __iomem *addr)
69 {
70         u32 x = readl(addr);
71
72         wil_icr_clear(x, addr);
73
74         return x;
75 }
76
77 static void wil6210_mask_irq_tx(struct wil6210_priv *wil)
78 {
79         wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMS),
80               WIL6210_IRQ_DISABLE);
81 }
82
83 static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
84 {
85         wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMS),
86               WIL6210_IRQ_DISABLE);
87 }
88
89 static void wil6210_mask_irq_misc(struct wil6210_priv *wil)
90 {
91         wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS),
92               WIL6210_IRQ_DISABLE);
93 }
94
95 static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
96 {
97         wil_dbg_irq(wil, "%s()\n", __func__);
98
99         wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_DISABLE);
100
101         clear_bit(wil_status_irqen, wil->status);
102 }
103
104 void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
105 {
106         wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMC),
107               WIL6210_IMC_TX);
108 }
109
110 void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
111 {
112         wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
113               WIL6210_IMC_RX);
114 }
115
116 static void wil6210_unmask_irq_misc(struct wil6210_priv *wil)
117 {
118         wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC),
119               WIL6210_IMC_MISC);
120 }
121
122 static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
123 {
124         wil_dbg_irq(wil, "%s()\n", __func__);
125
126         set_bit(wil_status_irqen, wil->status);
127
128         wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_PSEUDO_MASK);
129 }
130
131 void wil_mask_irq(struct wil6210_priv *wil)
132 {
133         wil_dbg_irq(wil, "%s()\n", __func__);
134
135         wil6210_mask_irq_tx(wil);
136         wil6210_mask_irq_rx(wil);
137         wil6210_mask_irq_misc(wil);
138         wil6210_mask_irq_pseudo(wil);
139 }
140
141 void wil_unmask_irq(struct wil6210_priv *wil)
142 {
143         wil_dbg_irq(wil, "%s()\n", __func__);
144
145         wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC),
146               WIL_ICR_ICC_VALUE);
147         wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC),
148               WIL_ICR_ICC_VALUE);
149         wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC),
150               WIL_ICR_ICC_VALUE);
151
152         wil6210_unmask_irq_pseudo(wil);
153         wil6210_unmask_irq_tx(wil);
154         wil6210_unmask_irq_rx(wil);
155         wil6210_unmask_irq_misc(wil);
156 }
157
158 void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
159 {
160         wil_dbg_irq(wil, "%s()\n", __func__);
161
162         /* disable interrupt moderation for monitor
163          * to get better timestamp precision
164          */
165         if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
166                 return;
167
168         /* Disable and clear tx counter before (re)configuration */
169         wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR);
170         wil_w(wil, RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration);
171         wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n",
172                  wil->tx_max_burst_duration);
173         /* Configure TX max burst duration timer to use usec units */
174         wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL,
175               BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL);
176
177         /* Disable and clear tx idle counter before (re)configuration */
178         wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR);
179         wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout);
180         wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n",
181                  wil->tx_interframe_timeout);
182         /* Configure TX max burst duration timer to use usec units */
183         wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN |
184               BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL);
185
186         /* Disable and clear rx counter before (re)configuration */
187         wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR);
188         wil_w(wil, RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration);
189         wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n",
190                  wil->rx_max_burst_duration);
191         /* Configure TX max burst duration timer to use usec units */
192         wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL,
193               BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL);
194
195         /* Disable and clear rx idle counter before (re)configuration */
196         wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR);
197         wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout);
198         wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n",
199                  wil->rx_interframe_timeout);
200         /* Configure TX max burst duration timer to use usec units */
201         wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN |
202               BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL);
203 }
204
205 static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
206 {
207         struct wil6210_priv *wil = cookie;
208         u32 isr = wil_ioread32_and_clear(wil->csr +
209                                          HOSTADDR(RGF_DMA_EP_RX_ICR) +
210                                          offsetof(struct RGF_ICR, ICR));
211         bool need_unmask = true;
212
213         trace_wil6210_irq_rx(isr);
214         wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
215
216         if (unlikely(!isr)) {
217                 wil_err(wil, "spurious IRQ: RX\n");
218                 return IRQ_NONE;
219         }
220
221         wil6210_mask_irq_rx(wil);
222
223         /* RX_DONE and RX_HTRSH interrupts are the same if interrupt
224          * moderation is not used. Interrupt moderation may cause RX
225          * buffer overflow while RX_DONE is delayed. The required
226          * action is always the same - should empty the accumulated
227          * packets from the RX ring.
228          */
229         if (likely(isr & (BIT_DMA_EP_RX_ICR_RX_DONE |
230                           BIT_DMA_EP_RX_ICR_RX_HTRSH))) {
231                 wil_dbg_irq(wil, "RX done\n");
232
233                 if (unlikely(isr & BIT_DMA_EP_RX_ICR_RX_HTRSH))
234                         wil_err_ratelimited(wil,
235                                             "Received \"Rx buffer is in risk of overflow\" interrupt\n");
236
237                 isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE |
238                          BIT_DMA_EP_RX_ICR_RX_HTRSH);
239                 if (likely(test_bit(wil_status_fwready, wil->status))) {
240                         if (likely(test_bit(wil_status_napi_en, wil->status))) {
241                                 wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
242                                 need_unmask = false;
243                                 napi_schedule(&wil->napi_rx);
244                         } else {
245                                 wil_err(wil,
246                                         "Got Rx interrupt while stopping interface\n");
247                         }
248                 } else {
249                         wil_err(wil, "Got Rx interrupt while in reset\n");
250                 }
251         }
252
253         if (unlikely(isr))
254                 wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
255
256         /* Rx IRQ will be enabled when NAPI processing finished */
257
258         atomic_inc(&wil->isr_count_rx);
259
260         if (unlikely(need_unmask))
261                 wil6210_unmask_irq_rx(wil);
262
263         return IRQ_HANDLED;
264 }
265
266 static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
267 {
268         struct wil6210_priv *wil = cookie;
269         u32 isr = wil_ioread32_and_clear(wil->csr +
270                                          HOSTADDR(RGF_DMA_EP_TX_ICR) +
271                                          offsetof(struct RGF_ICR, ICR));
272         bool need_unmask = true;
273
274         trace_wil6210_irq_tx(isr);
275         wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
276
277         if (unlikely(!isr)) {
278                 wil_err(wil, "spurious IRQ: TX\n");
279                 return IRQ_NONE;
280         }
281
282         wil6210_mask_irq_tx(wil);
283
284         if (likely(isr & BIT_DMA_EP_TX_ICR_TX_DONE)) {
285                 wil_dbg_irq(wil, "TX done\n");
286                 isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
287                 /* clear also all VRING interrupts */
288                 isr &= ~(BIT(25) - 1UL);
289                 if (likely(test_bit(wil_status_fwready, wil->status))) {
290                         wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
291                         need_unmask = false;
292                         napi_schedule(&wil->napi_tx);
293                 } else {
294                         wil_err(wil, "Got Tx interrupt while in reset\n");
295                 }
296         }
297
298         if (unlikely(isr))
299                 wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
300
301         /* Tx IRQ will be enabled when NAPI processing finished */
302
303         atomic_inc(&wil->isr_count_tx);
304
305         if (unlikely(need_unmask))
306                 wil6210_unmask_irq_tx(wil);
307
308         return IRQ_HANDLED;
309 }
310
311 static void wil_notify_fw_error(struct wil6210_priv *wil)
312 {
313         struct device *dev = &wil_to_ndev(wil)->dev;
314         char *envp[3] = {
315                 [0] = "SOURCE=wil6210",
316                 [1] = "EVENT=FW_ERROR",
317                 [2] = NULL,
318         };
319         wil_err(wil, "Notify about firmware error\n");
320         kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
321 }
322
323 static void wil_cache_mbox_regs(struct wil6210_priv *wil)
324 {
325         /* make shadow copy of registers that should not change on run time */
326         wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
327                              sizeof(struct wil6210_mbox_ctl));
328         wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
329         wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
330 }
331
332 static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
333 {
334         struct wil6210_priv *wil = cookie;
335         u32 isr = wil_ioread32_and_clear(wil->csr +
336                                          HOSTADDR(RGF_DMA_EP_MISC_ICR) +
337                                          offsetof(struct RGF_ICR, ICR));
338
339         trace_wil6210_irq_misc(isr);
340         wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr);
341
342         if (!isr) {
343                 wil_err(wil, "spurious IRQ: MISC\n");
344                 return IRQ_NONE;
345         }
346
347         wil6210_mask_irq_misc(wil);
348
349         if (isr & ISR_MISC_FW_ERROR) {
350                 u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE);
351                 u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE);
352
353                 wil_err(wil,
354                         "Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n",
355                         fw_assert_code, ucode_assert_code);
356                 clear_bit(wil_status_fwready, wil->status);
357                 /*
358                  * do not clear @isr here - we do 2-nd part in thread
359                  * there, user space get notified, and it should be done
360                  * in non-atomic context
361                  */
362         }
363
364         if (isr & ISR_MISC_FW_READY) {
365                 wil_dbg_irq(wil, "IRQ: FW ready\n");
366                 wil_cache_mbox_regs(wil);
367                 set_bit(wil_status_mbox_ready, wil->status);
368                 /**
369                  * Actual FW ready indicated by the
370                  * WMI_FW_READY_EVENTID
371                  */
372                 isr &= ~ISR_MISC_FW_READY;
373         }
374
375         wil->isr_misc = isr;
376
377         if (isr) {
378                 return IRQ_WAKE_THREAD;
379         } else {
380                 wil6210_unmask_irq_misc(wil);
381                 return IRQ_HANDLED;
382         }
383 }
384
385 static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
386 {
387         struct wil6210_priv *wil = cookie;
388         u32 isr = wil->isr_misc;
389
390         trace_wil6210_irq_misc_thread(isr);
391         wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
392
393         if (isr & ISR_MISC_FW_ERROR) {
394                 wil_fw_core_dump(wil);
395                 wil_notify_fw_error(wil);
396                 isr &= ~ISR_MISC_FW_ERROR;
397                 if (wil->platform_ops.notify_crash) {
398                         wil_err(wil, "notify platform driver about FW crash");
399                         wil->platform_ops.notify_crash(wil->platform_handle);
400                 } else {
401                         wil_fw_error_recovery(wil);
402                 }
403         }
404         if (isr & ISR_MISC_MBOX_EVT) {
405                 wil_dbg_irq(wil, "MBOX event\n");
406                 wmi_recv_cmd(wil);
407                 isr &= ~ISR_MISC_MBOX_EVT;
408         }
409
410         if (isr)
411                 wil_dbg_irq(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
412
413         wil->isr_misc = 0;
414
415         wil6210_unmask_irq_misc(wil);
416
417         return IRQ_HANDLED;
418 }
419
420 /**
421  * thread IRQ handler
422  */
423 static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
424 {
425         struct wil6210_priv *wil = cookie;
426
427         wil_dbg_irq(wil, "Thread IRQ\n");
428         /* Discover real IRQ cause */
429         if (wil->isr_misc)
430                 wil6210_irq_misc_thread(irq, cookie);
431
432         wil6210_unmask_irq_pseudo(wil);
433
434         return IRQ_HANDLED;
435 }
436
437 /* DEBUG
438  * There is subtle bug in hardware that causes IRQ to raise when it should be
439  * masked. It is quite rare and hard to debug.
440  *
441  * Catch irq issue if it happens and print all I can.
442  */
443 static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
444 {
445         if (!test_bit(wil_status_irqen, wil->status)) {
446                 u32 icm_rx = wil_ioread32_and_clear(wil->csr +
447                                 HOSTADDR(RGF_DMA_EP_RX_ICR) +
448                                 offsetof(struct RGF_ICR, ICM));
449                 u32 icr_rx = wil_ioread32_and_clear(wil->csr +
450                                 HOSTADDR(RGF_DMA_EP_RX_ICR) +
451                                 offsetof(struct RGF_ICR, ICR));
452                 u32 imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR +
453                                    offsetof(struct RGF_ICR, IMV));
454                 u32 icm_tx = wil_ioread32_and_clear(wil->csr +
455                                 HOSTADDR(RGF_DMA_EP_TX_ICR) +
456                                 offsetof(struct RGF_ICR, ICM));
457                 u32 icr_tx = wil_ioread32_and_clear(wil->csr +
458                                 HOSTADDR(RGF_DMA_EP_TX_ICR) +
459                                 offsetof(struct RGF_ICR, ICR));
460                 u32 imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR +
461                                    offsetof(struct RGF_ICR, IMV));
462                 u32 icm_misc = wil_ioread32_and_clear(wil->csr +
463                                 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
464                                 offsetof(struct RGF_ICR, ICM));
465                 u32 icr_misc = wil_ioread32_and_clear(wil->csr +
466                                 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
467                                 offsetof(struct RGF_ICR, ICR));
468                 u32 imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR +
469                                      offsetof(struct RGF_ICR, IMV));
470                 wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n"
471                                 "Rx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
472                                 "Tx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
473                                 "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n",
474                                 pseudo_cause,
475                                 icm_rx, icr_rx, imv_rx,
476                                 icm_tx, icr_tx, imv_tx,
477                                 icm_misc, icr_misc, imv_misc);
478
479                 return -EINVAL;
480         }
481
482         return 0;
483 }
484
485 static irqreturn_t wil6210_hardirq(int irq, void *cookie)
486 {
487         irqreturn_t rc = IRQ_HANDLED;
488         struct wil6210_priv *wil = cookie;
489         u32 pseudo_cause = wil_r(wil, RGF_DMA_PSEUDO_CAUSE);
490
491         /**
492          * pseudo_cause is Clear-On-Read, no need to ACK
493          */
494         if (unlikely((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)))
495                 return IRQ_NONE;
496
497         /* FIXME: IRQ mask debug */
498         if (unlikely(wil6210_debug_irq_mask(wil, pseudo_cause)))
499                 return IRQ_NONE;
500
501         trace_wil6210_irq_pseudo(pseudo_cause);
502         wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause);
503
504         wil6210_mask_irq_pseudo(wil);
505
506         /* Discover real IRQ cause
507          * There are 2 possible phases for every IRQ:
508          * - hard IRQ handler called right here
509          * - threaded handler called later
510          *
511          * Hard IRQ handler reads and clears ISR.
512          *
513          * If threaded handler requested, hard IRQ handler
514          * returns IRQ_WAKE_THREAD and saves ISR register value
515          * for the threaded handler use.
516          *
517          * voting for wake thread - need at least 1 vote
518          */
519         if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) &&
520             (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
521                 rc = IRQ_WAKE_THREAD;
522
523         if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
524             (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
525                 rc = IRQ_WAKE_THREAD;
526
527         if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) &&
528             (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD))
529                 rc = IRQ_WAKE_THREAD;
530
531         /* if thread is requested, it will unmask IRQ */
532         if (rc != IRQ_WAKE_THREAD)
533                 wil6210_unmask_irq_pseudo(wil);
534
535         return rc;
536 }
537
538 /* can't use wil_ioread32_and_clear because ICC value is not set yet */
539 static inline void wil_clear32(void __iomem *addr)
540 {
541         u32 x = readl(addr);
542
543         writel(x, addr);
544 }
545
546 void wil6210_clear_irq(struct wil6210_priv *wil)
547 {
548         wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
549                     offsetof(struct RGF_ICR, ICR));
550         wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) +
551                     offsetof(struct RGF_ICR, ICR));
552         wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
553                     offsetof(struct RGF_ICR, ICR));
554         wmb(); /* make sure write completed */
555 }
556
557 int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi)
558 {
559         int rc;
560
561         wil_dbg_misc(wil, "%s(%s)\n", __func__, use_msi ? "MSI" : "INTx");
562
563         rc = request_threaded_irq(irq, wil6210_hardirq,
564                                   wil6210_thread_irq,
565                                   use_msi ? 0 : IRQF_SHARED,
566                                   WIL_NAME, wil);
567         return rc;
568 }
569
570 void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
571 {
572         wil_dbg_misc(wil, "%s()\n", __func__);
573
574         wil_mask_irq(wil);
575         free_irq(irq, wil);
576 }