cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

interrupt.c (25023B)


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