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 21 /** 22 * Theory of operation: 23 * 24 * There is ISR pseudo-cause register, 25 * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE 26 * Its bits represents OR'ed bits from 3 real ISR registers: 27 * TX, RX, and MISC. 28 * 29 * Registers may be configured to either "write 1 to clear" or 30 * "clear on read" mode 31 * 32 * When handling interrupt, one have to mask/unmask interrupts for the 33 * real ISR registers, or hardware may malfunction. 34 * 35 */ 36 37 #define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL) 38 #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE 39 #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ 40 BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) 41 #define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT) 42 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 51 static inline void wil_icr_clear(u32 x, void __iomem *addr) 52 { 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 59 static inline void wil_icr_clear(u32 x, void __iomem *addr) 60 { 61 iowrite32(x, addr); 62 } 63 #endif /* defined(CONFIG_WIL6210_ISR_COR) */ 64 65 static inline u32 wil_ioread32_and_clear(void __iomem *addr) 66 { 67 u32 x = ioread32(addr); 68 69 wil_icr_clear(x, addr); 70 71 return x; 72 } 73 74 static void wil6210_mask_irq_tx(struct wil6210_priv *wil) 75 { 76 iowrite32(WIL6210_IRQ_DISABLE, wil->csr + 77 HOSTADDR(RGF_DMA_EP_TX_ICR) + 78 offsetof(struct RGF_ICR, IMS)); 79 } 80 81 static void wil6210_mask_irq_rx(struct wil6210_priv *wil) 82 { 83 iowrite32(WIL6210_IRQ_DISABLE, wil->csr + 84 HOSTADDR(RGF_DMA_EP_RX_ICR) + 85 offsetof(struct RGF_ICR, IMS)); 86 } 87 88 static void wil6210_mask_irq_misc(struct wil6210_priv *wil) 89 { 90 iowrite32(WIL6210_IRQ_DISABLE, wil->csr + 91 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 92 offsetof(struct RGF_ICR, IMS)); 93 } 94 95 static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) 96 { 97 wil_dbg_IRQ(wil, "%s()\n", __func__); 98 99 iowrite32(WIL6210_IRQ_DISABLE, wil->csr + 100 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); 101 102 clear_bit(wil_status_irqen, &wil->status); 103 } 104 105 static void wil6210_unmask_irq_tx(struct wil6210_priv *wil) 106 { 107 iowrite32(WIL6210_IMC_TX, wil->csr + 108 HOSTADDR(RGF_DMA_EP_TX_ICR) + 109 offsetof(struct RGF_ICR, IMC)); 110 } 111 112 static void wil6210_unmask_irq_rx(struct wil6210_priv *wil) 113 { 114 iowrite32(WIL6210_IMC_RX, wil->csr + 115 HOSTADDR(RGF_DMA_EP_RX_ICR) + 116 offsetof(struct RGF_ICR, IMC)); 117 } 118 119 static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) 120 { 121 iowrite32(WIL6210_IMC_MISC, wil->csr + 122 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 123 offsetof(struct RGF_ICR, IMC)); 124 } 125 126 static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) 127 { 128 wil_dbg_IRQ(wil, "%s()\n", __func__); 129 130 set_bit(wil_status_irqen, &wil->status); 131 132 iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + 133 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); 134 } 135 136 void wil6210_disable_irq(struct wil6210_priv *wil) 137 { 138 wil_dbg_IRQ(wil, "%s()\n", __func__); 139 140 wil6210_mask_irq_tx(wil); 141 wil6210_mask_irq_rx(wil); 142 wil6210_mask_irq_misc(wil); 143 wil6210_mask_irq_pseudo(wil); 144 } 145 146 void wil6210_enable_irq(struct wil6210_priv *wil) 147 { 148 wil_dbg_IRQ(wil, "%s()\n", __func__); 149 150 iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + 151 offsetof(struct RGF_ICR, ICC)); 152 iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + 153 offsetof(struct RGF_ICR, ICC)); 154 iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + 155 offsetof(struct RGF_ICR, ICC)); 156 157 wil6210_unmask_irq_pseudo(wil); 158 wil6210_unmask_irq_tx(wil); 159 wil6210_unmask_irq_rx(wil); 160 wil6210_unmask_irq_misc(wil); 161 } 162 163 static irqreturn_t wil6210_irq_rx(int irq, void *cookie) 164 { 165 struct wil6210_priv *wil = cookie; 166 u32 isr = wil_ioread32_and_clear(wil->csr + 167 HOSTADDR(RGF_DMA_EP_RX_ICR) + 168 offsetof(struct RGF_ICR, ICR)); 169 170 wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr); 171 172 if (!isr) { 173 wil_err(wil, "spurious IRQ: RX\n"); 174 return IRQ_NONE; 175 } 176 177 wil6210_mask_irq_rx(wil); 178 179 if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { 180 wil_dbg_IRQ(wil, "RX done\n"); 181 isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; 182 wil_rx_handle(wil); 183 } 184 185 if (isr) 186 wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); 187 188 wil6210_unmask_irq_rx(wil); 189 190 return IRQ_HANDLED; 191 } 192 193 static irqreturn_t wil6210_irq_tx(int irq, void *cookie) 194 { 195 struct wil6210_priv *wil = cookie; 196 u32 isr = wil_ioread32_and_clear(wil->csr + 197 HOSTADDR(RGF_DMA_EP_TX_ICR) + 198 offsetof(struct RGF_ICR, ICR)); 199 200 wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr); 201 202 if (!isr) { 203 wil_err(wil, "spurious IRQ: TX\n"); 204 return IRQ_NONE; 205 } 206 207 wil6210_mask_irq_tx(wil); 208 209 if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { 210 uint i; 211 wil_dbg_IRQ(wil, "TX done\n"); 212 isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; 213 for (i = 0; i < 24; i++) { 214 u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); 215 if (isr & mask) { 216 isr &= ~mask; 217 wil_dbg_IRQ(wil, "TX done(%i)\n", i); 218 wil_tx_complete(wil, i); 219 } 220 } 221 } 222 223 if (isr) 224 wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); 225 226 wil6210_unmask_irq_tx(wil); 227 228 return IRQ_HANDLED; 229 } 230 231 static irqreturn_t wil6210_irq_misc(int irq, void *cookie) 232 { 233 struct wil6210_priv *wil = cookie; 234 u32 isr = wil_ioread32_and_clear(wil->csr + 235 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 236 offsetof(struct RGF_ICR, ICR)); 237 238 wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr); 239 240 if (!isr) { 241 wil_err(wil, "spurious IRQ: MISC\n"); 242 return IRQ_NONE; 243 } 244 245 wil6210_mask_irq_misc(wil); 246 247 if (isr & ISR_MISC_FW_READY) { 248 wil_dbg_IRQ(wil, "IRQ: FW ready\n"); 249 /** 250 * Actual FW ready indicated by the 251 * WMI_FW_READY_EVENTID 252 */ 253 isr &= ~ISR_MISC_FW_READY; 254 } 255 256 wil->isr_misc = isr; 257 258 if (isr) { 259 return IRQ_WAKE_THREAD; 260 } else { 261 wil6210_unmask_irq_misc(wil); 262 return IRQ_HANDLED; 263 } 264 } 265 266 static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) 267 { 268 struct wil6210_priv *wil = cookie; 269 u32 isr = wil->isr_misc; 270 271 wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr); 272 273 if (isr & ISR_MISC_MBOX_EVT) { 274 wil_dbg_IRQ(wil, "MBOX event\n"); 275 wmi_recv_cmd(wil); 276 isr &= ~ISR_MISC_MBOX_EVT; 277 } 278 279 if (isr) 280 wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr); 281 282 wil->isr_misc = 0; 283 284 wil6210_unmask_irq_misc(wil); 285 286 return IRQ_HANDLED; 287 } 288 289 /** 290 * thread IRQ handler 291 */ 292 static irqreturn_t wil6210_thread_irq(int irq, void *cookie) 293 { 294 struct wil6210_priv *wil = cookie; 295 296 wil_dbg_IRQ(wil, "Thread IRQ\n"); 297 /* Discover real IRQ cause */ 298 if (wil->isr_misc) 299 wil6210_irq_misc_thread(irq, cookie); 300 301 wil6210_unmask_irq_pseudo(wil); 302 303 return IRQ_HANDLED; 304 } 305 306 /* DEBUG 307 * There is subtle bug in hardware that causes IRQ to raise when it should be 308 * masked. It is quite rare and hard to debug. 309 * 310 * Catch irq issue if it happens and print all I can. 311 */ 312 static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) 313 { 314 if (!test_bit(wil_status_irqen, &wil->status)) { 315 u32 icm_rx = wil_ioread32_and_clear(wil->csr + 316 HOSTADDR(RGF_DMA_EP_RX_ICR) + 317 offsetof(struct RGF_ICR, ICM)); 318 u32 icr_rx = wil_ioread32_and_clear(wil->csr + 319 HOSTADDR(RGF_DMA_EP_RX_ICR) + 320 offsetof(struct RGF_ICR, ICR)); 321 u32 imv_rx = ioread32(wil->csr + 322 HOSTADDR(RGF_DMA_EP_RX_ICR) + 323 offsetof(struct RGF_ICR, IMV)); 324 u32 icm_tx = wil_ioread32_and_clear(wil->csr + 325 HOSTADDR(RGF_DMA_EP_TX_ICR) + 326 offsetof(struct RGF_ICR, ICM)); 327 u32 icr_tx = wil_ioread32_and_clear(wil->csr + 328 HOSTADDR(RGF_DMA_EP_TX_ICR) + 329 offsetof(struct RGF_ICR, ICR)); 330 u32 imv_tx = ioread32(wil->csr + 331 HOSTADDR(RGF_DMA_EP_TX_ICR) + 332 offsetof(struct RGF_ICR, IMV)); 333 u32 icm_misc = wil_ioread32_and_clear(wil->csr + 334 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 335 offsetof(struct RGF_ICR, ICM)); 336 u32 icr_misc = wil_ioread32_and_clear(wil->csr + 337 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 338 offsetof(struct RGF_ICR, ICR)); 339 u32 imv_misc = ioread32(wil->csr + 340 HOSTADDR(RGF_DMA_EP_MISC_ICR) + 341 offsetof(struct RGF_ICR, IMV)); 342 wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n" 343 "Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" 344 "Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" 345 "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n", 346 pseudo_cause, 347 icm_rx, icr_rx, imv_rx, 348 icm_tx, icr_tx, imv_tx, 349 icm_misc, icr_misc, imv_misc); 350 351 return -EINVAL; 352 } 353 354 return 0; 355 } 356 357 static irqreturn_t wil6210_hardirq(int irq, void *cookie) 358 { 359 irqreturn_t rc = IRQ_HANDLED; 360 struct wil6210_priv *wil = cookie; 361 u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); 362 363 /** 364 * pseudo_cause is Clear-On-Read, no need to ACK 365 */ 366 if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)) 367 return IRQ_NONE; 368 369 /* FIXME: IRQ mask debug */ 370 if (wil6210_debug_irq_mask(wil, pseudo_cause)) 371 return IRQ_NONE; 372 373 wil6210_mask_irq_pseudo(wil); 374 375 /* Discover real IRQ cause 376 * There are 2 possible phases for every IRQ: 377 * - hard IRQ handler called right here 378 * - threaded handler called later 379 * 380 * Hard IRQ handler reads and clears ISR. 381 * 382 * If threaded handler requested, hard IRQ handler 383 * returns IRQ_WAKE_THREAD and saves ISR register value 384 * for the threaded handler use. 385 * 386 * voting for wake thread - need at least 1 vote 387 */ 388 if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) && 389 (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD)) 390 rc = IRQ_WAKE_THREAD; 391 392 if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) && 393 (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD)) 394 rc = IRQ_WAKE_THREAD; 395 396 if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) && 397 (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD)) 398 rc = IRQ_WAKE_THREAD; 399 400 /* if thread is requested, it will unmask IRQ */ 401 if (rc != IRQ_WAKE_THREAD) 402 wil6210_unmask_irq_pseudo(wil); 403 404 wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause); 405 406 return rc; 407 } 408 409 static int wil6210_request_3msi(struct wil6210_priv *wil, int irq) 410 { 411 int rc; 412 /* 413 * IRQ's are in the following order: 414 * - Tx 415 * - Rx 416 * - Misc 417 */ 418 419 rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED, 420 WIL_NAME"_tx", wil); 421 if (rc) 422 return rc; 423 424 rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED, 425 WIL_NAME"_rx", wil); 426 if (rc) 427 goto free0; 428 429 rc = request_threaded_irq(irq + 2, wil6210_irq_misc, 430 wil6210_irq_misc_thread, 431 IRQF_SHARED, WIL_NAME"_misc", wil); 432 if (rc) 433 goto free1; 434 435 return 0; 436 /* error branch */ 437 free1: 438 free_irq(irq + 1, wil); 439 free0: 440 free_irq(irq, wil); 441 442 return rc; 443 } 444 445 int wil6210_init_irq(struct wil6210_priv *wil, int irq) 446 { 447 int rc; 448 if (wil->n_msi == 3) 449 rc = wil6210_request_3msi(wil, irq); 450 else 451 rc = request_threaded_irq(irq, wil6210_hardirq, 452 wil6210_thread_irq, 453 wil->n_msi ? 0 : IRQF_SHARED, 454 WIL_NAME, wil); 455 if (rc) 456 return rc; 457 458 wil6210_enable_irq(wil); 459 460 return 0; 461 } 462 463 void wil6210_fini_irq(struct wil6210_priv *wil, int irq) 464 { 465 wil6210_disable_irq(wil); 466 free_irq(irq, wil); 467 if (wil->n_msi == 3) { 468 free_irq(irq + 1, wil); 469 free_irq(irq + 2, wil); 470 } 471 } 472