910 lines · c
1// SPDX-License-Identifier: ISC2/*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_CAUSE17 * 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" or21 * "clear on read" mode22 *23 * When handling interrupt, one have to mask/unmask interrupts for the24 * 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_IRQ37#define WIL6210_IMC_RX_EDMA BIT_RX_STATUS_IRQ38#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 regular230 * (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 monitor243 * to get better timestamp precision244 */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 interrupt307 * moderation is not used. Interrupt moderation may cause RX308 * buffer overflow while RX_DONE is delayed. The required309 * action is always the same - should empty the accumulated310 * 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 thread564 * there, user space get notified, and it should be done565 * in non-atomic context566 */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 the576 * WMI_FW_READY_EVENTID577 */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_irq637 * 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/* DEBUG670 * There is subtle bug in hardware that causes IRQ to raise when it should be671 * 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 are727 * masked728 */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 ACK755 */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 cause769 * There are 2 possible phases for every IRQ:770 * - hard IRQ handler called right here771 * - threaded handler called later772 *773 * Hard IRQ handler reads and clears ISR.774 *775 * If threaded handler requested, hard IRQ handler776 * returns IRQ_WAKE_THREAD and saves ISR register value777 * for the threaded handler use.778 *779 * voting for wake thread - need at least 1 vote780 */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 * - Tx806 * - Rx807 * - Misc808 */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 else892 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}910