xref: /linux/drivers/net/wireless/ath/wil6210/interrupt.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
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 }
567