2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
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.
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.
17 #include <linux/interrupt.h>
22 * Theory of operation:
24 * There is ISR pseudo-cause register,
25 * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE
26 * Its bits represents OR'ed bits from 3 real ISR registers:
29 * Registers may be configured to either "write 1 to clear" or
30 * "clear on read" mode
32 * When handling interrupt, one have to mask/unmask interrupts for the
33 * real ISR registers, or hardware may malfunction.
37 #define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL)
38 #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE
39 #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \
40 BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
41 #define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT)
43 #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
44 BIT_DMA_PSEUDO_CAUSE_TX | \
45 BIT_DMA_PSEUDO_CAUSE_MISC))
47 #if defined(CONFIG_WIL6210_ISR_COR)
48 /* configure to Clear-On-Read mode */
49 #define WIL_ICR_ICC_VALUE (0xFFFFFFFFUL)
51 static inline void wil_icr_clear(u32 x
, void __iomem
*addr
)
55 #else /* defined(CONFIG_WIL6210_ISR_COR) */
56 /* configure to Write-1-to-Clear mode */
57 #define WIL_ICR_ICC_VALUE (0UL)
59 static inline void wil_icr_clear(u32 x
, void __iomem
*addr
)
63 #endif /* defined(CONFIG_WIL6210_ISR_COR) */
65 static inline u32
wil_ioread32_and_clear(void __iomem
*addr
)
67 u32 x
= ioread32(addr
);
69 wil_icr_clear(x
, addr
);
74 static void wil6210_mask_irq_tx(struct wil6210_priv
*wil
)
76 iowrite32(WIL6210_IRQ_DISABLE
, wil
->csr
+
77 HOSTADDR(RGF_DMA_EP_TX_ICR
) +
78 offsetof(struct RGF_ICR
, IMS
));
81 static void wil6210_mask_irq_rx(struct wil6210_priv
*wil
)
83 iowrite32(WIL6210_IRQ_DISABLE
, wil
->csr
+
84 HOSTADDR(RGF_DMA_EP_RX_ICR
) +
85 offsetof(struct RGF_ICR
, IMS
));
88 static void wil6210_mask_irq_misc(struct wil6210_priv
*wil
)
90 iowrite32(WIL6210_IRQ_DISABLE
, wil
->csr
+
91 HOSTADDR(RGF_DMA_EP_MISC_ICR
) +
92 offsetof(struct RGF_ICR
, IMS
));
95 static void wil6210_mask_irq_pseudo(struct wil6210_priv
*wil
)
97 wil_dbg_IRQ(wil
, "%s()\n", __func__
);
99 iowrite32(WIL6210_IRQ_DISABLE
, wil
->csr
+
100 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW
));
102 clear_bit(wil_status_irqen
, &wil
->status
);
105 static void wil6210_unmask_irq_tx(struct wil6210_priv
*wil
)
107 iowrite32(WIL6210_IMC_TX
, wil
->csr
+
108 HOSTADDR(RGF_DMA_EP_TX_ICR
) +
109 offsetof(struct RGF_ICR
, IMC
));
112 static void wil6210_unmask_irq_rx(struct wil6210_priv
*wil
)
114 iowrite32(WIL6210_IMC_RX
, wil
->csr
+
115 HOSTADDR(RGF_DMA_EP_RX_ICR
) +
116 offsetof(struct RGF_ICR
, IMC
));
119 static void wil6210_unmask_irq_misc(struct wil6210_priv
*wil
)
121 iowrite32(WIL6210_IMC_MISC
, wil
->csr
+
122 HOSTADDR(RGF_DMA_EP_MISC_ICR
) +
123 offsetof(struct RGF_ICR
, IMC
));
126 static void wil6210_unmask_irq_pseudo(struct wil6210_priv
*wil
)
128 wil_dbg_IRQ(wil
, "%s()\n", __func__
);
130 set_bit(wil_status_irqen
, &wil
->status
);
132 iowrite32(WIL6210_IRQ_PSEUDO_MASK
, wil
->csr
+
133 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW
));
136 void wil6210_disable_irq(struct wil6210_priv
*wil
)
138 wil_dbg_IRQ(wil
, "%s()\n", __func__
);
140 wil6210_mask_irq_tx(wil
);
141 wil6210_mask_irq_rx(wil
);
142 wil6210_mask_irq_misc(wil
);
143 wil6210_mask_irq_pseudo(wil
);
146 void wil6210_enable_irq(struct wil6210_priv
*wil
)
148 wil_dbg_IRQ(wil
, "%s()\n", __func__
);
150 iowrite32(WIL_ICR_ICC_VALUE
, wil
->csr
+ HOSTADDR(RGF_DMA_EP_RX_ICR
) +
151 offsetof(struct RGF_ICR
, ICC
));
152 iowrite32(WIL_ICR_ICC_VALUE
, wil
->csr
+ HOSTADDR(RGF_DMA_EP_TX_ICR
) +
153 offsetof(struct RGF_ICR
, ICC
));
154 iowrite32(WIL_ICR_ICC_VALUE
, wil
->csr
+ HOSTADDR(RGF_DMA_EP_MISC_ICR
) +
155 offsetof(struct RGF_ICR
, ICC
));
157 wil6210_unmask_irq_pseudo(wil
);
158 wil6210_unmask_irq_tx(wil
);
159 wil6210_unmask_irq_rx(wil
);
160 wil6210_unmask_irq_misc(wil
);
163 static irqreturn_t
wil6210_irq_rx(int irq
, void *cookie
)
165 struct wil6210_priv
*wil
= cookie
;
166 u32 isr
= wil_ioread32_and_clear(wil
->csr
+
167 HOSTADDR(RGF_DMA_EP_RX_ICR
) +
168 offsetof(struct RGF_ICR
, ICR
));
170 wil_dbg_IRQ(wil
, "ISR RX 0x%08x\n", isr
);
173 wil_err(wil
, "spurious IRQ: RX\n");
177 wil6210_mask_irq_rx(wil
);
179 if (isr
& BIT_DMA_EP_RX_ICR_RX_DONE
) {
180 wil_dbg_IRQ(wil
, "RX done\n");
181 isr
&= ~BIT_DMA_EP_RX_ICR_RX_DONE
;
186 wil_err(wil
, "un-handled RX ISR bits 0x%08x\n", isr
);
188 wil6210_unmask_irq_rx(wil
);
193 static irqreturn_t
wil6210_irq_tx(int irq
, void *cookie
)
195 struct wil6210_priv
*wil
= cookie
;
196 u32 isr
= wil_ioread32_and_clear(wil
->csr
+
197 HOSTADDR(RGF_DMA_EP_TX_ICR
) +
198 offsetof(struct RGF_ICR
, ICR
));
200 wil_dbg_IRQ(wil
, "ISR TX 0x%08x\n", isr
);
203 wil_err(wil
, "spurious IRQ: TX\n");
207 wil6210_mask_irq_tx(wil
);
209 if (isr
& BIT_DMA_EP_TX_ICR_TX_DONE
) {
211 wil_dbg_IRQ(wil
, "TX done\n");
212 isr
&= ~BIT_DMA_EP_TX_ICR_TX_DONE
;
213 for (i
= 0; i
< 24; i
++) {
214 u32 mask
= BIT_DMA_EP_TX_ICR_TX_DONE_N(i
);
217 wil_dbg_IRQ(wil
, "TX done(%i)\n", i
);
218 wil_tx_complete(wil
, i
);
224 wil_err(wil
, "un-handled TX ISR bits 0x%08x\n", isr
);
226 wil6210_unmask_irq_tx(wil
);
231 static irqreturn_t
wil6210_irq_misc(int irq
, void *cookie
)
233 struct wil6210_priv
*wil
= cookie
;
234 u32 isr
= wil_ioread32_and_clear(wil
->csr
+
235 HOSTADDR(RGF_DMA_EP_MISC_ICR
) +
236 offsetof(struct RGF_ICR
, ICR
));
238 wil_dbg_IRQ(wil
, "ISR MISC 0x%08x\n", isr
);
241 wil_err(wil
, "spurious IRQ: MISC\n");
245 wil6210_mask_irq_misc(wil
);
247 if (isr
& ISR_MISC_FW_READY
) {
248 wil_dbg_IRQ(wil
, "IRQ: FW ready\n");
250 * Actual FW ready indicated by the
251 * WMI_FW_READY_EVENTID
253 isr
&= ~ISR_MISC_FW_READY
;
259 return IRQ_WAKE_THREAD
;
261 wil6210_unmask_irq_misc(wil
);
266 static irqreturn_t
wil6210_irq_misc_thread(int irq
, void *cookie
)
268 struct wil6210_priv
*wil
= cookie
;
269 u32 isr
= wil
->isr_misc
;
271 wil_dbg_IRQ(wil
, "Thread ISR MISC 0x%08x\n", isr
);
273 if (isr
& ISR_MISC_MBOX_EVT
) {
274 wil_dbg_IRQ(wil
, "MBOX event\n");
276 isr
&= ~ISR_MISC_MBOX_EVT
;
280 wil_err(wil
, "un-handled MISC ISR bits 0x%08x\n", isr
);
284 wil6210_unmask_irq_misc(wil
);
292 static irqreturn_t
wil6210_thread_irq(int irq
, void *cookie
)
294 struct wil6210_priv
*wil
= cookie
;
296 wil_dbg_IRQ(wil
, "Thread IRQ\n");
297 /* Discover real IRQ cause */
299 wil6210_irq_misc_thread(irq
, cookie
);
301 wil6210_unmask_irq_pseudo(wil
);
307 * There is subtle bug in hardware that causes IRQ to raise when it should be
308 * masked. It is quite rare and hard to debug.
310 * Catch irq issue if it happens and print all I can.
312 static int wil6210_debug_irq_mask(struct wil6210_priv
*wil
, u32 pseudo_cause
)
314 if (!test_bit(wil_status_irqen
, &wil
->status
)) {
315 u32 icm_rx
= wil_ioread32_and_clear(wil
->csr
+
316 HOSTADDR(RGF_DMA_EP_RX_ICR
) +
317 offsetof(struct RGF_ICR
, ICM
));
318 u32 icr_rx
= wil_ioread32_and_clear(wil
->csr
+
319 HOSTADDR(RGF_DMA_EP_RX_ICR
) +
320 offsetof(struct RGF_ICR
, ICR
));
321 u32 imv_rx
= ioread32(wil
->csr
+
322 HOSTADDR(RGF_DMA_EP_RX_ICR
) +
323 offsetof(struct RGF_ICR
, IMV
));
324 u32 icm_tx
= wil_ioread32_and_clear(wil
->csr
+
325 HOSTADDR(RGF_DMA_EP_TX_ICR
) +
326 offsetof(struct RGF_ICR
, ICM
));
327 u32 icr_tx
= wil_ioread32_and_clear(wil
->csr
+
328 HOSTADDR(RGF_DMA_EP_TX_ICR
) +
329 offsetof(struct RGF_ICR
, ICR
));
330 u32 imv_tx
= ioread32(wil
->csr
+
331 HOSTADDR(RGF_DMA_EP_TX_ICR
) +
332 offsetof(struct RGF_ICR
, IMV
));
333 u32 icm_misc
= wil_ioread32_and_clear(wil
->csr
+
334 HOSTADDR(RGF_DMA_EP_MISC_ICR
) +
335 offsetof(struct RGF_ICR
, ICM
));
336 u32 icr_misc
= wil_ioread32_and_clear(wil
->csr
+
337 HOSTADDR(RGF_DMA_EP_MISC_ICR
) +
338 offsetof(struct RGF_ICR
, ICR
));
339 u32 imv_misc
= ioread32(wil
->csr
+
340 HOSTADDR(RGF_DMA_EP_MISC_ICR
) +
341 offsetof(struct RGF_ICR
, IMV
));
342 wil_err(wil
, "IRQ when it should be masked: pseudo 0x%08x\n"
343 "Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
344 "Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
345 "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n",
347 icm_rx
, icr_rx
, imv_rx
,
348 icm_tx
, icr_tx
, imv_tx
,
349 icm_misc
, icr_misc
, imv_misc
);
357 static irqreturn_t
wil6210_hardirq(int irq
, void *cookie
)
359 irqreturn_t rc
= IRQ_HANDLED
;
360 struct wil6210_priv
*wil
= cookie
;
361 u32 pseudo_cause
= ioread32(wil
->csr
+ HOSTADDR(RGF_DMA_PSEUDO_CAUSE
));
364 * pseudo_cause is Clear-On-Read, no need to ACK
366 if ((pseudo_cause
== 0) || ((pseudo_cause
& 0xff) == 0xff))
369 /* FIXME: IRQ mask debug */
370 if (wil6210_debug_irq_mask(wil
, pseudo_cause
))
373 wil6210_mask_irq_pseudo(wil
);
375 /* Discover real IRQ cause
376 * There are 2 possible phases for every IRQ:
377 * - hard IRQ handler called right here
378 * - threaded handler called later
380 * Hard IRQ handler reads and clears ISR.
382 * If threaded handler requested, hard IRQ handler
383 * returns IRQ_WAKE_THREAD and saves ISR register value
384 * for the threaded handler use.
386 * voting for wake thread - need at least 1 vote
388 if ((pseudo_cause
& BIT_DMA_PSEUDO_CAUSE_RX
) &&
389 (wil6210_irq_rx(irq
, cookie
) == IRQ_WAKE_THREAD
))
390 rc
= IRQ_WAKE_THREAD
;
392 if ((pseudo_cause
& BIT_DMA_PSEUDO_CAUSE_TX
) &&
393 (wil6210_irq_tx(irq
, cookie
) == IRQ_WAKE_THREAD
))
394 rc
= IRQ_WAKE_THREAD
;
396 if ((pseudo_cause
& BIT_DMA_PSEUDO_CAUSE_MISC
) &&
397 (wil6210_irq_misc(irq
, cookie
) == IRQ_WAKE_THREAD
))
398 rc
= IRQ_WAKE_THREAD
;
400 /* if thread is requested, it will unmask IRQ */
401 if (rc
!= IRQ_WAKE_THREAD
)
402 wil6210_unmask_irq_pseudo(wil
);
404 wil_dbg_IRQ(wil
, "Hard IRQ 0x%08x\n", pseudo_cause
);
409 static int wil6210_request_3msi(struct wil6210_priv
*wil
, int irq
)
413 * IRQ's are in the following order:
419 rc
= request_irq(irq
, wil6210_irq_tx
, IRQF_SHARED
,
424 rc
= request_irq(irq
+ 1, wil6210_irq_rx
, IRQF_SHARED
,
429 rc
= request_threaded_irq(irq
+ 2, wil6210_irq_misc
,
430 wil6210_irq_misc_thread
,
431 IRQF_SHARED
, WIL_NAME
"_misc", wil
);
438 free_irq(irq
+ 1, wil
);
445 int wil6210_init_irq(struct wil6210_priv
*wil
, int irq
)
449 rc
= wil6210_request_3msi(wil
, irq
);
451 rc
= request_threaded_irq(irq
, wil6210_hardirq
,
453 wil
->n_msi
? 0 : IRQF_SHARED
,
458 wil6210_enable_irq(wil
);
463 void wil6210_fini_irq(struct wil6210_priv
*wil
, int irq
)
465 wil6210_disable_irq(wil
);
467 if (wil
->n_msi
== 3) {
468 free_irq(irq
+ 1, wil
);
469 free_irq(irq
+ 2, wil
);