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