File Index
Files and directories
Sign in
FILE

interrupt.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/ath/wil6210/interrupt.c C
  1// SPDX-License-Identifier: ISC
  2/*
  3 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
  4 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  5 */
  6
  7#include <linux/interrupt.h>
  8
  9#include "wil6210.h"
 10#include "trace.h"
 11
 12/*
 13 * Theory of operation:
 14 *
 15 * There is ISR pseudo-cause register,
 16 * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE
 17 * Its bits represents OR'ed bits from 3 real ISR registers:
 18 * TX, RX, and MISC.
 19 *
 20 * Registers may be configured to either "write 1 to clear" or
 21 * "clear on read" mode
 22 *
 23 * When handling interrupt, one have to mask/unmask interrupts for the
 24 * real ISR registers, or hardware may malfunction.
 25 *
 26 */
 27
 28#define WIL6210_IRQ_DISABLE		(0xFFFFFFFFUL)
 29#define WIL6210_IRQ_DISABLE_NO_HALP	(0xF7FFFFFFUL)
 30#define WIL6210_IMC_RX		(BIT_DMA_EP_RX_ICR_RX_DONE | \
 31				 BIT_DMA_EP_RX_ICR_RX_HTRSH)
 32#define WIL6210_IMC_RX_NO_RX_HTRSH (WIL6210_IMC_RX & \
 33				    (~(BIT_DMA_EP_RX_ICR_RX_HTRSH)))
 34#define WIL6210_IMC_TX		(BIT_DMA_EP_TX_ICR_TX_DONE | \
 35				BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
 36#define WIL6210_IMC_TX_EDMA		BIT_TX_STATUS_IRQ
 37#define WIL6210_IMC_RX_EDMA		BIT_RX_STATUS_IRQ
 38#define WIL6210_IMC_MISC_NO_HALP	(ISR_MISC_FW_READY | \
 39					 ISR_MISC_MBOX_EVT | \
 40					 ISR_MISC_FW_ERROR)
 41#define WIL6210_IMC_MISC		(WIL6210_IMC_MISC_NO_HALP | \
 42					 BIT_DMA_EP_MISC_ICR_HALP)
 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#define WIL_ICR_ICC_MISC_VALUE	(0xF7FFFFFFUL)
 51
 52static inline void wil_icr_clear(u32 x, void __iomem *addr)
 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#define WIL_ICR_ICC_MISC_VALUE	(0UL)
 59
 60static inline void wil_icr_clear(u32 x, void __iomem *addr)
 61{
 62	writel(x, addr);
 63}
 64#endif /* defined(CONFIG_WIL6210_ISR_COR) */
 65
 66static inline u32 wil_ioread32_and_clear(void __iomem *addr)
 67{
 68	u32 x = readl(addr);
 69
 70	wil_icr_clear(x, addr);
 71
 72	return x;
 73}
 74
 75static void wil6210_mask_irq_tx(struct wil6210_priv *wil)
 76{
 77	wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMS),
 78	      WIL6210_IRQ_DISABLE);
 79}
 80
 81static void wil6210_mask_irq_tx_edma(struct wil6210_priv *wil)
 82{
 83	wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMS),
 84	      WIL6210_IRQ_DISABLE);
 85}
 86
 87static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
 88{
 89	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMS),
 90	      WIL6210_IRQ_DISABLE);
 91}
 92
 93static void wil6210_mask_irq_rx_edma(struct wil6210_priv *wil)
 94{
 95	wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMS),
 96	      WIL6210_IRQ_DISABLE);
 97}
 98
 99static void wil6210_mask_irq_misc(struct wil6210_priv *wil, bool mask_halp)
