]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/ath/wil6210/interrupt.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide
[karo-tx-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                 wil_fw_error_recovery(wil);
398         }
399
400         if (isr & ISR_MISC_MBOX_EVT) {
401                 wil_dbg_irq(wil, "MBOX event\n");
402                 wmi_recv_cmd(wil);
403                 isr &= ~ISR_MISC_MBOX_EVT;
404         }
405
406         if (isr)
407                 wil_dbg_irq(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
408
409         wil->isr_misc = 0;
410
411         wil6210_unmask_irq_misc(wil);
412
413         return IRQ_HANDLED;
414 }
415
416 /**
417  * thread IRQ handler
418  */
419 static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
420 {
421         struct wil6210_priv *wil = cookie;
422
423         wil_dbg_irq(wil, "Thread IRQ\n");
424         /* Discover real IRQ cause */
425         if (wil->isr_misc)
426                 wil6210_irq_misc_thread(irq, cookie);
427
428         wil6210_unmask_irq_pseudo(wil);
429
430         return IRQ_HANDLED;
431 }
432
433 /* DEBUG
434  * There is subtle bug in hardware that causes IRQ to raise when it should be
435  * masked. It is quite rare and hard to debug.
436  *
437  * Catch irq issue if it happens and print all I can.
438  */
439 static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
440 {
441         if (!test_bit(wil_status_irqen, wil->status)) {
442                 u32 icm_rx = wil_ioread32_and_clear(wil->csr +
443                                 HOSTADDR(RGF_DMA_EP_RX_ICR) +
444                                 offsetof(struct RGF_ICR, ICM));
445                 u32 icr_rx = wil_ioread32_and_clear(wil->csr +
446                                 HOSTADDR(RGF_DMA_EP_RX_ICR) +
447                                 offsetof(struct RGF_ICR, ICR));
448                 u32 imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR +
449                                    offsetof(struct RGF_ICR, IMV));
450                 u32 icm_tx = wil_ioread32_and_clear(wil->csr +
451                                 HOSTADDR(RGF_DMA_EP_TX_ICR) +
452                                 offsetof(struct RGF_ICR, ICM));
453                 u32 icr_tx = wil_ioread32_and_clear(wil->csr +
454                                 HOSTADDR(RGF_DMA_EP_TX_ICR) +
455                                 offsetof(struct RGF_ICR, ICR));
456                 u32 imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR +
457                                    offsetof(struct RGF_ICR, IMV));
458                 u32 icm_misc = wil_ioread32_and_clear(wil->csr +
459                                 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
460                                 offsetof(struct RGF_ICR, ICM));
461                 u32 icr_misc = wil_ioread32_and_clear(wil->csr +
462                                 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
463                                 offsetof(struct RGF_ICR, ICR));
464                 u32 imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR +
465                                      offsetof(struct RGF_ICR, IMV));
466                 wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n"
467                                 "Rx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
468                                 "Tx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
469                                 "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n",
470                                 pseudo_cause,
471                                 icm_rx, icr_rx, imv_rx,
472                                 icm_tx, icr_tx, imv_tx,
473                                 icm_misc, icr_misc, imv_misc);
474
475                 return -EINVAL;
476         }
477
478         return 0;
479 }
480
481 static irqreturn_t wil6210_hardirq(int irq, void *cookie)
482 {
483         irqreturn_t rc = IRQ_HANDLED;
484         struct wil6210_priv *wil = cookie;
485         u32 pseudo_cause = wil_r(wil, RGF_DMA_PSEUDO_CAUSE);
486
487         /**
488          * pseudo_cause is Clear-On-Read, no need to ACK
489          */
490         if (unlikely((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)))
491                 return IRQ_NONE;
492
493         /* FIXME: IRQ mask debug */
494         if (unlikely(wil6210_debug_irq_mask(wil, pseudo_cause)))
495                 return IRQ_NONE;
496
497         trace_wil6210_irq_pseudo(pseudo_cause);
498         wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause);
499
500         wil6210_mask_irq_pseudo(wil);
501
502         /* Discover real IRQ cause
503          * There are 2 possible phases for every IRQ:
504          * - hard IRQ handler called right here
505          * - threaded handler called later
506          *
507          * Hard IRQ handler reads and clears ISR.
508          *
509          * If threaded handler requested, hard IRQ handler
510          * returns IRQ_WAKE_THREAD and saves ISR register value
511          * for the threaded handler use.
512          *
513          * voting for wake thread - need at least 1 vote
514          */
515         if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) &&
516             (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
517                 rc = IRQ_WAKE_THREAD;
518
519         if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
520             (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
521                 rc = IRQ_WAKE_THREAD;
522
523         if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) &&
524             (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD))
525                 rc = IRQ_WAKE_THREAD;
526
527         /* if thread is requested, it will unmask IRQ */
528         if (rc != IRQ_WAKE_THREAD)
529                 wil6210_unmask_irq_pseudo(wil);
530
531         return rc;
532 }
533
534 /* can't use wil_ioread32_and_clear because ICC value is not set yet */
535 static inline void wil_clear32(void __iomem *addr)
536 {
537         u32 x = readl(addr);
538
539         writel(x, addr);
540 }
541
542 void wil6210_clear_irq(struct wil6210_priv *wil)
543 {
544         wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
545                     offsetof(struct RGF_ICR, ICR));
546         wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) +
547                     offsetof(struct RGF_ICR, ICR));
548         wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
549                     offsetof(struct RGF_ICR, ICR));
550         wmb(); /* make sure write completed */
551 }
552
553 int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi)
554 {
555         int rc;
556
557         wil_dbg_misc(wil, "%s(%s)\n", __func__, use_msi ? "MSI" : "INTx");
558
559         rc = request_threaded_irq(irq, wil6210_hardirq,
560                                   wil6210_thread_irq,
561                                   use_msi ? 0 : IRQF_SHARED,
562                                   WIL_NAME, wil);
563         return rc;
564 }
565
566 void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
567 {
568         wil_dbg_misc(wil, "%s()\n", __func__);
569
570         wil_mask_irq(wil);
571         free_irq(irq, wil);
572 }