xref: /openbmc/linux/drivers/net/wireless/ath/wil6210/interrupt.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
185630469SLior David // SPDX-License-Identifier: ISC
22be7d22fSVladimir Kondratiev /*
3af3db60aSLazar Alexei  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
4979c9d8dSMaya Erez  * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
52be7d22fSVladimir Kondratiev  */
62be7d22fSVladimir Kondratiev 
72be7d22fSVladimir Kondratiev #include <linux/interrupt.h>
82be7d22fSVladimir Kondratiev 
92be7d22fSVladimir Kondratiev #include "wil6210.h"
1098658095SVladimir Kondratiev #include "trace.h"
112be7d22fSVladimir Kondratiev 
12*9d1bb228SYang Shen /*
132be7d22fSVladimir Kondratiev  * Theory of operation:
142be7d22fSVladimir Kondratiev  *
152be7d22fSVladimir Kondratiev  * There is ISR pseudo-cause register,
162be7d22fSVladimir Kondratiev  * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE
172be7d22fSVladimir Kondratiev  * Its bits represents OR'ed bits from 3 real ISR registers:
182be7d22fSVladimir Kondratiev  * TX, RX, and MISC.
192be7d22fSVladimir Kondratiev  *
202be7d22fSVladimir Kondratiev  * Registers may be configured to either "write 1 to clear" or
212be7d22fSVladimir Kondratiev  * "clear on read" mode
222be7d22fSVladimir Kondratiev  *
232be7d22fSVladimir Kondratiev  * When handling interrupt, one have to mask/unmask interrupts for the
242be7d22fSVladimir Kondratiev  * real ISR registers, or hardware may malfunction.
252be7d22fSVladimir Kondratiev  *
262be7d22fSVladimir Kondratiev  */
272be7d22fSVladimir Kondratiev 
282be7d22fSVladimir Kondratiev #define WIL6210_IRQ_DISABLE		(0xFFFFFFFFUL)
29349214c1SMaya Erez #define WIL6210_IRQ_DISABLE_NO_HALP	(0xF7FFFFFFUL)
3040e391b4SVladimir Kondratiev #define WIL6210_IMC_RX		(BIT_DMA_EP_RX_ICR_RX_DONE | \
3140e391b4SVladimir Kondratiev 				 BIT_DMA_EP_RX_ICR_RX_HTRSH)
3254eaa8c6SMaya Erez #define WIL6210_IMC_RX_NO_RX_HTRSH (WIL6210_IMC_RX & \
3354eaa8c6SMaya Erez 				    (~(BIT_DMA_EP_RX_ICR_RX_HTRSH)))
342be7d22fSVladimir Kondratiev #define WIL6210_IMC_TX		(BIT_DMA_EP_TX_ICR_TX_DONE | \
352be7d22fSVladimir Kondratiev 				BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
369202d7b6SMaya Erez #define WIL6210_IMC_TX_EDMA		BIT_TX_STATUS_IRQ
377be13fc3SGidon Studinski #define WIL6210_IMC_RX_EDMA		BIT_RX_STATUS_IRQ
38349214c1SMaya Erez #define WIL6210_IMC_MISC_NO_HALP	(ISR_MISC_FW_READY | \
397269494eSVladimir Kondratiev 					 ISR_MISC_MBOX_EVT | \
407269494eSVladimir Kondratiev 					 ISR_MISC_FW_ERROR)
41349214c1SMaya Erez #define WIL6210_IMC_MISC		(WIL6210_IMC_MISC_NO_HALP | \
42349214c1SMaya Erez 					 BIT_DMA_EP_MISC_ICR_HALP)
432be7d22fSVladimir Kondratiev #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
442be7d22fSVladimir Kondratiev 					BIT_DMA_PSEUDO_CAUSE_TX | \
452be7d22fSVladimir Kondratiev 					BIT_DMA_PSEUDO_CAUSE_MISC))
462be7d22fSVladimir Kondratiev 
472be7d22fSVladimir Kondratiev #if defined(CONFIG_WIL6210_ISR_COR)
482be7d22fSVladimir Kondratiev /* configure to Clear-On-Read mode */
492be7d22fSVladimir Kondratiev #define WIL_ICR_ICC_VALUE	(0xFFFFFFFFUL)
50349214c1SMaya Erez #define WIL_ICR_ICC_MISC_VALUE	(0xF7FFFFFFUL)
512be7d22fSVladimir Kondratiev 
wil_icr_clear(u32 x,void __iomem * addr)522be7d22fSVladimir Kondratiev static inline void wil_icr_clear(u32 x, void __iomem *addr)
532be7d22fSVladimir Kondratiev {
542be7d22fSVladimir Kondratiev }
552be7d22fSVladimir Kondratiev #else /* defined(CONFIG_WIL6210_ISR_COR) */
562be7d22fSVladimir Kondratiev /* configure to Write-1-to-Clear mode */
572be7d22fSVladimir Kondratiev #define WIL_ICR_ICC_VALUE	(0UL)
58349214c1SMaya Erez #define WIL_ICR_ICC_MISC_VALUE	(0UL)
592be7d22fSVladimir Kondratiev 
wil_icr_clear(u32 x,void __iomem * addr)602be7d22fSVladimir Kondratiev static inline void wil_icr_clear(u32 x, void __iomem *addr)
612be7d22fSVladimir Kondratiev {
62b9eeb512SVladimir Kondratiev 	writel(x, addr);
632be7d22fSVladimir Kondratiev }
642be7d22fSVladimir Kondratiev #endif /* defined(CONFIG_WIL6210_ISR_COR) */
652be7d22fSVladimir Kondratiev 
wil_ioread32_and_clear(void __iomem * addr)662be7d22fSVladimir Kondratiev static inline u32 wil_ioread32_and_clear(void __iomem *addr)
672be7d22fSVladimir Kondratiev {
68b9eeb512SVladimir Kondratiev 	u32 x = readl(addr);
692be7d22fSVladimir Kondratiev 
702be7d22fSVladimir Kondratiev 	wil_icr_clear(x, addr);
712be7d22fSVladimir Kondratiev 
722be7d22fSVladimir Kondratiev 	return x;
732be7d22fSVladimir Kondratiev }
742be7d22fSVladimir Kondratiev 
wil6210_mask_irq_tx(struct wil6210_priv * wil)752be7d22fSVladimir Kondratiev static void wil6210_mask_irq_tx(struct wil6210_priv *wil)
762be7d22fSVladimir Kondratiev {
77b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMS),
78b9eeb512SVladimir Kondratiev 	      WIL6210_IRQ_DISABLE);
792be7d22fSVladimir Kondratiev }
802be7d22fSVladimir Kondratiev 
wil6210_mask_irq_tx_edma(struct wil6210_priv * wil)819202d7b6SMaya Erez static void wil6210_mask_irq_tx_edma(struct wil6210_priv *wil)
829202d7b6SMaya Erez {
839202d7b6SMaya Erez 	wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMS),
849202d7b6SMaya Erez 	      WIL6210_IRQ_DISABLE);
859202d7b6SMaya Erez }
869202d7b6SMaya Erez 
wil6210_mask_irq_rx(struct wil6210_priv * wil)872be7d22fSVladimir Kondratiev static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
882be7d22fSVladimir Kondratiev {
89b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMS),
90b9eeb512SVladimir Kondratiev 	      WIL6210_IRQ_DISABLE);
912be7d22fSVladimir Kondratiev }
922be7d22fSVladimir Kondratiev 
wil6210_mask_irq_rx_edma(struct wil6210_priv * wil)937be13fc3SGidon Studinski static void wil6210_mask_irq_rx_edma(struct wil6210_priv *wil)
947be13fc3SGidon Studinski {
957be13fc3SGidon Studinski 	wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMS),
967be13fc3SGidon Studinski 	      WIL6210_IRQ_DISABLE);
977be13fc3SGidon Studinski }
987be13fc3SGidon Studinski 
wil6210_mask_irq_misc(struct wil6210_priv * wil,bool mask_halp)99349214c1SMaya Erez static void wil6210_mask_irq_misc(struct wil6210_priv *wil, bool mask_halp)
1002be7d22fSVladimir Kondratiev {
101af3db60aSLazar Alexei 	wil_dbg_irq(wil, "mask_irq_misc: mask_halp(%s)\n",
102349214c1SMaya Erez 		    mask_halp ? "true" : "false");
103349214c1SMaya Erez 
104b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS),
105349214c1SMaya Erez 	      mask_halp ? WIL6210_IRQ_DISABLE : WIL6210_IRQ_DISABLE_NO_HALP);
106349214c1SMaya Erez }
107349214c1SMaya Erez 
wil6210_mask_halp(struct wil6210_priv * wil)108f1b7764fSMaya Erez void wil6210_mask_halp(struct wil6210_priv *wil)
109349214c1SMaya Erez {
110af3db60aSLazar Alexei 	wil_dbg_irq(wil, "mask_halp\n");
111349214c1SMaya Erez 
112349214c1SMaya Erez 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS),
113349214c1SMaya Erez 	      BIT_DMA_EP_MISC_ICR_HALP);
1142be7d22fSVladimir Kondratiev }
1152be7d22fSVladimir Kondratiev 
wil6210_mask_irq_pseudo(struct wil6210_priv * wil)1162be7d22fSVladimir Kondratiev static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
1172be7d22fSVladimir Kondratiev {
118af3db60aSLazar Alexei 	wil_dbg_irq(wil, "mask_irq_pseudo\n");
1192be7d22fSVladimir Kondratiev 
120b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_DISABLE);
1212be7d22fSVladimir Kondratiev 
1229419b6a2SVladimir Kondratiev 	clear_bit(wil_status_irqen, wil->status);
1232be7d22fSVladimir Kondratiev }
1242be7d22fSVladimir Kondratiev 
wil6210_unmask_irq_tx(struct wil6210_priv * wil)125e0287c4aSVladimir Kondratiev void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
1262be7d22fSVladimir Kondratiev {
127b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMC),
128b9eeb512SVladimir Kondratiev 	      WIL6210_IMC_TX);
1292be7d22fSVladimir Kondratiev }
1302be7d22fSVladimir Kondratiev 
wil6210_unmask_irq_tx_edma(struct wil6210_priv * wil)1319202d7b6SMaya Erez void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil)
1329202d7b6SMaya Erez {
1339202d7b6SMaya Erez 	wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMC),
1349202d7b6SMaya Erez 	      WIL6210_IMC_TX_EDMA);
1359202d7b6SMaya Erez }
1369202d7b6SMaya Erez 
wil6210_unmask_irq_rx(struct wil6210_priv * wil)137e0287c4aSVladimir Kondratiev void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
1382be7d22fSVladimir Kondratiev {
1395bd60982SLior David 	bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0;
14054eaa8c6SMaya Erez 
141b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
14254eaa8c6SMaya Erez 	      unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
1432be7d22fSVladimir Kondratiev }
1442be7d22fSVladimir Kondratiev 
wil6210_unmask_irq_rx_edma(struct wil6210_priv * wil)1457be13fc3SGidon Studinski void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil)
1467be13fc3SGidon Studinski {
1477be13fc3SGidon Studinski 	wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMC),
1487be13fc3SGidon Studinski 	      WIL6210_IMC_RX_EDMA);
1497be13fc3SGidon Studinski }
1507be13fc3SGidon Studinski 
wil6210_unmask_irq_misc(struct wil6210_priv * wil,bool unmask_halp)151349214c1SMaya Erez static void wil6210_unmask_irq_misc(struct wil6210_priv *wil, bool unmask_halp)
1522be7d22fSVladimir Kondratiev {
153af3db60aSLazar Alexei 	wil_dbg_irq(wil, "unmask_irq_misc: unmask_halp(%s)\n",
154349214c1SMaya Erez 		    unmask_halp ? "true" : "false");
155349214c1SMaya Erez 
156b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC),
157349214c1SMaya Erez 	      unmask_halp ? WIL6210_IMC_MISC : WIL6210_IMC_MISC_NO_HALP);
158349214c1SMaya Erez }
159349214c1SMaya Erez 
wil6210_unmask_halp(struct wil6210_priv * wil)160349214c1SMaya Erez static void wil6210_unmask_halp(struct wil6210_priv *wil)
161349214c1SMaya Erez {
162af3db60aSLazar Alexei 	wil_dbg_irq(wil, "unmask_halp\n");
163349214c1SMaya Erez 
164349214c1SMaya Erez 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC),
165349214c1SMaya Erez 	      BIT_DMA_EP_MISC_ICR_HALP);
1662be7d22fSVladimir Kondratiev }
1672be7d22fSVladimir Kondratiev 
wil6210_unmask_irq_pseudo(struct wil6210_priv * wil)1682be7d22fSVladimir Kondratiev static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
1692be7d22fSVladimir Kondratiev {
170af3db60aSLazar Alexei 	wil_dbg_irq(wil, "unmask_irq_pseudo\n");
1712be7d22fSVladimir Kondratiev 
1729419b6a2SVladimir Kondratiev 	set_bit(wil_status_irqen, wil->status);
1732be7d22fSVladimir Kondratiev 
174b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_PSEUDO_MASK);
1752be7d22fSVladimir Kondratiev }
1762be7d22fSVladimir Kondratiev 
wil_mask_irq(struct wil6210_priv * wil)177e4dbb093SVladimir Kondratiev void wil_mask_irq(struct wil6210_priv *wil)
1782be7d22fSVladimir Kondratiev {
179af3db60aSLazar Alexei 	wil_dbg_irq(wil, "mask_irq\n");
1802be7d22fSVladimir Kondratiev 
1812be7d22fSVladimir Kondratiev 	wil6210_mask_irq_tx(wil);
1829202d7b6SMaya Erez 	wil6210_mask_irq_tx_edma(wil);
1832be7d22fSVladimir Kondratiev 	wil6210_mask_irq_rx(wil);
1847be13fc3SGidon Studinski 	wil6210_mask_irq_rx_edma(wil);
185349214c1SMaya Erez 	wil6210_mask_irq_misc(wil, true);
1862be7d22fSVladimir Kondratiev 	wil6210_mask_irq_pseudo(wil);
1872be7d22fSVladimir Kondratiev }
1882be7d22fSVladimir Kondratiev 
wil_unmask_irq(struct wil6210_priv * wil)189e4dbb093SVladimir Kondratiev void wil_unmask_irq(struct wil6210_priv *wil)
1902be7d22fSVladimir Kondratiev {
191af3db60aSLazar Alexei 	wil_dbg_irq(wil, "unmask_irq\n");
1922be7d22fSVladimir Kondratiev 
193b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC),
194b9eeb512SVladimir Kondratiev 	      WIL_ICR_ICC_VALUE);
195b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC),
196b9eeb512SVladimir Kondratiev 	      WIL_ICR_ICC_VALUE);
197b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC),
198349214c1SMaya Erez 	      WIL_ICR_ICC_MISC_VALUE);
1999202d7b6SMaya Erez 	wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, ICC),
2009202d7b6SMaya Erez 	      WIL_ICR_ICC_VALUE);
2017be13fc3SGidon Studinski 	wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, ICC),
2027be13fc3SGidon Studinski 	      WIL_ICR_ICC_VALUE);
2032be7d22fSVladimir Kondratiev 
2042be7d22fSVladimir Kondratiev 	wil6210_unmask_irq_pseudo(wil);
2059202d7b6SMaya Erez 	if (wil->use_enhanced_dma_hw) {
2069202d7b6SMaya Erez 		wil6210_unmask_irq_tx_edma(wil);
2077be13fc3SGidon Studinski 		wil6210_unmask_irq_rx_edma(wil);
2089202d7b6SMaya Erez 	} else {
2092be7d22fSVladimir Kondratiev 		wil6210_unmask_irq_tx(wil);
2102be7d22fSVladimir Kondratiev 		wil6210_unmask_irq_rx(wil);
2119202d7b6SMaya Erez 	}
212349214c1SMaya Erez 	wil6210_unmask_irq_misc(wil, true);
2132be7d22fSVladimir Kondratiev }
2142be7d22fSVladimir Kondratiev 
wil_configure_interrupt_moderation_edma(struct wil6210_priv * wil)21596c93589SGidon Studinski void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil)
21696c93589SGidon Studinski {
21796c93589SGidon Studinski 	u32 moderation;
21896c93589SGidon Studinski 
21996c93589SGidon Studinski 	wil_s(wil, RGF_INT_GEN_IDLE_TIME_LIMIT, WIL_EDMA_IDLE_TIME_LIMIT_USEC);
22096c93589SGidon Studinski 
22196c93589SGidon Studinski 	wil_s(wil, RGF_INT_GEN_TIME_UNIT_LIMIT, WIL_EDMA_TIME_UNIT_CLK_CYCLES);
22296c93589SGidon Studinski 
22396c93589SGidon Studinski 	/* Update RX and TX moderation */
22496c93589SGidon Studinski 	moderation = wil->rx_max_burst_duration |
22596c93589SGidon Studinski 		(WIL_EDMA_AGG_WATERMARK << WIL_EDMA_AGG_WATERMARK_POS);
22696c93589SGidon Studinski 	wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_0, moderation);
22796c93589SGidon Studinski 	wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_1, moderation);
22896c93589SGidon Studinski 
22996c93589SGidon Studinski 	/* Treat special events as regular
23096c93589SGidon Studinski 	 * (set bit 0 to 0x1 and clear bits 1-8)
23196c93589SGidon Studinski 	 */
23296c93589SGidon Studinski 	wil_c(wil, RGF_INT_COUNT_ON_SPECIAL_EVT, 0x1FE);
23396c93589SGidon Studinski 	wil_s(wil, RGF_INT_COUNT_ON_SPECIAL_EVT, 0x1);
23496c93589SGidon Studinski }
23596c93589SGidon Studinski 
wil_configure_interrupt_moderation(struct wil6210_priv * wil)2369a5511b5SVladimir Kondratiev void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
23778366f69SVladimir Kondratiev {
238e00243faSLior David 	struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
239e00243faSLior David 
240af3db60aSLazar Alexei 	wil_dbg_irq(wil, "configure_interrupt_moderation\n");
2419a5511b5SVladimir Kondratiev 
2429a5511b5SVladimir Kondratiev 	/* disable interrupt moderation for monitor
2439a5511b5SVladimir Kondratiev 	 * to get better timestamp precision
2449a5511b5SVladimir Kondratiev 	 */
245e00243faSLior David 	if (wdev->iftype == NL80211_IFTYPE_MONITOR)
2469a5511b5SVladimir Kondratiev 		return;
2479a5511b5SVladimir Kondratiev 
24878366f69SVladimir Kondratiev 	/* Disable and clear tx counter before (re)configuration */
249b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR);
250b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration);
25178366f69SVladimir Kondratiev 	wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n",
25278366f69SVladimir Kondratiev 		 wil->tx_max_burst_duration);
25378366f69SVladimir Kondratiev 	/* Configure TX max burst duration timer to use usec units */
254b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL,
25578366f69SVladimir Kondratiev 	      BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL);
25678366f69SVladimir Kondratiev 
25778366f69SVladimir Kondratiev 	/* Disable and clear tx idle counter before (re)configuration */
258b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR);
259b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout);
26078366f69SVladimir Kondratiev 	wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n",
26178366f69SVladimir Kondratiev 		 wil->tx_interframe_timeout);
26278366f69SVladimir Kondratiev 	/* Configure TX max burst duration timer to use usec units */
263b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN |
26478366f69SVladimir Kondratiev 	      BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL);
26578366f69SVladimir Kondratiev 
26678366f69SVladimir Kondratiev 	/* Disable and clear rx counter before (re)configuration */
267b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR);
268b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration);
26978366f69SVladimir Kondratiev 	wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n",
27078366f69SVladimir Kondratiev 		 wil->rx_max_burst_duration);
27178366f69SVladimir Kondratiev 	/* Configure TX max burst duration timer to use usec units */
272b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL,
27378366f69SVladimir Kondratiev 	      BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL);
27478366f69SVladimir Kondratiev 
27578366f69SVladimir Kondratiev 	/* Disable and clear rx idle counter before (re)configuration */
276b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR);
277b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout);
27878366f69SVladimir Kondratiev 	wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n",
27978366f69SVladimir Kondratiev 		 wil->rx_interframe_timeout);
28078366f69SVladimir Kondratiev 	/* Configure TX max burst duration timer to use usec units */
281b9eeb512SVladimir Kondratiev 	wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN |
28278366f69SVladimir Kondratiev 	      BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL);
28378366f69SVladimir Kondratiev }
28478366f69SVladimir Kondratiev 
wil6210_irq_rx(int irq,void * cookie)2852be7d22fSVladimir Kondratiev static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
2862be7d22fSVladimir Kondratiev {
2872be7d22fSVladimir Kondratiev 	struct wil6210_priv *wil = cookie;
288e10b0eddSMaya Erez 	u32 isr;
289e10b0eddSMaya Erez 	bool need_unmask = true;
290e10b0eddSMaya Erez 
291e10b0eddSMaya Erez 	wil6210_mask_irq_rx(wil);
292e10b0eddSMaya Erez 
293e10b0eddSMaya Erez 	isr = wil_ioread32_and_clear(wil->csr +
2942be7d22fSVladimir Kondratiev 				     HOSTADDR(RGF_DMA_EP_RX_ICR) +
2952be7d22fSVladimir Kondratiev 				     offsetof(struct RGF_ICR, ICR));
2962be7d22fSVladimir Kondratiev 
29798658095SVladimir Kondratiev 	trace_wil6210_irq_rx(isr);
2987743882dSVladimir Kondratiev 	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
2992be7d22fSVladimir Kondratiev 
30033c477fdSVladimir Kondratiev 	if (unlikely(!isr)) {
30140cbd88bSLior David 		wil_err_ratelimited(wil, "spurious IRQ: RX\n");
302e10b0eddSMaya Erez 		wil6210_unmask_irq_rx(wil);
3032be7d22fSVladimir Kondratiev 		return IRQ_NONE;
3042be7d22fSVladimir Kondratiev 	}
3052be7d22fSVladimir Kondratiev 
30640e391b4SVladimir Kondratiev 	/* RX_DONE and RX_HTRSH interrupts are the same if interrupt
30740e391b4SVladimir Kondratiev 	 * moderation is not used. Interrupt moderation may cause RX
30840e391b4SVladimir Kondratiev 	 * buffer overflow while RX_DONE is delayed. The required
30940e391b4SVladimir Kondratiev 	 * action is always the same - should empty the accumulated
31040e391b4SVladimir Kondratiev 	 * packets from the RX ring.
31140e391b4SVladimir Kondratiev 	 */
31233c477fdSVladimir Kondratiev 	if (likely(isr & (BIT_DMA_EP_RX_ICR_RX_DONE |
31333c477fdSVladimir Kondratiev 			  BIT_DMA_EP_RX_ICR_RX_HTRSH))) {
314b523d35bSMaya Erez 		wil_dbg_irq(wil, "RX done / RX_HTRSH received, ISR (0x%x)\n",
315b523d35bSMaya Erez 			    isr);
31640e391b4SVladimir Kondratiev 
3171aeda13bSVladimir Kondratiev 		isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE |
3181aeda13bSVladimir Kondratiev 			 BIT_DMA_EP_RX_ICR_RX_HTRSH);
319817f1853SVladimir Kondratiev 		if (likely(test_bit(wil_status_fwready, wil->status))) {
32033c477fdSVladimir Kondratiev 			if (likely(test_bit(wil_status_napi_en, wil->status))) {
3210fef1818SVladimir Kondratiev 				wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
32240e391b4SVladimir Kondratiev 				need_unmask = false;
323e0287c4aSVladimir Kondratiev 				napi_schedule(&wil->napi_rx);
3240fef1818SVladimir Kondratiev 			} else {
32540cbd88bSLior David 				wil_err_ratelimited(
32640cbd88bSLior David 					wil,
3271aeda13bSVladimir Kondratiev 					"Got Rx interrupt while stopping interface\n");
32873d839aeSVladimir Kondratiev 			}
32973d839aeSVladimir Kondratiev 		} else {
33040cbd88bSLior David 			wil_err_ratelimited(wil, "Got Rx interrupt while in reset\n");
3310fef1818SVladimir Kondratiev 		}
3322be7d22fSVladimir Kondratiev 	}
3332be7d22fSVladimir Kondratiev 
33433c477fdSVladimir Kondratiev 	if (unlikely(isr))
3352be7d22fSVladimir Kondratiev 		wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
3362be7d22fSVladimir Kondratiev 
337e0287c4aSVladimir Kondratiev 	/* Rx IRQ will be enabled when NAPI processing finished */
3382be7d22fSVladimir Kondratiev 
339be299858SVladimir Kondratiev 	atomic_inc(&wil->isr_count_rx);
34040e391b4SVladimir Kondratiev 
34140e391b4SVladimir Kondratiev 	if (unlikely(need_unmask))
34240e391b4SVladimir Kondratiev 		wil6210_unmask_irq_rx(wil);
34340e391b4SVladimir Kondratiev 
3442be7d22fSVladimir Kondratiev 	return IRQ_HANDLED;
3452be7d22fSVladimir Kondratiev }
3462be7d22fSVladimir Kondratiev 
wil6210_irq_rx_edma(int irq,void * cookie)3477be13fc3SGidon Studinski static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie)
3487be13fc3SGidon Studinski {
3497be13fc3SGidon Studinski 	struct wil6210_priv *wil = cookie;
350e10b0eddSMaya Erez 	u32 isr;
351e10b0eddSMaya Erez 	bool need_unmask = true;
352e10b0eddSMaya Erez 
353e10b0eddSMaya Erez 	wil6210_mask_irq_rx_edma(wil);
354e10b0eddSMaya Erez 
355e10b0eddSMaya Erez 	isr = wil_ioread32_and_clear(wil->csr +
3567be13fc3SGidon Studinski 				     HOSTADDR(RGF_INT_GEN_RX_ICR) +
3577be13fc3SGidon Studinski 				     offsetof(struct RGF_ICR, ICR));
3587be13fc3SGidon Studinski 
3597be13fc3SGidon Studinski 	trace_wil6210_irq_rx(isr);
3607be13fc3SGidon Studinski 	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
3617be13fc3SGidon Studinski 
3627be13fc3SGidon Studinski 	if (unlikely(!isr)) {
3637be13fc3SGidon Studinski 		wil_err(wil, "spurious IRQ: RX\n");
364e10b0eddSMaya Erez 		wil6210_unmask_irq_rx_edma(wil);
3657be13fc3SGidon Studinski 		return IRQ_NONE;
3667be13fc3SGidon Studinski 	}
3677be13fc3SGidon Studinski 
3687be13fc3SGidon Studinski 	if (likely(isr & BIT_RX_STATUS_IRQ)) {
3697be13fc3SGidon Studinski 		wil_dbg_irq(wil, "RX status ring\n");
3707be13fc3SGidon Studinski 		isr &= ~BIT_RX_STATUS_IRQ;
3717be13fc3SGidon Studinski 		if (likely(test_bit(wil_status_fwready, wil->status))) {
3727be13fc3SGidon Studinski 			if (likely(test_bit(wil_status_napi_en, wil->status))) {
3737be13fc3SGidon Studinski 				wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
3747be13fc3SGidon Studinski 				need_unmask = false;
3757be13fc3SGidon Studinski 				napi_schedule(&wil->napi_rx);
3767be13fc3SGidon Studinski 			} else {
3777be13fc3SGidon Studinski 				wil_err(wil,
3787be13fc3SGidon Studinski 					"Got Rx interrupt while stopping interface\n");
3797be13fc3SGidon Studinski 			}
3807be13fc3SGidon Studinski 		} else {
3817be13fc3SGidon Studinski 			wil_err(wil, "Got Rx interrupt while in reset\n");
3827be13fc3SGidon Studinski 		}
3837be13fc3SGidon Studinski 	}
3847be13fc3SGidon Studinski 
3857be13fc3SGidon Studinski 	if (unlikely(isr))
3867be13fc3SGidon Studinski 		wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
3877be13fc3SGidon Studinski 
3887be13fc3SGidon Studinski 	/* Rx IRQ will be enabled when NAPI processing finished */
3897be13fc3SGidon Studinski 
3907be13fc3SGidon Studinski 	atomic_inc(&wil->isr_count_rx);
3917be13fc3SGidon Studinski 
3927be13fc3SGidon Studinski 	if (unlikely(need_unmask))
3937be13fc3SGidon Studinski 		wil6210_unmask_irq_rx_edma(wil);
3947be13fc3SGidon Studinski 
3957be13fc3SGidon Studinski 	return IRQ_HANDLED;
3967be13fc3SGidon Studinski }
3977be13fc3SGidon Studinski 
wil6210_irq_tx_edma(int irq,void * cookie)3989202d7b6SMaya Erez static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie)
3999202d7b6SMaya Erez {
4009202d7b6SMaya Erez 	struct wil6210_priv *wil = cookie;
401e10b0eddSMaya Erez 	u32 isr;
402e10b0eddSMaya Erez 	bool need_unmask = true;
403e10b0eddSMaya Erez 
404e10b0eddSMaya Erez 	wil6210_mask_irq_tx_edma(wil);
405e10b0eddSMaya Erez 
406e10b0eddSMaya Erez 	isr = wil_ioread32_and_clear(wil->csr +
4079202d7b6SMaya Erez 				     HOSTADDR(RGF_INT_GEN_TX_ICR) +
4089202d7b6SMaya Erez 				     offsetof(struct RGF_ICR, ICR));
4099202d7b6SMaya Erez 
4109202d7b6SMaya Erez 	trace_wil6210_irq_tx(isr);
4119202d7b6SMaya Erez 	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
4129202d7b6SMaya Erez 
4139202d7b6SMaya Erez 	if (unlikely(!isr)) {
4149202d7b6SMaya Erez 		wil_err(wil, "spurious IRQ: TX\n");
415e10b0eddSMaya Erez 		wil6210_unmask_irq_tx_edma(wil);
4169202d7b6SMaya Erez 		return IRQ_NONE;
4179202d7b6SMaya Erez 	}
4189202d7b6SMaya Erez 
4199202d7b6SMaya Erez 	if (likely(isr & BIT_TX_STATUS_IRQ)) {
4209202d7b6SMaya Erez 		wil_dbg_irq(wil, "TX status ring\n");
4219202d7b6SMaya Erez 		isr &= ~BIT_TX_STATUS_IRQ;
4229202d7b6SMaya Erez 		if (likely(test_bit(wil_status_fwready, wil->status))) {
4239202d7b6SMaya Erez 			wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
4249202d7b6SMaya Erez 			need_unmask = false;
4259202d7b6SMaya Erez 			napi_schedule(&wil->napi_tx);
4269202d7b6SMaya Erez 		} else {
4279202d7b6SMaya Erez 			wil_err(wil, "Got Tx status ring IRQ while in reset\n");
4289202d7b6SMaya Erez 		}
4299202d7b6SMaya Erez 	}
4309202d7b6SMaya Erez 
4319202d7b6SMaya Erez 	if (unlikely(isr))
4329202d7b6SMaya Erez 		wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
4339202d7b6SMaya Erez 
4349202d7b6SMaya Erez 	/* Tx IRQ will be enabled when NAPI processing finished */
4359202d7b6SMaya Erez 
4369202d7b6SMaya Erez 	atomic_inc(&wil->isr_count_tx);
4379202d7b6SMaya Erez 
4389202d7b6SMaya Erez 	if (unlikely(need_unmask))
4399202d7b6SMaya Erez 		wil6210_unmask_irq_tx_edma(wil);
4409202d7b6SMaya Erez 
4419202d7b6SMaya Erez 	return IRQ_HANDLED;
4429202d7b6SMaya Erez }
4439202d7b6SMaya Erez 
wil6210_irq_tx(int irq,void * cookie)4442be7d22fSVladimir Kondratiev static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
4452be7d22fSVladimir Kondratiev {
4462be7d22fSVladimir Kondratiev 	struct wil6210_priv *wil = cookie;
447e10b0eddSMaya Erez 	u32 isr;
448e10b0eddSMaya Erez 	bool need_unmask = true;
449e10b0eddSMaya Erez 
450e10b0eddSMaya Erez 	wil6210_mask_irq_tx(wil);
451e10b0eddSMaya Erez 
452e10b0eddSMaya Erez 	isr = wil_ioread32_and_clear(wil->csr +
4532be7d22fSVladimir Kondratiev 				     HOSTADDR(RGF_DMA_EP_TX_ICR) +
4542be7d22fSVladimir Kondratiev 				     offsetof(struct RGF_ICR, ICR));
4552be7d22fSVladimir Kondratiev 
45698658095SVladimir Kondratiev 	trace_wil6210_irq_tx(isr);
4577743882dSVladimir Kondratiev 	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
4582be7d22fSVladimir Kondratiev 
45933c477fdSVladimir Kondratiev 	if (unlikely(!isr)) {
46040cbd88bSLior David 		wil_err_ratelimited(wil, "spurious IRQ: TX\n");
461e10b0eddSMaya Erez 		wil6210_unmask_irq_tx(wil);
4622be7d22fSVladimir Kondratiev 		return IRQ_NONE;
4632be7d22fSVladimir Kondratiev 	}
4642be7d22fSVladimir Kondratiev 
46533c477fdSVladimir Kondratiev 	if (likely(isr & BIT_DMA_EP_TX_ICR_TX_DONE)) {
4667743882dSVladimir Kondratiev 		wil_dbg_irq(wil, "TX done\n");
4672be7d22fSVladimir Kondratiev 		isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
468e0287c4aSVladimir Kondratiev 		/* clear also all VRING interrupts */
469e0287c4aSVladimir Kondratiev 		isr &= ~(BIT(25) - 1UL);
470817f1853SVladimir Kondratiev 		if (likely(test_bit(wil_status_fwready, wil->status))) {
4710fef1818SVladimir Kondratiev 			wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
47240e391b4SVladimir Kondratiev 			need_unmask = false;
4730fef1818SVladimir Kondratiev 			napi_schedule(&wil->napi_tx);
4740fef1818SVladimir Kondratiev 		} else {
47540cbd88bSLior David 			wil_err_ratelimited(wil, "Got Tx interrupt while in reset\n");
4760fef1818SVladimir Kondratiev 		}
4772be7d22fSVladimir Kondratiev 	}
4782be7d22fSVladimir Kondratiev 
47933c477fdSVladimir Kondratiev 	if (unlikely(isr))
48040cbd88bSLior David 		wil_err_ratelimited(wil, "un-handled TX ISR bits 0x%08x\n",
48140cbd88bSLior David 				    isr);
4822be7d22fSVladimir Kondratiev 
483e0287c4aSVladimir Kondratiev 	/* Tx IRQ will be enabled when NAPI processing finished */
4842be7d22fSVladimir Kondratiev 
485be299858SVladimir Kondratiev 	atomic_inc(&wil->isr_count_tx);
48640e391b4SVladimir Kondratiev 
48740e391b4SVladimir Kondratiev 	if (unlikely(need_unmask))
48840e391b4SVladimir Kondratiev 		wil6210_unmask_irq_tx(wil);
48940e391b4SVladimir Kondratiev 
4902be7d22fSVladimir Kondratiev 	return IRQ_HANDLED;
4912be7d22fSVladimir Kondratiev }
4922be7d22fSVladimir Kondratiev 
wil_notify_fw_error(struct wil6210_priv * wil)4937269494eSVladimir Kondratiev static void wil_notify_fw_error(struct wil6210_priv *wil)
4947269494eSVladimir Kondratiev {
495e00243faSLior David 	struct device *dev = &wil->main_ndev->dev;
4967269494eSVladimir Kondratiev 	char *envp[3] = {
4977269494eSVladimir Kondratiev 		[0] = "SOURCE=wil6210",
4987269494eSVladimir Kondratiev 		[1] = "EVENT=FW_ERROR",
4997269494eSVladimir Kondratiev 		[2] = NULL,
5007269494eSVladimir Kondratiev 	};
50192b6747eSVladimir Kondratiev 	wil_err(wil, "Notify about firmware error\n");
5027269494eSVladimir Kondratiev 	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
5037269494eSVladimir Kondratiev }
5047269494eSVladimir Kondratiev 
wil_cache_mbox_regs(struct wil6210_priv * wil)50555f7acddSVladimir Kondratiev static void wil_cache_mbox_regs(struct wil6210_priv *wil)
50655f7acddSVladimir Kondratiev {
50755f7acddSVladimir Kondratiev 	/* make shadow copy of registers that should not change on run time */
50855f7acddSVladimir Kondratiev 	wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
50955f7acddSVladimir Kondratiev 			     sizeof(struct wil6210_mbox_ctl));
51055f7acddSVladimir Kondratiev 	wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
51155f7acddSVladimir Kondratiev 	wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
51255f7acddSVladimir Kondratiev }
51355f7acddSVladimir Kondratiev 
wil_validate_mbox_regs(struct wil6210_priv * wil)51426a6d527SLior David static bool wil_validate_mbox_regs(struct wil6210_priv *wil)
51526a6d527SLior David {
51626a6d527SLior David 	size_t min_size = sizeof(struct wil6210_mbox_hdr) +
51726a6d527SLior David 		sizeof(struct wmi_cmd_hdr);
51826a6d527SLior David 
51926a6d527SLior David 	if (wil->mbox_ctl.rx.entry_size < min_size) {
52026a6d527SLior David 		wil_err(wil, "rx mbox entry too small (%d)\n",
52126a6d527SLior David 			wil->mbox_ctl.rx.entry_size);
52226a6d527SLior David 		return false;
52326a6d527SLior David 	}
52426a6d527SLior David 	if (wil->mbox_ctl.tx.entry_size < min_size) {
52526a6d527SLior David 		wil_err(wil, "tx mbox entry too small (%d)\n",
52626a6d527SLior David 			wil->mbox_ctl.tx.entry_size);
52726a6d527SLior David 		return false;
52826a6d527SLior David 	}
52926a6d527SLior David 
53026a6d527SLior David 	return true;
53126a6d527SLior David }
53226a6d527SLior David 
wil6210_irq_misc(int irq,void * cookie)5332be7d22fSVladimir Kondratiev static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
5342be7d22fSVladimir Kondratiev {
5352be7d22fSVladimir Kondratiev 	struct wil6210_priv *wil = cookie;
536e10b0eddSMaya Erez 	u32 isr;
537e10b0eddSMaya Erez 
538e10b0eddSMaya Erez 	wil6210_mask_irq_misc(wil, false);
539e10b0eddSMaya Erez 
540e10b0eddSMaya Erez 	isr = wil_ioread32_and_clear(wil->csr +
5412be7d22fSVladimir Kondratiev 				     HOSTADDR(RGF_DMA_EP_MISC_ICR) +
5422be7d22fSVladimir Kondratiev 				     offsetof(struct RGF_ICR, ICR));
5432be7d22fSVladimir Kondratiev 
54498658095SVladimir Kondratiev 	trace_wil6210_irq_misc(isr);
5457743882dSVladimir Kondratiev 	wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr);
5462be7d22fSVladimir Kondratiev 
5472be7d22fSVladimir Kondratiev 	if (!isr) {
5482be7d22fSVladimir Kondratiev 		wil_err(wil, "spurious IRQ: MISC\n");
549e10b0eddSMaya Erez 		wil6210_unmask_irq_misc(wil, false);
5502be7d22fSVladimir Kondratiev 		return IRQ_NONE;
5512be7d22fSVladimir Kondratiev 	}
5522be7d22fSVladimir Kondratiev 
5537269494eSVladimir Kondratiev 	if (isr & ISR_MISC_FW_ERROR) {
5544276d771SMaya Erez 		u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr);
5554276d771SMaya Erez 		u32 ucode_assert_code =
5564276d771SMaya Erez 			wil_r(wil, wil->rgf_ucode_assert_code_addr);
557bf2f6734SVladimir Kondratiev 
558bf2f6734SVladimir Kondratiev 		wil_err(wil,
559bf2f6734SVladimir Kondratiev 			"Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n",
560bf2f6734SVladimir Kondratiev 			fw_assert_code, ucode_assert_code);
5619419b6a2SVladimir Kondratiev 		clear_bit(wil_status_fwready, wil->status);
562de70ab87SVladimir Kondratiev 		/*
563de70ab87SVladimir Kondratiev 		 * do not clear @isr here - we do 2-nd part in thread
564de70ab87SVladimir Kondratiev 		 * there, user space get notified, and it should be done
565de70ab87SVladimir Kondratiev 		 * in non-atomic context
566de70ab87SVladimir Kondratiev 		 */
5677269494eSVladimir Kondratiev 	}
5687269494eSVladimir Kondratiev 
5692be7d22fSVladimir Kondratiev 	if (isr & ISR_MISC_FW_READY) {
5707743882dSVladimir Kondratiev 		wil_dbg_irq(wil, "IRQ: FW ready\n");
57155f7acddSVladimir Kondratiev 		wil_cache_mbox_regs(wil);
57226a6d527SLior David 		if (wil_validate_mbox_regs(wil))
573817f1853SVladimir Kondratiev 			set_bit(wil_status_mbox_ready, wil->status);
5742be7d22fSVladimir Kondratiev 		/**
5752be7d22fSVladimir Kondratiev 		 * Actual FW ready indicated by the
5762be7d22fSVladimir Kondratiev 		 * WMI_FW_READY_EVENTID
5772be7d22fSVladimir Kondratiev 		 */
5782be7d22fSVladimir Kondratiev 		isr &= ~ISR_MISC_FW_READY;
5792be7d22fSVladimir Kondratiev 	}
5802be7d22fSVladimir Kondratiev 
581349214c1SMaya Erez 	if (isr & BIT_DMA_EP_MISC_ICR_HALP) {
582979c9d8dSMaya Erez 		isr &= ~BIT_DMA_EP_MISC_ICR_HALP;
583979c9d8dSMaya Erez 		if (wil->halp.handle_icr) {
584979c9d8dSMaya Erez 			/* no need to handle HALP ICRs until next vote */
585979c9d8dSMaya Erez 			wil->halp.handle_icr = false;
586af3db60aSLazar Alexei 			wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n");
5877441be71SMaya Erez 			wil6210_mask_irq_misc(wil, true);
588349214c1SMaya Erez 			complete(&wil->halp.comp);
589349214c1SMaya Erez 		}
590979c9d8dSMaya Erez 	}
591349214c1SMaya Erez 
5922be7d22fSVladimir Kondratiev 	wil->isr_misc = isr;
5932be7d22fSVladimir Kondratiev 
5942be7d22fSVladimir Kondratiev 	if (isr) {
5952be7d22fSVladimir Kondratiev 		return IRQ_WAKE_THREAD;
5962be7d22fSVladimir Kondratiev 	} else {
597349214c1SMaya Erez 		wil6210_unmask_irq_misc(wil, false);
5982be7d22fSVladimir Kondratiev 		return IRQ_HANDLED;
5992be7d22fSVladimir Kondratiev 	}
6002be7d22fSVladimir Kondratiev }
6012be7d22fSVladimir Kondratiev 
wil6210_irq_misc_thread(int irq,void * cookie)6022be7d22fSVladimir Kondratiev static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
6032be7d22fSVladimir Kondratiev {
6042be7d22fSVladimir Kondratiev 	struct wil6210_priv *wil = cookie;
6052be7d22fSVladimir Kondratiev 	u32 isr = wil->isr_misc;
6062be7d22fSVladimir Kondratiev 
60798658095SVladimir Kondratiev 	trace_wil6210_irq_misc_thread(isr);
6087743882dSVladimir Kondratiev 	wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
6092be7d22fSVladimir Kondratiev 
610de70ab87SVladimir Kondratiev 	if (isr & ISR_MISC_FW_ERROR) {
611375a173fSLior David 		wil->recovery_state = fw_recovery_pending;
6127dc47258SVladimir Kondratiev 		wil_fw_core_dump(wil);
613de70ab87SVladimir Kondratiev 		wil_notify_fw_error(wil);
614de70ab87SVladimir Kondratiev 		isr &= ~ISR_MISC_FW_ERROR;
6155f0823efSMaya Erez 		if (wil->platform_ops.notify) {
616ea3ade75SLior David 			wil_err(wil, "notify platform driver about FW crash");
6175f0823efSMaya Erez 			wil->platform_ops.notify(wil->platform_handle,
6185f0823efSMaya Erez 						 WIL_PLATFORM_EVT_FW_CRASH);
619ea3ade75SLior David 		} else {
620ed6f9dc6SVladimir Kondratiev 			wil_fw_error_recovery(wil);
621de70ab87SVladimir Kondratiev 		}
622ea3ade75SLior David 	}
6232be7d22fSVladimir Kondratiev 	if (isr & ISR_MISC_MBOX_EVT) {
6247743882dSVladimir Kondratiev 		wil_dbg_irq(wil, "MBOX event\n");
6252be7d22fSVladimir Kondratiev 		wmi_recv_cmd(wil);
6262be7d22fSVladimir Kondratiev 		isr &= ~ISR_MISC_MBOX_EVT;
6272be7d22fSVladimir Kondratiev 	}
6282be7d22fSVladimir Kondratiev 
6292be7d22fSVladimir Kondratiev 	if (isr)
63015e23124SVladimir Kondratiev 		wil_dbg_irq(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
6312be7d22fSVladimir Kondratiev 
6322be7d22fSVladimir Kondratiev 	wil->isr_misc = 0;
6332be7d22fSVladimir Kondratiev 
634349214c1SMaya Erez 	wil6210_unmask_irq_misc(wil, false);
6352be7d22fSVladimir Kondratiev 
636aea2f8b7SAlexei Avshalom Lazar 	/* in non-triple MSI case, this is done inside wil6210_thread_irq
637aea2f8b7SAlexei Avshalom Lazar 	 * because it has to be done after unmasking the pseudo.
638aea2f8b7SAlexei Avshalom Lazar 	 */
639aea2f8b7SAlexei Avshalom Lazar 	if (wil->n_msi == 3 && wil->suspend_resp_rcvd) {
640aea2f8b7SAlexei Avshalom Lazar 		wil_dbg_irq(wil, "set suspend_resp_comp to true\n");
641aea2f8b7SAlexei Avshalom Lazar 		wil->suspend_resp_comp = true;
642aea2f8b7SAlexei Avshalom Lazar 		wake_up_interruptible(&wil->wq);
643aea2f8b7SAlexei Avshalom Lazar 	}
644aea2f8b7SAlexei Avshalom Lazar 
6452be7d22fSVladimir Kondratiev 	return IRQ_HANDLED;
6462be7d22fSVladimir Kondratiev }
6472be7d22fSVladimir Kondratiev 
648299ff6c6SLee Jones /* thread IRQ handler */
wil6210_thread_irq(int irq,void * cookie)6492be7d22fSVladimir Kondratiev static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
6502be7d22fSVladimir Kondratiev {
6512be7d22fSVladimir Kondratiev 	struct wil6210_priv *wil = cookie;
6522be7d22fSVladimir Kondratiev 
6537743882dSVladimir Kondratiev 	wil_dbg_irq(wil, "Thread IRQ\n");
6542be7d22fSVladimir Kondratiev 	/* Discover real IRQ cause */
6552be7d22fSVladimir Kondratiev 	if (wil->isr_misc)
6562be7d22fSVladimir Kondratiev 		wil6210_irq_misc_thread(irq, cookie);
6572be7d22fSVladimir Kondratiev 
6582be7d22fSVladimir Kondratiev 	wil6210_unmask_irq_pseudo(wil);
6592be7d22fSVladimir Kondratiev 
660fe9ee51eSMaya Erez 	if (wil->suspend_resp_rcvd) {
661fe9ee51eSMaya Erez 		wil_dbg_irq(wil, "set suspend_resp_comp to true\n");
662fe9ee51eSMaya Erez 		wil->suspend_resp_comp = true;
663fe9ee51eSMaya Erez 		wake_up_interruptible(&wil->wq);
664fe9ee51eSMaya Erez 	}
665fe9ee51eSMaya Erez 
6662be7d22fSVladimir Kondratiev 	return IRQ_HANDLED;
6672be7d22fSVladimir Kondratiev }
6682be7d22fSVladimir Kondratiev 
6692be7d22fSVladimir Kondratiev /* DEBUG
6702be7d22fSVladimir Kondratiev  * There is subtle bug in hardware that causes IRQ to raise when it should be
6712be7d22fSVladimir Kondratiev  * masked. It is quite rare and hard to debug.
6722be7d22fSVladimir Kondratiev  *
6732be7d22fSVladimir Kondratiev  * Catch irq issue if it happens and print all I can.
6742be7d22fSVladimir Kondratiev  */
wil6210_debug_irq_mask(struct wil6210_priv * wil,u32 pseudo_cause)6752be7d22fSVladimir Kondratiev static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
6762be7d22fSVladimir Kondratiev {
6777be13fc3SGidon Studinski 	u32 icm_rx, icr_rx, imv_rx;
6789202d7b6SMaya Erez 	u32 icm_tx, icr_tx, imv_tx;
6799202d7b6SMaya Erez 	u32 icm_misc, icr_misc, imv_misc;
6809202d7b6SMaya Erez 
6819419b6a2SVladimir Kondratiev 	if (!test_bit(wil_status_irqen, wil->status)) {
6829202d7b6SMaya Erez 		if (wil->use_enhanced_dma_hw) {
6837be13fc3SGidon Studinski 			icm_rx = wil_ioread32_and_clear(wil->csr +
6847be13fc3SGidon Studinski 					HOSTADDR(RGF_INT_GEN_RX_ICR) +
6857be13fc3SGidon Studinski 					offsetof(struct RGF_ICR, ICM));
6867be13fc3SGidon Studinski 			icr_rx = wil_ioread32_and_clear(wil->csr +
6877be13fc3SGidon Studinski 					HOSTADDR(RGF_INT_GEN_RX_ICR) +
6887be13fc3SGidon Studinski 					offsetof(struct RGF_ICR, ICR));
6897be13fc3SGidon Studinski 			imv_rx = wil_r(wil, RGF_INT_GEN_RX_ICR +
6907be13fc3SGidon Studinski 				   offsetof(struct RGF_ICR, IMV));
6919202d7b6SMaya Erez 			icm_tx = wil_ioread32_and_clear(wil->csr +
6929202d7b6SMaya Erez 					HOSTADDR(RGF_INT_GEN_TX_ICR) +
6939202d7b6SMaya Erez 					offsetof(struct RGF_ICR, ICM));
6949202d7b6SMaya Erez 			icr_tx = wil_ioread32_and_clear(wil->csr +
6959202d7b6SMaya Erez 					HOSTADDR(RGF_INT_GEN_TX_ICR) +
6969202d7b6SMaya Erez 					offsetof(struct RGF_ICR, ICR));
6979202d7b6SMaya Erez 			imv_tx = wil_r(wil, RGF_INT_GEN_TX_ICR +
6989202d7b6SMaya Erez 					   offsetof(struct RGF_ICR, IMV));
6999202d7b6SMaya Erez 		} else {
7009202d7b6SMaya Erez 			icm_rx = wil_ioread32_and_clear(wil->csr +
7012be7d22fSVladimir Kondratiev 					HOSTADDR(RGF_DMA_EP_RX_ICR) +
7022be7d22fSVladimir Kondratiev 					offsetof(struct RGF_ICR, ICM));
7039202d7b6SMaya Erez 			icr_rx = wil_ioread32_and_clear(wil->csr +
7042be7d22fSVladimir Kondratiev 					HOSTADDR(RGF_DMA_EP_RX_ICR) +
7052be7d22fSVladimir Kondratiev 					offsetof(struct RGF_ICR, ICR));
7069202d7b6SMaya Erez 			imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR +
7072be7d22fSVladimir Kondratiev 				   offsetof(struct RGF_ICR, IMV));
7089202d7b6SMaya Erez 			icm_tx = wil_ioread32_and_clear(wil->csr +
7092be7d22fSVladimir Kondratiev 					HOSTADDR(RGF_DMA_EP_TX_ICR) +
7102be7d22fSVladimir Kondratiev 					offsetof(struct RGF_ICR, ICM));
7119202d7b6SMaya Erez 			icr_tx = wil_ioread32_and_clear(wil->csr +
7122be7d22fSVladimir Kondratiev 					HOSTADDR(RGF_DMA_EP_TX_ICR) +
7132be7d22fSVladimir Kondratiev 					offsetof(struct RGF_ICR, ICR));
7149202d7b6SMaya Erez 			imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR +
7152be7d22fSVladimir Kondratiev 					   offsetof(struct RGF_ICR, IMV));
7169202d7b6SMaya Erez 		}
7179202d7b6SMaya Erez 		icm_misc = wil_ioread32_and_clear(wil->csr +
7182be7d22fSVladimir Kondratiev 				HOSTADDR(RGF_DMA_EP_MISC_ICR) +
7192be7d22fSVladimir Kondratiev 				offsetof(struct RGF_ICR, ICM));
7209202d7b6SMaya Erez 		icr_misc = wil_ioread32_and_clear(wil->csr +
7212be7d22fSVladimir Kondratiev 				HOSTADDR(RGF_DMA_EP_MISC_ICR) +
7222be7d22fSVladimir Kondratiev 				offsetof(struct RGF_ICR, ICR));
7239202d7b6SMaya Erez 		imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR +
7242be7d22fSVladimir Kondratiev 				     offsetof(struct RGF_ICR, IMV));
725f1b7764fSMaya Erez 
726f1b7764fSMaya Erez 		/* HALP interrupt can be unmasked when misc interrupts are
727f1b7764fSMaya Erez 		 * masked
728f1b7764fSMaya Erez 		 */
729f1b7764fSMaya Erez 		if (icr_misc & BIT_DMA_EP_MISC_ICR_HALP)
730f1b7764fSMaya Erez 			return 0;
731f1b7764fSMaya Erez 
7322be7d22fSVladimir Kondratiev 		wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n"
7332be7d22fSVladimir Kondratiev 				"Rx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
7342be7d22fSVladimir Kondratiev 				"Tx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
7352be7d22fSVladimir Kondratiev 				"Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n",
7362be7d22fSVladimir Kondratiev 				pseudo_cause,
7372be7d22fSVladimir Kondratiev 				icm_rx, icr_rx, imv_rx,
7382be7d22fSVladimir Kondratiev 				icm_tx, icr_tx, imv_tx,
7392be7d22fSVladimir Kondratiev 				icm_misc, icr_misc, imv_misc);
7402be7d22fSVladimir Kondratiev 
7412be7d22fSVladimir Kondratiev 		return -EINVAL;
7422be7d22fSVladimir Kondratiev 	}
7432be7d22fSVladimir Kondratiev 
7442be7d22fSVladimir Kondratiev 	return 0;
7452be7d22fSVladimir Kondratiev }
7462be7d22fSVladimir Kondratiev 
wil6210_hardirq(int irq,void * cookie)7472be7d22fSVladimir Kondratiev static irqreturn_t wil6210_hardirq(int irq, void *cookie)
7482be7d22fSVladimir Kondratiev {
7492be7d22fSVladimir Kondratiev 	irqreturn_t rc = IRQ_HANDLED;
7502be7d22fSVladimir Kondratiev 	struct wil6210_priv *wil = cookie;
751b9eeb512SVladimir Kondratiev 	u32 pseudo_cause = wil_r(wil, RGF_DMA_PSEUDO_CAUSE);
7522be7d22fSVladimir Kondratiev 
7532be7d22fSVladimir Kondratiev 	/**
7542be7d22fSVladimir Kondratiev 	 * pseudo_cause is Clear-On-Read, no need to ACK
7552be7d22fSVladimir Kondratiev 	 */
75633c477fdSVladimir Kondratiev 	if (unlikely((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)))
7572be7d22fSVladimir Kondratiev 		return IRQ_NONE;
7582be7d22fSVladimir Kondratiev 
75983957bc3SDedy Lansky 	/* IRQ mask debug */
76033c477fdSVladimir Kondratiev 	if (unlikely(wil6210_debug_irq_mask(wil, pseudo_cause)))
7612be7d22fSVladimir Kondratiev 		return IRQ_NONE;
7622be7d22fSVladimir Kondratiev 
76398658095SVladimir Kondratiev 	trace_wil6210_irq_pseudo(pseudo_cause);
7647743882dSVladimir Kondratiev 	wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause);
7654789d728SVladimir Kondratiev 
7662be7d22fSVladimir Kondratiev 	wil6210_mask_irq_pseudo(wil);
7672be7d22fSVladimir Kondratiev 
7682be7d22fSVladimir Kondratiev 	/* Discover real IRQ cause
7692be7d22fSVladimir Kondratiev 	 * There are 2 possible phases for every IRQ:
7702be7d22fSVladimir Kondratiev 	 * - hard IRQ handler called right here
7712be7d22fSVladimir Kondratiev 	 * - threaded handler called later
7722be7d22fSVladimir Kondratiev 	 *
7732be7d22fSVladimir Kondratiev 	 * Hard IRQ handler reads and clears ISR.
7742be7d22fSVladimir Kondratiev 	 *
7752be7d22fSVladimir Kondratiev 	 * If threaded handler requested, hard IRQ handler
7762be7d22fSVladimir Kondratiev 	 * returns IRQ_WAKE_THREAD and saves ISR register value
7772be7d22fSVladimir Kondratiev 	 * for the threaded handler use.
7782be7d22fSVladimir Kondratiev 	 *
7792be7d22fSVladimir Kondratiev 	 * voting for wake thread - need at least 1 vote
7802be7d22fSVladimir Kondratiev 	 */
7812be7d22fSVladimir Kondratiev 	if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) &&
7827be13fc3SGidon Studinski 	    (wil->txrx_ops.irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
7832be7d22fSVladimir Kondratiev 		rc = IRQ_WAKE_THREAD;
7842be7d22fSVladimir Kondratiev 
7852be7d22fSVladimir Kondratiev 	if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
7869202d7b6SMaya Erez 	    (wil->txrx_ops.irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
7872be7d22fSVladimir Kondratiev 		rc = IRQ_WAKE_THREAD;
7882be7d22fSVladimir Kondratiev 
7892be7d22fSVladimir Kondratiev 	if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) &&
7902be7d22fSVladimir Kondratiev 	    (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD))
7912be7d22fSVladimir Kondratiev 		rc = IRQ_WAKE_THREAD;
7922be7d22fSVladimir Kondratiev 
7932be7d22fSVladimir Kondratiev 	/* if thread is requested, it will unmask IRQ */
7942be7d22fSVladimir Kondratiev 	if (rc != IRQ_WAKE_THREAD)
7952be7d22fSVladimir Kondratiev 		wil6210_unmask_irq_pseudo(wil);
7962be7d22fSVladimir Kondratiev 
7972be7d22fSVladimir Kondratiev 	return rc;
7982be7d22fSVladimir Kondratiev }
7992be7d22fSVladimir Kondratiev 
wil6210_request_3msi(struct wil6210_priv * wil,int irq)800aea2f8b7SAlexei Avshalom Lazar static int wil6210_request_3msi(struct wil6210_priv *wil, int irq)
801aea2f8b7SAlexei Avshalom Lazar {
802aea2f8b7SAlexei Avshalom Lazar 	int rc;
803aea2f8b7SAlexei Avshalom Lazar 
804aea2f8b7SAlexei Avshalom Lazar 	/* IRQ's are in the following order:
805aea2f8b7SAlexei Avshalom Lazar 	 * - Tx
806aea2f8b7SAlexei Avshalom Lazar 	 * - Rx
807aea2f8b7SAlexei Avshalom Lazar 	 * - Misc
808aea2f8b7SAlexei Avshalom Lazar 	 */
809aea2f8b7SAlexei Avshalom Lazar 	rc = request_irq(irq, wil->txrx_ops.irq_tx, IRQF_SHARED,
810aea2f8b7SAlexei Avshalom Lazar 			 WIL_NAME "_tx", wil);
811aea2f8b7SAlexei Avshalom Lazar 	if (rc)
812aea2f8b7SAlexei Avshalom Lazar 		return rc;
813aea2f8b7SAlexei Avshalom Lazar 
814aea2f8b7SAlexei Avshalom Lazar 	rc = request_irq(irq + 1, wil->txrx_ops.irq_rx, IRQF_SHARED,
815aea2f8b7SAlexei Avshalom Lazar 			 WIL_NAME "_rx", wil);
816aea2f8b7SAlexei Avshalom Lazar 	if (rc)
817aea2f8b7SAlexei Avshalom Lazar 		goto free0;
818aea2f8b7SAlexei Avshalom Lazar 
819aea2f8b7SAlexei Avshalom Lazar 	rc = request_threaded_irq(irq + 2, wil6210_irq_misc,
820aea2f8b7SAlexei Avshalom Lazar 				  wil6210_irq_misc_thread,
821aea2f8b7SAlexei Avshalom Lazar 				  IRQF_SHARED, WIL_NAME "_misc", wil);
822aea2f8b7SAlexei Avshalom Lazar 	if (rc)
823aea2f8b7SAlexei Avshalom Lazar 		goto free1;
824aea2f8b7SAlexei Avshalom Lazar 
825aea2f8b7SAlexei Avshalom Lazar 	return 0;
826aea2f8b7SAlexei Avshalom Lazar free1:
827aea2f8b7SAlexei Avshalom Lazar 	free_irq(irq + 1, wil);
828aea2f8b7SAlexei Avshalom Lazar free0:
829aea2f8b7SAlexei Avshalom Lazar 	free_irq(irq, wil);
830aea2f8b7SAlexei Avshalom Lazar 
831aea2f8b7SAlexei Avshalom Lazar 	return rc;
832aea2f8b7SAlexei Avshalom Lazar }
833aea2f8b7SAlexei Avshalom Lazar 
834d00a6367SVladimir Kondratiev /* can't use wil_ioread32_and_clear because ICC value is not set yet */
wil_clear32(void __iomem * addr)835f4b5a803SVladimir Kondratiev static inline void wil_clear32(void __iomem *addr)
836f4b5a803SVladimir Kondratiev {
837b9eeb512SVladimir Kondratiev 	u32 x = readl(addr);
838f4b5a803SVladimir Kondratiev 
839b9eeb512SVladimir Kondratiev 	writel(x, addr);
840f4b5a803SVladimir Kondratiev }
841f4b5a803SVladimir Kondratiev 
wil6210_clear_irq(struct wil6210_priv * wil)842f4b5a803SVladimir Kondratiev void wil6210_clear_irq(struct wil6210_priv *wil)
843f4b5a803SVladimir Kondratiev {
844f4b5a803SVladimir Kondratiev 	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
845f4b5a803SVladimir Kondratiev 		    offsetof(struct RGF_ICR, ICR));
846f4b5a803SVladimir Kondratiev 	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) +
847f4b5a803SVladimir Kondratiev 		    offsetof(struct RGF_ICR, ICR));
8487be13fc3SGidon Studinski 	wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_RX_ICR) +
8497be13fc3SGidon Studinski 		    offsetof(struct RGF_ICR, ICR));
8509202d7b6SMaya Erez 	wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) +
8519202d7b6SMaya Erez 		    offsetof(struct RGF_ICR, ICR));
852f4b5a803SVladimir Kondratiev 	wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
853f4b5a803SVladimir Kondratiev 		    offsetof(struct RGF_ICR, ICR));
854151a9706SVladimir Kondratiev 	wmb(); /* make sure write completed */
855f4b5a803SVladimir Kondratiev }
8562be7d22fSVladimir Kondratiev 
wil6210_set_halp(struct wil6210_priv * wil)857349214c1SMaya Erez void wil6210_set_halp(struct wil6210_priv *wil)
858349214c1SMaya Erez {
859af3db60aSLazar Alexei 	wil_dbg_irq(wil, "set_halp\n");
860349214c1SMaya Erez 
861349214c1SMaya Erez 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICS),
862349214c1SMaya Erez 	      BIT_DMA_EP_MISC_ICR_HALP);
863349214c1SMaya Erez }
864349214c1SMaya Erez 
wil6210_clear_halp(struct wil6210_priv * wil)865349214c1SMaya Erez void wil6210_clear_halp(struct wil6210_priv *wil)
866349214c1SMaya Erez {
867af3db60aSLazar Alexei 	wil_dbg_irq(wil, "clear_halp\n");
868349214c1SMaya Erez 
869349214c1SMaya Erez 	wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICR),
870349214c1SMaya Erez 	      BIT_DMA_EP_MISC_ICR_HALP);
871349214c1SMaya Erez 	wil6210_unmask_halp(wil);
872349214c1SMaya Erez }
873349214c1SMaya Erez 
wil6210_init_irq(struct wil6210_priv * wil,int irq)874aea2f8b7SAlexei Avshalom Lazar int wil6210_init_irq(struct wil6210_priv *wil, int irq)
8752be7d22fSVladimir Kondratiev {
8762be7d22fSVladimir Kondratiev 	int rc;
8779cf10d62SVladimir Kondratiev 
878aea2f8b7SAlexei Avshalom Lazar 	wil_dbg_misc(wil, "init_irq: %s, n_msi=%d\n",
879aea2f8b7SAlexei Avshalom Lazar 		     wil->n_msi ? "MSI" : "INTx", wil->n_msi);
8809cf10d62SVladimir Kondratiev 
8817be13fc3SGidon Studinski 	if (wil->use_enhanced_dma_hw) {
8829202d7b6SMaya Erez 		wil->txrx_ops.irq_tx = wil6210_irq_tx_edma;
8837be13fc3SGidon Studinski 		wil->txrx_ops.irq_rx = wil6210_irq_rx_edma;
8847be13fc3SGidon Studinski 	} else {
8859202d7b6SMaya Erez 		wil->txrx_ops.irq_tx = wil6210_irq_tx;
8867be13fc3SGidon Studinski 		wil->txrx_ops.irq_rx = wil6210_irq_rx;
8877be13fc3SGidon Studinski 	}
888aea2f8b7SAlexei Avshalom Lazar 
889aea2f8b7SAlexei Avshalom Lazar 	if (wil->n_msi == 3)
890aea2f8b7SAlexei Avshalom Lazar 		rc = wil6210_request_3msi(wil, irq);
891aea2f8b7SAlexei Avshalom Lazar 	else
8922be7d22fSVladimir Kondratiev 		rc = request_threaded_irq(irq, wil6210_hardirq,
8932be7d22fSVladimir Kondratiev 					  wil6210_thread_irq,
894aea2f8b7SAlexei Avshalom Lazar 					  wil->n_msi ? 0 : IRQF_SHARED,
8952be7d22fSVladimir Kondratiev 					  WIL_NAME, wil);
8962be7d22fSVladimir Kondratiev 	return rc;
8972be7d22fSVladimir Kondratiev }
8982be7d22fSVladimir Kondratiev 
wil6210_fini_irq(struct wil6210_priv * wil,int irq)8992be7d22fSVladimir Kondratiev void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
9002be7d22fSVladimir Kondratiev {
901af3db60aSLazar Alexei 	wil_dbg_misc(wil, "fini_irq:\n");
9029cf10d62SVladimir Kondratiev 
903e4dbb093SVladimir Kondratiev 	wil_mask_irq(wil);
9042be7d22fSVladimir Kondratiev 	free_irq(irq, wil);
905aea2f8b7SAlexei Avshalom Lazar 	if (wil->n_msi == 3) {
906aea2f8b7SAlexei Avshalom Lazar 		free_irq(irq + 1, wil);
907aea2f8b7SAlexei Avshalom Lazar 		free_irq(irq + 2, wil);
908aea2f8b7SAlexei Avshalom Lazar 	}
9092be7d22fSVladimir Kondratiev }
910