100{
101	wil_dbg_irq(wil, "mask_irq_misc: mask_halp(%s)\n",
102		    mask_halp ? "true" : "false");
103
104	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS),
105	      mask_halp ? WIL6210_IRQ_DISABLE : WIL6210_IRQ_DISABLE_NO_HALP);
106}
107
108void wil6210_mask_halp(struct wil6210_priv *wil)
109{
110	wil_dbg_irq(wil, "mask_halp\n");
111
112	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS),
113	      BIT_DMA_EP_MISC_ICR_HALP);
114}
115
116static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
117{
118	wil_dbg_irq(wil, "mask_irq_pseudo\n");
119
120	wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_DISABLE);
121
122	clear_bit(wil_status_irqen, wil->status);
123}
124
125void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
126{
127	wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMC),
128	      WIL6210_IMC_TX);
129}
130
131void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil)
132{
133	wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMC),
134	      WIL6210_IMC_TX_EDMA);
135}
136
137void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
138{
139	bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0;
140
141	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
142	      unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
143}
144
145void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil)
146{
147	wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMC),
148	      WIL6210_IMC_RX_EDMA);
149}
150
151static void wil6210_unmask_irq_misc(struct wil6210_priv *wil, bool unmask_halp)
152{
153	wil_dbg_irq(wil, "unmask_irq_misc: unmask_halp(%s)\n",
154		    unmask_halp ? "true" : "false");
155
156	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC),
157	      unmask_halp ? WIL6210_IMC_MISC : WIL6210_IMC_MISC_NO_HALP);
158}
159
160static void wil6210_unmask_halp(struct wil6210_priv *wil)
161{
162	wil_dbg_irq(wil, "unmask_halp\n");
163
164	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC),
165	      BIT_DMA_EP_MISC_ICR_HALP);
166}
167
168static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
169{
170	wil_dbg_irq(wil, "unmask_irq_pseudo\n");
171
172	set_bit(wil_status_irqen, wil->status);
173
174	wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_PSEUDO_MASK);
175}
176
177void wil_mask_irq(struct wil6210_priv *wil)
178{
179	wil_dbg_irq(wil, "mask_irq\n");
180
181	wil6210_mask_irq_tx(wil);
182	if (wil->use_enhanced_dma_hw)
183		wil6210_mask_irq_tx_edma(wil);
184	wil6210_mask_irq_rx(wil);
185	if (wil->use_enhanced_dma_hw)
186		wil6210_mask_irq_rx_edma(wil);
187	wil6210_mask_irq_misc(wil, true);
188	wil6210_mask_irq_pseudo(wil);
189}
190
191void wil_unmask_irq(struct wil6210_priv *wil)
192{
193	wil_dbg_irq(wil, "unmask_irq\n");
194
195	if (wil->use_enhanced_dma_hw) {
196		wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC),
197		      WIL_ICR_ICC_VALUE);
198		wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC),
199		      WIL_ICR_ICC_VALUE);
200	}
201	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC),
202	      WIL_ICR_ICC_MISC_VALUE);
203	wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, ICC),
204	      WIL_ICR_ICC_VALUE);
205	wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, ICC),
206	      WIL_ICR_ICC_VALUE);
207
208	wil6210_unmask_irq_pseudo(wil);
209	if (wil->use_enhanced_dma_hw) {
210		wil6210_unmask_irq_tx_edma(wil);
211		wil6210_unmask_irq_rx_edma(wil);
212	} else {
213		wil6210_unmask_irq_tx(wil);
214		wil6210_unmask_irq_rx(wil);
215	}
216	wil6210_unmask_irq_misc(wil, true);
217}
218
219void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil)
220{
221	u32 moderation;
222
223	wil_s(wil, RGF_INT_GEN_IDLE_TIME_LIMIT, WIL_EDMA_IDLE_TIME_LIMIT_USEC);
224
225	wil_s(wil, RGF_INT_GEN_TIME_UNIT_LIMIT, WIL_EDMA_TIME_UNIT_CLK_CYCLES);
226
227	/* Update RX and TX moderation */
228	moderation = wil->rx_max_burst_duration |
229		(WIL_EDMA_AGG_WATERMARK << WIL_EDMA_AGG_WATERMARK_POS);
230	wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_0, moderation);
231	wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_1, moderation);
232
233	/* Treat special events as regular
234	 * (set bit 0 to 0x1 and clear bits 1-8)
235	 */
236	wil_c(wil, RGF_INT_COUNT_ON_SPECIAL_EVT, 0x1FE);
237	wil_s(wil, RGF_INT_COUNT_ON_SPECIAL_EVT, 0x1);
238}
239
240void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
241{
242	struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
243
244	wil_dbg_irq(wil, "configure_interrupt_moderation\n");
245
246	/* disable interrupt moderation for monitor
247	 * to get better timestamp precision
248	 */
249	if (wdev->iftype == NL80211_IFTYPE_MONITOR)
250		return;
251
252	/* Disable and clear tx counter before (re)configuration */
253	wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR);
254	wil_w(wil, RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration);
255	wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n",
256		 wil->tx_max_burst_duration);
257	/* Configure TX max burst duration timer to use usec units */
258	wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL,
259	      BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL);
260
261	/* Disable and clear tx idle counter before (re)configuration */
262	wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR);
263	wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout);
264	wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n",
265		 wil->tx_interframe_timeout);
266	/* Configure TX max burst duration timer to use usec units */
267	wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN |
268	      BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL);
269
270	/* Disable and clear rx counter before (re)configuration */
271	wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR);
272	wil_w(wil, RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration);
273	wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n",
274		 wil->rx_max_burst_duration);
275	/* Configure TX max burst duration timer to use usec units */
276	wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL,
277	      BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL);
278
279	/* Disable and clear rx idle counter before (re)configuration */
280	wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR);
281	wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout);
282	wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n",
283		 wil->rx_interframe_timeout);
284	/* Configure TX max burst duration timer to use usec units */
285	wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN |
286	      BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL);
287}
288
289static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
290{
291	struct wil6210_priv *wil = cookie;
292	u32 isr;
293	bool need_unmask = true;
294
295	wil6210_mask_irq_rx(wil);
296
297	isr = wil_ioread32_and_clear(wil->csr +
298				     HOSTADDR(RGF_DMA_EP_RX_ICR) +
299				     offsetof(struct RGF_ICR, ICR));
300
301	trace_wil6210_irq_rx(isr);
302	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
303
304	if (unlikely(!isr)) {
305		wil_err_ratelimited(wil, "spurious IRQ: RX\n");
306		wil6210_unmask_irq_rx(wil);
307		return IRQ_NONE;
308	}
309
310	/* RX_DONE and RX_HTRSH interrupts are the same if interrupt
311	 * moderation is not used. Interrupt moderation may cause RX
312	 * buffer overflow while RX_DONE is delayed. The required
313	 * action is always the same - should empty the accumulated
314	 * packets from the RX ring.
315	 */
316	if (likely(isr & (BIT_DMA_EP_RX_ICR_RX_DONE |
317			  BIT_DMA_EP_RX_ICR_RX_HTRSH))) {
318		wil_dbg_irq(wil, "RX done / RX_HTRSH received, ISR (0x%x)\n",
319			    isr);
320
321		isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE |
322			 BIT_DMA_EP_RX_ICR_RX_HTRSH);
323		if (likely(test_bit(wil_status_fwready, wil->status))) {
324			if (likely(test_bit(wil_status_napi_en, wil->status))) {
325				wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
326				need_unmask = false;
327				napi_schedule(&wil->napi_rx);
328			} else {
329				wil_err_ratelimited(
330					wil,
331					"Got Rx interrupt while stopping interface\n");
332			}
333		} else {
334			wil_err_ratelimited(wil, "Got Rx interrupt while in reset\n");
335		}
336	}
337
338	if (unlikely(isr))
339		wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
340
341	/* Rx IRQ will be enabled when NAPI processing finished */
342
343	atomic_inc(&wil->isr_count_rx);
344
345	if (unlikely(need_unmask))
346		wil6210_unmask_irq_rx(wil);
347
348	return IRQ_HANDLED;
349}
350
351static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie)
352{
353	struct wil6210_priv *wil = cookie;
354	u32 isr;
355	bool need_unmask = true;
356
357	wil6210_mask_irq_rx_edma(wil);
358
359	isr = wil_ioread32_and_clear(wil->csr +
360				     HOSTADDR(RGF_INT_GEN_RX_ICR) +
361				     offsetof(struct RGF_ICR, ICR));
362
363	trace_wil6210_irq_rx(isr);
364	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
365
366	if (unlikely(!isr)) {
367		wil_err(wil, "spurious IRQ: RX\n");
368		wil6210_unmask_irq_rx_edma(wil);
369		return IRQ_NONE;
370	}
371
372	if (likely(isr & BIT_RX_STATUS_IRQ)) {
373		wil_dbg_irq(wil, "RX status ring\n");
374		isr &= ~BIT_RX_STATUS_IRQ;
375		if (likely(test_bit(wil_status_fwready, wil->status))) {
376			if (likely(test_bit(wil_status_napi_en, wil->status))) {
377				wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
378				need_unmask = false;
379				napi_schedule(&wil->napi_rx);
380			} else {
381				wil_err(wil,
382					"Got Rx interrupt while stopping interface\n");
383			}
384		} else {
385			wil_err(wil, "Got Rx interrupt while in reset\n");
386		}
387	}
388
389	if (unlikely(isr))
390		wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
391
392	/* Rx IRQ will be enabled when NAPI processing finished */
393
394	atomic_inc(&wil->isr_count_rx);
395
396	if (unlikely(need_unmask))
397		wil6210_unmask_irq_rx_edma(wil);
398
399	return IRQ_HANDLED;
400}
401
402static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie)
403{
404	struct wil6210_priv *wil = cookie;
405	u32 isr;
406	bool need_unmask = true;
407
408	wil6210_mask_irq_tx_edma(wil);
409
410	isr = wil_ioread32_and_clear(wil->csr +
411				     HOSTADDR(RGF_INT_GEN_TX_ICR) +
412				     offsetof(struct RGF_ICR, ICR));
413
414	trace_wil6210_irq_tx(isr);
415	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
416
417	if (unlikely(!isr)) {
418		wil_err(wil, "spurious IRQ: TX\n");
419		wil6210_unmask_irq_tx_edma(wil);
420		return IRQ_NONE;
421	}
422
423	if (likely(isr & BIT_TX_STATUS_IRQ)) {
424		wil_dbg_irq(wil, "TX status ring\n");
425		isr &= ~BIT_TX_STATUS_IRQ;
426		if (likely(test_bit(wil_status_fwready, wil->status))) {
427			wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
428			need_unmask = false;
429			napi_schedule(&wil->napi_tx);
430		} else {
431			wil_err(wil, "Got Tx status ring IRQ while in reset\n");
432		}
433	}
434
435	if (unlikely(isr))
436		wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
437
438	/* Tx IRQ will be enabled when NAPI processing finished */
439
440	atomic_inc(&wil->isr_count_tx);
441
442	if (unlikely(need_unmask))
443		wil6210_unmask_irq_tx_edma(wil);
444
445	return IRQ_HANDLED;
446}
447
448static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
449{
450	struct wil6210_priv *wil = cookie;
451	u32 isr;
452	bool need_unmask = true;
453
454	wil6210_mask_irq_tx(wil);
455
456	isr = wil_ioread32_and_clear(wil->csr +
457				     HOSTADDR(RGF_DMA_EP_TX_ICR) +
458				     offsetof(struct RGF_ICR, ICR));
459
460	trace_wil6210_irq_tx(isr);
461	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
462
463	if (unlikely(!isr)) {
464		wil_err_ratelimited(wil, "spurious IRQ: TX\n");
465		wil6210_unmask_irq_tx(wil);
466		return IRQ_NONE;
467	}
468
469	if (likely(isr & BIT_DMA_EP_TX_ICR_TX_DONE)) {
470		wil_dbg_irq(wil, "TX done\n");
471		isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
472		/* clear also all VRING interrupts */
473		isr &= ~(BIT(25) - 1UL);
474		if (likely(test_bit(wil_status_fwready, wil->status))) {
475			wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
476			need_unmask = false;
477			napi_schedule(&wil->napi_tx);
478		} else {
479			wil_err_ratelimited(wil, "Got Tx interrupt while in reset\n");
480		}
481	}
482
483	if (unlikely(isr))
484		wil_err_ratelimited(wil, "un-handled TX ISR bits 0x%08x\n",
485				    isr);
486
487	/* Tx IRQ will be enabled when NAPI processing finished */
488
489	atomic_inc(&wil->isr_count_tx);
490
491	if (unlikely(need_unmask))
492		wil6210_unmask_irq_tx(wil);
493
494	return IRQ_HANDLED;
495}
496
497static void wil_notify_fw_error(struct wil6210_priv *wil)
498{
499	struct device *dev = &wil->main_ndev->dev;
500	char *envp[3] = {
501		[0] = "SOURCE=wil6210",
502		[1] = "EVENT=FW_ERROR",
503		[2] = NULL,
504	};
505	wil_err(wil, "Notify about firmware error\n");
506	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
507}
508
509static void wil_cache_mbox_regs(struct wil6210_priv *wil)
510{
511	/* make shadow copy of registers that should not change on run time */
512	wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
513			     sizeof(struct wil6210_mbox_ctl));
514	wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
515	wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
516}
517
518static bool wil_validate_mbox_regs(struct wil6210_priv *wil)
519{
520	size_t min_size = sizeof(struct wil6210_mbox_hdr) +
521		sizeof(struct wmi_cmd_hdr);
522
523	if (wil->mbox_ctl.rx.entry_size < min_size) {
524		wil_err(wil, "rx mbox entry too small (%d)\n",
525			wil->mbox_ctl.rx.entry_size);
526		return false;
527	}
528	if (wil->mbox_ctl.tx.entry_size < min_size) {
529		wil_err(wil, "tx mbox entry too small (%d)\n",
530			wil->mbox_ctl.tx.entry_size);
531		return false;
532	}
533
534	return true;
535}
536
537static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
538{
539	struct wil6210_priv *wil = cookie;
540	u32 isr;
541
542	wil6210_mask_irq_misc(wil, false);
543
544	isr = wil_ioread32_and_clear(wil->csr +
545				     HOSTADDR(RGF_DMA_EP_MISC_ICR) +
546				     offsetof(struct RGF_ICR, ICR));
547
548	trace_wil6210_irq_misc(isr);
549	wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr);
550
551	if (!isr) {
552		wil_err(wil, "spurious IRQ: MISC\n");
553		wil6210_unmask_irq_misc(wil, false);
554		return IRQ_NONE;
555	}
556
557	if (isr & ISR_MISC_FW_ERROR) {
558		u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr);
559		u32 ucode_assert_code =
560			wil_r(wil, wil->rgf_ucode_assert_code_addr);
561
562		wil_err(wil,
563			"Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n",
564			fw_assert_code, ucode_assert_code);
565		clear_bit(wil_status_fwready, wil->status);
566		/*
567		 * do not clear @isr here - we do 2-nd part in thread
568		 * there, user space get notified, and it should be done
569		 * in non-atomic context
570		 */
571	}
572
573	if (isr & ISR_MISC_FW_READY) {
574		wil_dbg_irq(wil, "IRQ: FW ready\n");
575		wil_cache_mbox_regs(wil);
576		if (wil_validate_mbox_regs(wil))
577			set_bit(wil_status_mbox_ready, wil->status);
578		/**
579		 * Actual FW ready indicated by the
580		 * WMI_FW_READY_EVENTID
581		 */
582		isr &= ~ISR_MISC_FW_READY;
583	}
584
585	if (isr & BIT_DMA_EP_MISC_ICR_HALP) {
586		isr &= ~BIT_DMA_EP_MISC_ICR_HALP;
587		if (wil->halp.handle_icr) {
588			/* no need to handle HALP ICRs until next vote */
589			wil->halp.handle_icr = false;
590			wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
591			wil6210_mask_irq_misc(wil, true);
592			complete(&wil->halp.comp);
593		}
594	}
595
596	wil->isr_misc = isr;
597
598	if (isr) {
599		return IRQ_WAKE_THREAD;
600	} else {
601		wil6210_unmask_irq_misc(wil, false);
602		return IRQ_HANDLED;
603	}
604}
605
606static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
607{
608	struct wil6210_priv *wil = cookie;
609	u32 isr = wil->isr_misc;
610
611	trace_wil6210_irq_misc_thread(isr);
612	wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
613
614	if (isr & ISR_MISC_FW_ERROR) {
615		wil->recovery_state = fw_recovery_pending;
616		wil_fw_core_dump(wil);
617		wil_notify_fw_error(wil);
618		isr &= ~ISR_MISC_FW_ERROR;
619		if (wil->platform_ops.notify) {
620			wil_err(wil, "notify platform driver about FW crash");
621			wil->platform_ops.notify(wil->platform_handle,
622						 WIL_PLATFORM_EVT_FW_CRASH);
623		} else {
624			wil_fw_error_recovery(wil);
625		}
626	}
627	if (isr & ISR_MISC_MBOX_EVT) {
628		wil_dbg_irq(wil, "MBOX event\n");
629		wmi_recv_cmd(wil);
630		isr &= ~ISR_MISC_MBOX_EVT;
631	}
632
633	if (isr)
634		wil_dbg_irq(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
635
636	wil->isr_misc = 0;
637
638	wil6210_unmask_irq_misc(wil, false);
639
640	/* in non-triple MSI case, this is done inside wil6210_thread_irq
641	 * because it has to be done after unmasking the pseudo.
642	 */
643	if (wil->n_msi == 3 && wil->suspend_resp_rcvd) {
644		wil_dbg_irq(wil, "set suspend_resp_comp to true\n");
645		wil->suspend_resp_comp = true;
646		wake_up_interruptible(&wil->wq);
647	}
648
649	return IRQ_HANDLED;
650}
651
652/* thread IRQ handler */
653static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
654{
655	struct wil6210_priv *wil = cookie;
656
657	wil_dbg_irq(wil, "Thread IRQ\n");
658	/* Discover real IRQ cause */
659	if (wil->isr_misc)
660		wil6210_irq_misc_thread(irq, cookie);
661
662	wil6210_unmask_irq_pseudo(wil);
663
664	if (wil->suspend_resp_rcvd) {
665		wil_dbg_irq(wil, "set suspend_resp_comp to true\n");
666		wil->suspend_resp_comp = true;
667		wake_up_interruptible(&wil->wq);
668	}
669
670	return IRQ_HANDLED;
671}
672
673/* DEBUG
674 * There is subtle bug in hardware that causes IRQ to raise when it should be
675 * masked. It is quite rare and hard to debug.
676 *
677 * Catch irq issue if it happens and print all I can.
678 */
679static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
680{
681	u32 icm_rx, icr_rx, imv_rx;
682	u32 icm_tx, icr_tx, imv_tx;
683	u32 icm_misc, icr_misc, imv_misc;
684
685	if (!test_bit(wil_status_irqen, wil->status)) {
686		if (wil->use_enhanced_dma_hw) {
687			icm_rx = wil_ioread32_and_clear(wil->csr +
688					HOSTADDR(RGF_INT_GEN_RX_ICR) +
689					offsetof(struct RGF_ICR, ICM));
690			icr_rx = wil_ioread32_and_clear(wil->csr +
691					HOSTADDR(RGF_INT_GEN_RX_ICR) +
692					offsetof(struct RGF_ICR, ICR));
693			imv_rx = wil_r(wil, RGF_INT_GEN_RX_ICR +
694				   offsetof(struct RGF_ICR, IMV));
695			icm_tx = wil_ioread32_and_clear(wil->csr +
696					HOSTADDR(RGF_INT_GEN_TX_ICR) +
697					offsetof(struct RGF_ICR, ICM));
698			icr_tx = wil_ioread32_and_clear(wil->csr +
699					HOSTADDR(RGF_INT_GEN_TX_ICR) +
700					offsetof(struct RGF_ICR, ICR));
701			imv_tx = wil_r(wil, RGF_INT_GEN_TX_ICR +
702					   offsetof(struct RGF_ICR, IMV));
703		} else {
704			icm_rx = wil_ioread32_and_clear(wil->csr +
705					HOSTADDR(RGF_DMA_EP_RX_ICR) +
706					offsetof(struct RGF_ICR, ICM));
707			icr_rx = wil_ioread32_and_clear(wil->csr +
708					HOSTADDR(RGF_DMA_EP_RX_ICR) +
709					offsetof(struct RGF_ICR, ICR));
710			imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR +
711				   offsetof(struct RGF_ICR, IMV));
712			icm_tx = wil_ioread32_and_clear(wil->csr +
713					HOSTADDR(RGF_DMA_EP_TX_ICR) +
714					offsetof(struct RGF_ICR, ICM));
715			icr_tx = wil_ioread32_and_clear(wil->csr +
716					HOSTADDR(RGF_DMA_EP_TX_ICR) +
717					offsetof(struct RGF_ICR, ICR));
718			imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR +
719					   offsetof(struct RGF_ICR, IMV));
720		}
721		icm_misc = wil_ioread32_and_clear(wil->csr +
722				HOSTADDR(RGF_DMA_EP_MISC_ICR) +
723				offsetof(struct RGF_ICR, ICM));
724		icr_misc = wil_ioread32_and_clear(wil->csr +
725				HOSTADDR(RGF_DMA_EP_MISC_ICR) +
726				offsetof(struct RGF_ICR, ICR));
727		imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR +
728				     offsetof(struct RGF_ICR, IMV));
729
730		/* HALP interrupt can be unmasked when misc interrupts are
731		 * masked
732		 */
733		if (icr_misc & BIT_DMA_EP_MISC_ICR_HALP)
734			return 0;
735
736		wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n"
737				"Rx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
738				"Tx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
739				"Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n",
740				pseudo_cause,
741				icm_rx, icr_rx, imv_rx,
742				icm_tx, icr_tx, imv_tx,
743				icm_misc, icr_misc, imv_misc);
744
745		return -EINVAL;
746	}
747
748	return 0;
749}
750
751static irqreturn_t wil6210_hardirq(int irq, void *cookie)
752{
753	irqreturn_t rc = IRQ_HANDLED;
754	struct wil6210_priv *wil = cookie;
755	u32 pseudo_cause = wil_r(wil, RGF_DMA_PSEUDO_CAUSE);
756
757	/**
758	 * pseudo_cause is Clear-On-Read, no need to ACK
759	 */
760	if (unlikely((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)))
761		return IRQ_NONE;
762
763	/* IRQ mask debug */
764	if (unlikely(wil6210_debug_irq_mask(wil, pseudo_cause)))
765		return IRQ_NONE;
766
767	trace_wil6210_irq_pseudo(pseudo_cause);
768	wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause);
769
770	wil6210_mask_irq_pseudo(wil);
771
772	/* Discover real IRQ cause
773	 * There are 2 possible phases for every IRQ:
774	 * - hard IRQ handler called right here
775	 * - threaded handler called later
776	 *
777	 * Hard IRQ handler reads and clears ISR.
778	 *
779	 * If threaded handler requested, hard IRQ handler
780	 * returns IRQ_WAKE_THREAD and saves ISR register value
781	 * for the threaded handler use.
782	 *
783	 * voting for wake thread - need at least 1 vote
784	 */
785	if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) &&
786	    (wil->txrx_ops.irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
787		rc = IRQ_WAKE_THREAD;
788
789	if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
790	    (wil->txrx_ops.irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
791		rc = IRQ_WAKE_THREAD;
792
793	if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) &&
794	    (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD))
795		rc = IRQ_WAKE_THREAD;
796
797	/* if thread is requested, it will unmask IRQ */
798	if (rc != IRQ_WAKE_THREAD)
799		wil6210_unmask_irq_pseudo(wil);
800
801	return rc;
802}
803
804static int wil6210_request_3msi(struct wil6210_priv *wil, int irq)
805{
806	int rc;
807
808	/* IRQ's are in the following order:
809	 * - Tx
810	 * - Rx
811	 * - Misc
812	 */
813	rc = request_irq(irq, wil->txrx_ops.irq_tx, IRQF_SHARED,
814			 WIL_NAME "_tx", wil);
815	if (rc)
816		return rc;
817
818	rc = request_irq(irq + 1, wil->txrx_ops.irq_rx, IRQF_SHARED,
819			 WIL_NAME "_rx", wil);
820	if (rc)
821		goto free0;
822
823	rc = request_threaded_irq(irq + 2, wil6210_irq_misc,
824				  wil6210_irq_misc_thread,
825				  IRQF_SHARED, WIL_NAME "_misc", wil);
826	if (rc)
827		goto free1;
828
829	return 0;
830free1:
831	free_irq(irq + 1, wil);
832free0:
833	free_irq(irq, wil);
834
835	return rc;
836}
837
838/* can't use wil_ioread32_and_clear because ICC value is not set yet */
839static inline void wil_clear32(void __iomem *addr)
840{
841	u32 x = readl(addr);
842
843	writel(x, addr);
844}
845
846void wil6210_clear_irq(struct wil6210_priv *wil)
847{
848	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
849		    offsetof(struct RGF_ICR, ICR));
850	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) +
851		    offsetof(struct RGF_ICR, ICR));
852	if (wil->use_enhanced_dma_hw) {
853		wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_RX_ICR) +
854			    offsetof(struct RGF_ICR, ICR));
855		wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) +
856			    offsetof(struct RGF_ICR, ICR));
857	}
858	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
859		    offsetof(struct RGF_ICR, ICR));
860	wmb(); /* make sure write completed */
861}
862
863void wil6210_set_halp(struct wil6210_priv *wil)
864{
865	wil_dbg_irq(wil, "set_halp\n");
866
867	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICS),
868	      BIT_DMA_EP_MISC_ICR_HALP);
869}
870
871void wil6210_clear_halp(struct wil6210_priv *wil)
872{
873	wil_dbg_irq(wil, "clear_halp\n");
874
875	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICR),
876	      BIT_DMA_EP_MISC_ICR_HALP);
877	wil6210_unmask_halp(wil);
878}
879
880int wil6210_init_irq(struct wil6210_priv *wil, int irq)
881{
882	int rc;
883
884	wil_dbg_misc(wil, "init_irq: %s, n_msi=%d\n",
885		     wil->n_msi ? "MSI" : "INTx", wil->n_msi);
886
887	if (wil->use_enhanced_dma_hw) {
888		wil->txrx_ops.irq_tx = wil6210_irq_tx_edma;
889		wil->txrx_ops.irq_rx = wil6210_irq_rx_edma;
890	} else {
891		wil->txrx_ops.irq_tx = wil6210_irq_tx;
892		wil->txrx_ops.irq_rx = wil6210_irq_rx;
893	}
894
895	if (wil->n_msi == 3)
896		rc = wil6210_request_3msi(wil, irq);
897	else
898		rc = request_threaded_irq(irq, wil6210_hardirq,
899					  wil6210_thread_irq,
900					  wil->n_msi ? 0 : IRQF_SHARED,
901					  WIL_NAME, wil);
902	return rc;
903}
904
905void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
906{
907	wil_dbg_misc(wil, "fini_irq:\n");
908
909	wil_mask_irq(wil);
910	free_irq(irq, wil);
911	if (wil->n_msi == 3) {
912		free_irq(irq + 1, wil);
913		free_irq(irq + 2, wil);
914	}
915}
~/ Read-only file preview.