1 /* 2 * Copyright (c) 2012 Qualcomm Atheros, Inc. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <linux/interrupt.h> 18 19 #include "wil6210.h" 20 #include "trace.h" 21 22 /** 23 * Theory of operation: 24 * 25 * There is ISR pseudo-cause register, 26 * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE 27 * Its bits represents OR'ed bits from 3 real ISR registers: 28 * TX, RX, and MISC. 29 * 30 * Registers may be configured to either "write 1 to clear" or 31 * "clear on read" mode 32 * 33 * When handling interrupt, one have to mask/unmask interrupts for the 34 * real ISR registers, or hardware may malfunction. 35 * 36 */ 37 38 #define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL) 39 #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE 40 #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ 41 BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) 42 #define WIL6210_IMC_MISC (ISR_MISC_FW_READY | \ 43 ISR_MISC_MBOX_EVT | \ 44 ISR_MISC_FW_ERROR) 45 46 #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \ 47 BIT_DMA_PSEUDO_CAUSE_TX | \ 48 BIT_DMA_PSEUDO_CAUSE_MISC)) 49 50 #if defined(CONFIG_WIL6210_ISR_COR) 51 /* configure to Clear-On-Read mode */ 52 #define WIL_ICR_ICC_VALUE (0xFFFFFFFFUL) 53 54 static inline void wil_icr_clear(u32 x, void __iomem *addr) 55 { 56 } 57 #else /* defined(CONFIG_WIL6210_ISR_COR) */ 58 /* configure to Write-1-to-Clear mode */ 59 #define WIL_ICR_ICC_VALUE (0UL) 60 61 static inline void wil_icr_clear(u32 x, void __iomem *addr) 62 { 63 iowrite32(x, addr); 64 } 65 #endif /* defined(CONFIG_WIL6210_ISR_COR) */ 66 67 static inline u32 wil_ioread32_and_clear(void __iomem *addr) 68 { 69 u32 x = ioread32(addr); 70 71 wil_icr_clear(x, addr); 72 73 return x; 74 } 75 76 static void wil6210_mask_irq_tx(struct wil6210_priv *wil) 77 { 78 iowrite32(WIL6210_IRQ_DISABLE, wil->csr + 79 HOSTADDR(RGF_DMA_EP_TX_ICR) + 80 offsetof(struct RGF_ICR, IMS)); 81 } 82 83 static void wil6210_mask_irq_rx(struct wil6210_priv *wil) 84 { 85 iowrite32(WIL6210_IRQ_DISABLE, wil->csr + 86 HOSTADDR(RGF_DMA_EP_RX_ICR) + 87 offsetof(struct RGF_ICR, IMS)); 88 } 89 90 static void wil6210_mask_irq_misc(struct wil6210_priv *wil) 91 { 92 iowrite32(WIL6210_IRQ_DISABLE, wil->csr + 93 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 94 offsetof(struct RGF_ICR, IMS)); 95 } 96 97 static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) 98 { 99 wil_dbg_irq(wil, "%s()\n", __func__); 100 101 iowrite32(WIL6210_IRQ_DISABLE, wil->csr + 102 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); 103 104 clear_bit(wil_status_irqen, &wil->status); 105 } 106 107 void wil6210_unmask_irq_tx(struct wil6210_priv *wil) 108 { 109 iowrite32(WIL6210_IMC_TX, wil->csr + 110 HOSTADDR(RGF_DMA_EP_TX_ICR) + 111 offsetof(struct RGF_ICR, IMC)); 112 } 113 114 void wil6210_unmask_irq_rx(struct wil6210_priv *wil) 115 { 116 iowrite32(WIL6210_IMC_RX, wil->csr + 117 HOSTADDR(RGF_DMA_EP_RX_ICR) + 118 offsetof(struct RGF_ICR, IMC)); 119 } 120 121 static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) 122 { 123 iowrite32(WIL6210_IMC_MISC, wil->csr + 124 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 125 offsetof(struct RGF_ICR, IMC)); 126 } 127 128 static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) 129 { 130 wil_dbg_irq(wil, "%s()\n", __func__); 131 132 set_bit(wil_status_irqen, &wil->status); 133 134 iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + 135 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); 136 } 137 138 void wil6210_disable_irq(struct wil6210_priv *wil) 139 { 140 wil_dbg_irq(wil, "%s()\n", __func__); 141 142 wil6210_mask_irq_tx(wil); 143 wil6210_mask_irq_rx(wil); 144 wil6210_mask_irq_misc(wil); 145 wil6210_mask_irq_pseudo(wil); 146 } 147 148 void wil6210_enable_irq(struct wil6210_priv *wil) 149 { 150 wil_dbg_irq(wil, "%s()\n", __func__); 151 152 iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + 153 offsetof(struct RGF_ICR, ICC)); 154 iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + 155 offsetof(struct RGF_ICR, ICC)); 156 iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + 157 offsetof(struct RGF_ICR, ICC)); 158 159 /* interrupt moderation parameters */ 160 if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { 161 /* disable interrupt moderation for monitor 162 * to get better timestamp precision 163 */ 164 iowrite32(0, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); 165 } else { 166 iowrite32(WIL6210_ITR_TRSH, 167 wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); 168 iowrite32(BIT_DMA_ITR_CNT_CRL_EN, 169 wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); 170 } 171 172 wil6210_unmask_irq_pseudo(wil); 173 wil6210_unmask_irq_tx(wil); 174 wil6210_unmask_irq_rx(wil); 175 wil6210_unmask_irq_misc(wil); 176 } 177 178 static irqreturn_t wil6210_irq_rx(int irq, void *cookie) 179 { 180 struct wil6210_priv *wil = cookie; 181 u32 isr = wil_ioread32_and_clear(wil->csr + 182 HOSTADDR(RGF_DMA_EP_RX_ICR) + 183 offsetof(struct RGF_ICR, ICR)); 184 185 trace_wil6210_irq_rx(isr); 186 wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); 187 188 if (!isr) { 189 wil_err(wil, "spurious IRQ: RX\n"); 190 return IRQ_NONE; 191 } 192 193 wil6210_mask_irq_rx(wil); 194 195 if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { 196 wil_dbg_irq(wil, "RX done\n"); 197 isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; 198 wil_dbg_txrx(wil, "NAPI schedule\n"); 199 napi_schedule(&wil->napi_rx); 200 } 201 202 if (isr) 203 wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); 204 205 /* Rx IRQ will be enabled when NAPI processing finished */ 206 207 return IRQ_HANDLED; 208 } 209 210 static irqreturn_t wil6210_irq_tx(int irq, void *cookie) 211 { 212 struct wil6210_priv *wil = cookie; 213 u32 isr = wil_ioread32_and_clear(wil->csr + 214 HOSTADDR(RGF_DMA_EP_TX_ICR) + 215 offsetof(struct RGF_ICR, ICR)); 216 217 trace_wil6210_irq_tx(isr); 218 wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); 219 220 if (!isr) { 221 wil_err(wil, "spurious IRQ: TX\n"); 222 return IRQ_NONE; 223 } 224 225 wil6210_mask_irq_tx(wil); 226 227 if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { 228 wil_dbg_irq(wil, "TX done\n"); 229 napi_schedule(&wil->napi_tx); 230 isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; 231 /* clear also all VRING interrupts */ 232 isr &= ~(BIT(25) - 1UL); 233 } 234 235 if (isr) 236 wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); 237 238 /* Tx IRQ will be enabled when NAPI processing finished */ 239 240 return IRQ_HANDLED; 241 } 242 243 static void wil_notify_fw_error(struct wil6210_priv *wil) 244 { 245 struct device *dev = &wil_to_ndev(wil)->dev; 246 char *envp[3] = { 247 [0] = "SOURCE=wil6210", 248 [1] = "EVENT=FW_ERROR", 249 [2] = NULL, 250 }; 251 kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); 252 } 253 254 static void wil_cache_mbox_regs(struct wil6210_priv *wil) 255 { 256 /* make shadow copy of registers that should not change on run time */ 257 wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, 258 sizeof(struct wil6210_mbox_ctl)); 259 wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); 260 wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); 261 } 262 263 static irqreturn_t wil6210_irq_misc(int irq, void *cookie) 264 { 265 struct wil6210_priv *wil = cookie; 266 u32 isr = wil_ioread32_and_clear(wil->csr + 267 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 268 offsetof(struct RGF_ICR, ICR)); 269 270 trace_wil6210_irq_misc(isr); 271 wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr); 272 273 if (!isr) { 274 wil_err(wil, "spurious IRQ: MISC\n"); 275 return IRQ_NONE; 276 } 277 278 wil6210_mask_irq_misc(wil); 279 280 if (isr & ISR_MISC_FW_ERROR) { 281 wil_err(wil, "Firmware error detected\n"); 282 clear_bit(wil_status_fwready, &wil->status); 283 /* 284 * do not clear @isr here - we do 2-nd part in thread 285 * there, user space get notified, and it should be done 286 * in non-atomic context 287 */ 288 } 289 290 if (isr & ISR_MISC_FW_READY) { 291 wil_dbg_irq(wil, "IRQ: FW ready\n"); 292 wil_cache_mbox_regs(wil); 293 set_bit(wil_status_reset_done, &wil->status); 294 /** 295 * Actual FW ready indicated by the 296 * WMI_FW_READY_EVENTID 297 */ 298 isr &= ~ISR_MISC_FW_READY; 299 } 300 301 wil->isr_misc = isr; 302 303 if (isr) { 304 return IRQ_WAKE_THREAD; 305 } else { 306 wil6210_unmask_irq_misc(wil); 307 return IRQ_HANDLED; 308 } 309 } 310 311 static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) 312 { 313 struct wil6210_priv *wil = cookie; 314 u32 isr = wil->isr_misc; 315 316 trace_wil6210_irq_misc_thread(isr); 317 wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr); 318 319 if (isr & ISR_MISC_FW_ERROR) { 320 wil_notify_fw_error(wil); 321 isr &= ~ISR_MISC_FW_ERROR; 322 } 323 324 if (isr & ISR_MISC_MBOX_EVT) { 325 wil_dbg_irq(wil, "MBOX event\n"); 326 wmi_recv_cmd(wil); 327 isr &= ~ISR_MISC_MBOX_EVT; 328 } 329 330 if (isr) 331 wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr); 332 333 wil->isr_misc = 0; 334 335 wil6210_unmask_irq_misc(wil); 336 337 return IRQ_HANDLED; 338 } 339 340 /** 341 * thread IRQ handler 342 */ 343 static irqreturn_t wil6210_thread_irq(int irq, void *cookie) 344 { 345 struct wil6210_priv *wil = cookie; 346 347 wil_dbg_irq(wil, "Thread IRQ\n"); 348 /* Discover real IRQ cause */ 349 if (wil->isr_misc) 350 wil6210_irq_misc_thread(irq, cookie); 351 352 wil6210_unmask_irq_pseudo(wil); 353 354 return IRQ_HANDLED; 355 } 356 357 /* DEBUG 358 * There is subtle bug in hardware that causes IRQ to raise when it should be 359 * masked. It is quite rare and hard to debug. 360 * 361 * Catch irq issue if it happens and print all I can. 362 */ 363 static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) 364 { 365 if (!test_bit(wil_status_irqen, &wil->status)) { 366 u32 icm_rx = wil_ioread32_and_clear(wil->csr + 367 HOSTADDR(RGF_DMA_EP_RX_ICR) + 368 offsetof(struct RGF_ICR, ICM)); 369 u32 icr_rx = wil_ioread32_and_clear(wil->csr + 370 HOSTADDR(RGF_DMA_EP_RX_ICR) + 371 offsetof(struct RGF_ICR, ICR)); 372 u32 imv_rx = ioread32(wil->csr + 373 HOSTADDR(RGF_DMA_EP_RX_ICR) + 374 offsetof(struct RGF_ICR, IMV)); 375 u32 icm_tx = wil_ioread32_and_clear(wil->csr + 376 HOSTADDR(RGF_DMA_EP_TX_ICR) + 377 offsetof(struct RGF_ICR, ICM)); 378 u32 icr_tx = wil_ioread32_and_clear(wil->csr + 379 HOSTADDR(RGF_DMA_EP_TX_ICR) + 380 offsetof(struct RGF_ICR, ICR)); 381 u32 imv_tx = ioread32(wil->csr + 382 HOSTADDR(RGF_DMA_EP_TX_ICR) + 383 offsetof(struct RGF_ICR, IMV)); 384 u32 icm_misc = wil_ioread32_and_clear(wil->csr + 385 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 386 offsetof(struct RGF_ICR, ICM)); 387 u32 icr_misc = wil_ioread32_and_clear(wil->csr + 388 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 389 offsetof(struct RGF_ICR, ICR)); 390 u32 imv_misc = ioread32(wil->csr + 391 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 392 offsetof(struct RGF_ICR, IMV)); 393 wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n" 394 "Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" 395 "Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" 396 "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n", 397 pseudo_cause, 398 icm_rx, icr_rx, imv_rx, 399 icm_tx, icr_tx, imv_tx, 400 icm_misc, icr_misc, imv_misc); 401 402 return -EINVAL; 403 } 404 405 return 0; 406 } 407 408 static irqreturn_t wil6210_hardirq(int irq, void *cookie) 409 { 410 irqreturn_t rc = IRQ_HANDLED; 411 struct wil6210_priv *wil = cookie; 412 u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); 413 414 /** 415 * pseudo_cause is Clear-On-Read, no need to ACK 416 */ 417 if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)) 418 return IRQ_NONE; 419 420 /* FIXME: IRQ mask debug */ 421 if (wil6210_debug_irq_mask(wil, pseudo_cause)) 422 return IRQ_NONE; 423 424 trace_wil6210_irq_pseudo(pseudo_cause); 425 wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause); 426 427 wil6210_mask_irq_pseudo(wil); 428 429 /* Discover real IRQ cause 430 * There are 2 possible phases for every IRQ: 431 * - hard IRQ handler called right here 432 * - threaded handler called later 433 * 434 * Hard IRQ handler reads and clears ISR. 435 * 436 * If threaded handler requested, hard IRQ handler 437 * returns IRQ_WAKE_THREAD and saves ISR register value 438 * for the threaded handler use. 439 * 440 * voting for wake thread - need at least 1 vote 441 */ 442 if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) && 443 (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD)) 444 rc = IRQ_WAKE_THREAD; 445 446 if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) && 447 (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD)) 448 rc = IRQ_WAKE_THREAD; 449 450 if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) && 451 (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD)) 452 rc = IRQ_WAKE_THREAD; 453 454 /* if thread is requested, it will unmask IRQ */ 455 if (rc != IRQ_WAKE_THREAD) 456 wil6210_unmask_irq_pseudo(wil); 457 458 return rc; 459 } 460 461 static int wil6210_request_3msi(struct wil6210_priv *wil, int irq) 462 { 463 int rc; 464 /* 465 * IRQ's are in the following order: 466 * - Tx 467 * - Rx 468 * - Misc 469 */ 470 471 rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED, 472 WIL_NAME"_tx", wil); 473 if (rc) 474 return rc; 475 476 rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED, 477 WIL_NAME"_rx", wil); 478 if (rc) 479 goto free0; 480 481 rc = request_threaded_irq(irq + 2, wil6210_irq_misc, 482 wil6210_irq_misc_thread, 483 IRQF_SHARED, WIL_NAME"_misc", wil); 484 if (rc) 485 goto free1; 486 487 return 0; 488 /* error branch */ 489 free1: 490 free_irq(irq + 1, wil); 491 free0: 492 free_irq(irq, wil); 493 494 return rc; 495 } 496 497 int wil6210_init_irq(struct wil6210_priv *wil, int irq) 498 { 499 int rc; 500 if (wil->n_msi == 3) 501 rc = wil6210_request_3msi(wil, irq); 502 else 503 rc = request_threaded_irq(irq, wil6210_hardirq, 504 wil6210_thread_irq, 505 wil->n_msi ? 0 : IRQF_SHARED, 506 WIL_NAME, wil); 507 if (rc) 508 return rc; 509 510 wil6210_enable_irq(wil); 511 512 return 0; 513 } 514 515 void wil6210_fini_irq(struct wil6210_priv *wil, int irq) 516 { 517 wil6210_disable_irq(wil); 518 free_irq(irq, wil); 519 if (wil->n_msi == 3) { 520 free_irq(irq + 1, wil); 521 free_irq(irq + 2, wil); 522 } 523 } 524