1 /*
2  * Copyright (c) 2012 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 
21 /**
22  * Theory of operation:
23  *
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:
27  * TX, RX, and MISC.
28  *
29  * Registers may be configured to either "write 1 to clear" or
30  * "clear on read" mode
31  *
32  * When handling interrupt, one have to mask/unmask interrupts for the
33  * real ISR registers, or hardware may malfunction.
34  *
35  */
36 
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)
42 
43 #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
44 					BIT_DMA_PSEUDO_CAUSE_TX | \
45 					BIT_DMA_PSEUDO_CAUSE_MISC))
46 
47 #if defined(CONFIG_WIL6210_ISR_COR)
48 /* configure to Clear-On-Read mode */
49 #define WIL_ICR_ICC_VALUE	(0xFFFFFFFFUL)
50 
51 static inline void wil_icr_clear(u32 x, void __iomem *addr)
52 {
53 
54 }
55 #else /* defined(CONFIG_WIL6210_ISR_COR) */
56 /* configure to Write-1-to-Clear mode */
57 #define WIL_ICR_ICC_VALUE	(0UL)
58 
59 static inline void wil_icr_clear(u32 x, void __iomem *addr)
60 {
61 	iowrite32(x, addr);
62 }
63 #endif /* defined(CONFIG_WIL6210_ISR_COR) */
64 
65 static inline u32 wil_ioread32_and_clear(void __iomem *addr)
66 {
67 	u32 x = ioread32(addr);
68 
69 	wil_icr_clear(x, addr);
70 
71 	return x;
72 }
73 
74 static void wil6210_mask_irq_tx(struct wil6210_priv *wil)
75 {
76 	iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
77 		  HOSTADDR(RGF_DMA_EP_TX_ICR) +
78 		  offsetof(struct RGF_ICR, IMS));
79 }
80 
81 static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
82 {
83 	iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
84 		  HOSTADDR(RGF_DMA_EP_RX_ICR) +
85 		  offsetof(struct RGF_ICR, IMS));
86 }
87 
88 static void wil6210_mask_irq_misc(struct wil6210_priv *wil)
89 {
90 	iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
91 		  HOSTADDR(RGF_DMA_EP_MISC_ICR) +
92 		  offsetof(struct RGF_ICR, IMS));
93 }
94 
95 static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
96 {
97 	wil_dbg_IRQ(wil, "%s()\n", __func__);
98 
99 	iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
100 		  HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
101 
102 	clear_bit(wil_status_irqen, &wil->status);
103 }
104 
105 static void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
106 {
107 	iowrite32(WIL6210_IMC_TX, wil->csr +
108 		  HOSTADDR(RGF_DMA_EP_TX_ICR) +
109 		  offsetof(struct RGF_ICR, IMC));
110 }
111 
112 static void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
113 {
114 	iowrite32(WIL6210_IMC_RX, wil->csr +
115 		  HOSTADDR(RGF_DMA_EP_RX_ICR) +
116 		  offsetof(struct RGF_ICR, IMC));
117 }
118 
119 static void wil6210_unmask_irq_misc(struct wil6210_priv *wil)
120 {
121 	iowrite32(WIL6210_IMC_MISC, wil->csr +
122 		  HOSTADDR(RGF_DMA_EP_MISC_ICR) +
123 		  offsetof(struct RGF_ICR, IMC));
124 }
125 
126 static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
127 {
128 	wil_dbg_IRQ(wil, "%s()\n", __func__);
129 
130 	set_bit(wil_status_irqen, &wil->status);
131 
132 	iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr +
133 		  HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
134 }
135 
136 void wil6210_disable_irq(struct wil6210_priv *wil)
137 {
138 	wil_dbg_IRQ(wil, "%s()\n", __func__);
139 
140 	wil6210_mask_irq_tx(wil);
141 	wil6210_mask_irq_rx(wil);
142 	wil6210_mask_irq_misc(wil);
143 	wil6210_mask_irq_pseudo(wil);
144 }
145 
146 void wil6210_enable_irq(struct wil6210_priv *wil)
147 {
148 	wil_dbg_IRQ(wil, "%s()\n", __func__);
149 
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));
156 
157 	wil6210_unmask_irq_pseudo(wil);
158 	wil6210_unmask_irq_tx(wil);
159 	wil6210_unmask_irq_rx(wil);
160 	wil6210_unmask_irq_misc(wil);
161 }
162 
163 static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
164 {
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));
169 
170 	wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr);
171 
172 	if (!isr) {
173 		wil_err(wil, "spurious IRQ: RX\n");
174 		return IRQ_NONE;
175 	}
176 
177 	wil6210_mask_irq_rx(wil);
178 
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;
182 		wil_rx_handle(wil);
183 	}
184 
185 	if (isr)
186 		wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
187 
188 	wil6210_unmask_irq_rx(wil);
189 
190 	return IRQ_HANDLED;
191 }
192 
193 static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
194 {
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));
199 
200 	wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr);
201 
202 	if (!isr) {
203 		wil_err(wil, "spurious IRQ: TX\n");
204 		return IRQ_NONE;
205 	}
206 
207 	wil6210_mask_irq_tx(wil);
208 
209 	if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
210 		uint i;
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);
215 			if (isr & mask) {
216 				isr &= ~mask;
217 				wil_dbg_IRQ(wil, "TX done(%i)\n", i);
218 				wil_tx_complete(wil, i);
219 			}
220 		}
221 	}
222 
223 	if (isr)
224 		wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
225 
226 	wil6210_unmask_irq_tx(wil);
227 
228 	return IRQ_HANDLED;
229 }
230 
231 static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
232 {
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));
237 
238 	wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr);
239 
240 	if (!isr) {
241 		wil_err(wil, "spurious IRQ: MISC\n");
242 		return IRQ_NONE;
243 	}
244 
245 	wil6210_mask_irq_misc(wil);
246 
247 	if (isr & ISR_MISC_FW_READY) {
248 		wil_dbg_IRQ(wil, "IRQ: FW ready\n");
249 		/**
250 		 * Actual FW ready indicated by the
251 		 * WMI_FW_READY_EVENTID
252 		 */
253 		isr &= ~ISR_MISC_FW_READY;
254 	}
255 
256 	wil->isr_misc = isr;
257 
258 	if (isr) {
259 		return IRQ_WAKE_THREAD;
260 	} else {
261 		wil6210_unmask_irq_misc(wil);
262 		return IRQ_HANDLED;
263 	}
264 }
265 
266 static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
267 {
268 	struct wil6210_priv *wil = cookie;
269 	u32 isr = wil->isr_misc;
270 
271 	wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr);
272 
273 	if (isr & ISR_MISC_MBOX_EVT) {
274 		wil_dbg_IRQ(wil, "MBOX event\n");
275 		wmi_recv_cmd(wil);
276 		isr &= ~ISR_MISC_MBOX_EVT;
277 	}
278 
279 	if (isr)
280 		wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
281 
282 	wil->isr_misc = 0;
283 
284 	wil6210_unmask_irq_misc(wil);
285 
286 	return IRQ_HANDLED;
287 }
288 
289 /**
290  * thread IRQ handler
291  */
292 static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
293 {
294 	struct wil6210_priv *wil = cookie;
295 
296 	wil_dbg_IRQ(wil, "Thread IRQ\n");
297 	/* Discover real IRQ cause */
298 	if (wil->isr_misc)
299 		wil6210_irq_misc_thread(irq, cookie);
300 
301 	wil6210_unmask_irq_pseudo(wil);
302 
303 	return IRQ_HANDLED;
304 }
305 
306 /* DEBUG
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.
309  *
310  * Catch irq issue if it happens and print all I can.
311  */
312 static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
313 {
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",
346 				pseudo_cause,
347 				icm_rx, icr_rx, imv_rx,
348 				icm_tx, icr_tx, imv_tx,
349 				icm_misc, icr_misc, imv_misc);
350 
351 		return -EINVAL;
352 	}
353 
354 	return 0;
355 }
356 
357 static irqreturn_t wil6210_hardirq(int irq, void *cookie)
358 {
359 	irqreturn_t rc = IRQ_HANDLED;
360 	struct wil6210_priv *wil = cookie;
361 	u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
362 
363 	/**
364 	 * pseudo_cause is Clear-On-Read, no need to ACK
365 	 */
366 	if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff))
367 		return IRQ_NONE;
368 
369 	/* FIXME: IRQ mask debug */
370 	if (wil6210_debug_irq_mask(wil, pseudo_cause))
371 		return IRQ_NONE;
372 
373 	wil6210_mask_irq_pseudo(wil);
374 
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
379 	 *
380 	 * Hard IRQ handler reads and clears ISR.
381 	 *
382 	 * If threaded handler requested, hard IRQ handler
383 	 * returns IRQ_WAKE_THREAD and saves ISR register value
384 	 * for the threaded handler use.
385 	 *
386 	 * voting for wake thread - need at least 1 vote
387 	 */
388 	if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) &&
389 	    (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
390 		rc = IRQ_WAKE_THREAD;
391 
392 	if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
393 	    (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
394 		rc = IRQ_WAKE_THREAD;
395 
396 	if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) &&
397 	    (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD))
398 		rc = IRQ_WAKE_THREAD;
399 
400 	/* if thread is requested, it will unmask IRQ */
401 	if (rc != IRQ_WAKE_THREAD)
402 		wil6210_unmask_irq_pseudo(wil);
403 
404 	wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause);
405 
406 	return rc;
407 }
408 
409 static int wil6210_request_3msi(struct wil6210_priv *wil, int irq)
410 {
411 	int rc;
412 	/*
413 	 * IRQ's are in the following order:
414 	 * - Tx
415 	 * - Rx
416 	 * - Misc
417 	 */
418 
419 	rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED,
420 			 WIL_NAME"_tx", wil);
421 	if (rc)
422 		return rc;
423 
424 	rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED,
425 			 WIL_NAME"_rx", wil);
426 	if (rc)
427 		goto free0;
428 
429 	rc = request_threaded_irq(irq + 2, wil6210_irq_misc,
430 				  wil6210_irq_misc_thread,
431 				  IRQF_SHARED, WIL_NAME"_misc", wil);
432 	if (rc)
433 		goto free1;
434 
435 	return 0;
436 	/* error branch */
437 free1:
438 	free_irq(irq + 1, wil);
439 free0:
440 	free_irq(irq, wil);
441 
442 	return rc;
443 }
444 
445 int wil6210_init_irq(struct wil6210_priv *wil, int irq)
446 {
447 	int rc;
448 	if (wil->n_msi == 3)
449 		rc = wil6210_request_3msi(wil, irq);
450 	else
451 		rc = request_threaded_irq(irq, wil6210_hardirq,
452 					  wil6210_thread_irq,
453 					  wil->n_msi ? 0 : IRQF_SHARED,
454 					  WIL_NAME, wil);
455 	if (rc)
456 		return rc;
457 
458 	wil6210_enable_irq(wil);
459 
460 	return 0;
461 }
462 
463 void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
464 {
465 	wil6210_disable_irq(wil);
466 	free_irq(irq, wil);
467 	if (wil->n_msi == 3) {
468 		free_irq(irq + 1, wil);
469 		free_irq(irq + 2, wil);
470 	}
471 }
472