1 /* 2 * Copyright (c) 2007-2011 Atheros Communications 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 #include "hif.h" 17 18 #include <linux/export.h> 19 20 #include "core.h" 21 #include "target.h" 22 #include "hif-ops.h" 23 #include "debug.h" 24 25 #define MAILBOX_FOR_BLOCK_SIZE 1 26 27 #define ATH6KL_TIME_QUANTUM 10 /* in ms */ 28 29 static int ath6kl_hif_cp_scat_dma_buf(struct hif_scatter_req *req, 30 bool from_dma) 31 { 32 u8 *buf; 33 int i; 34 35 buf = req->virt_dma_buf; 36 37 for (i = 0; i < req->scat_entries; i++) { 38 39 if (from_dma) 40 memcpy(req->scat_list[i].buf, buf, 41 req->scat_list[i].len); 42 else 43 memcpy(buf, req->scat_list[i].buf, 44 req->scat_list[i].len); 45 46 buf += req->scat_list[i].len; 47 } 48 49 return 0; 50 } 51 52 int ath6kl_hif_rw_comp_handler(void *context, int status) 53 { 54 struct htc_packet *packet = context; 55 56 ath6kl_dbg(ATH6KL_DBG_HIF, "hif rw completion pkt 0x%p status %d\n", 57 packet, status); 58 59 packet->status = status; 60 packet->completion(packet->context, packet); 61 62 return 0; 63 } 64 EXPORT_SYMBOL(ath6kl_hif_rw_comp_handler); 65 66 #define REG_DUMP_COUNT_AR6003 60 67 #define REGISTER_DUMP_LEN_MAX 60 68 69 static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar) 70 { 71 __le32 regdump_val[REGISTER_DUMP_LEN_MAX]; 72 u32 i, address, regdump_addr = 0; 73 int ret; 74 75 if (ar->target_type != TARGET_TYPE_AR6003) 76 return; 77 78 /* the reg dump pointer is copied to the host interest area */ 79 address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state)); 80 address = TARG_VTOP(ar->target_type, address); 81 82 /* read RAM location through diagnostic window */ 83 ret = ath6kl_diag_read32(ar, address, ®dump_addr); 84 85 if (ret || !regdump_addr) { 86 ath6kl_warn("failed to get ptr to register dump area: %d\n", 87 ret); 88 return; 89 } 90 91 ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n", 92 regdump_addr); 93 regdump_addr = TARG_VTOP(ar->target_type, regdump_addr); 94 95 /* fetch register dump data */ 96 ret = ath6kl_diag_read(ar, regdump_addr, (u8 *)®dump_val[0], 97 REG_DUMP_COUNT_AR6003 * (sizeof(u32))); 98 if (ret) { 99 ath6kl_warn("failed to get register dump: %d\n", ret); 100 return; 101 } 102 103 ath6kl_info("crash dump:\n"); 104 ath6kl_info("hw 0x%x fw %s\n", ar->wiphy->hw_version, 105 ar->wiphy->fw_version); 106 107 BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4); 108 109 for (i = 0; i < REG_DUMP_COUNT_AR6003 / 4; i++) { 110 ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", 111 4 * i, 112 le32_to_cpu(regdump_val[i]), 113 le32_to_cpu(regdump_val[i + 1]), 114 le32_to_cpu(regdump_val[i + 2]), 115 le32_to_cpu(regdump_val[i + 3])); 116 } 117 118 } 119 120 static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) 121 { 122 u32 dummy; 123 int ret; 124 125 ath6kl_warn("firmware crashed\n"); 126 127 /* 128 * read counter to clear the interrupt, the debug error interrupt is 129 * counter 0. 130 */ 131 ret = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS, 132 (u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC); 133 if (ret) 134 ath6kl_warn("Failed to clear debug interrupt: %d\n", ret); 135 136 ath6kl_hif_dump_fw_crash(dev->ar); 137 138 return ret; 139 } 140 141 /* mailbox recv message polling */ 142 int ath6kl_hif_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd, 143 int timeout) 144 { 145 struct ath6kl_irq_proc_registers *rg; 146 int status = 0, i; 147 u8 htc_mbox = 1 << HTC_MAILBOX; 148 149 for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) { 150 /* this is the standard HIF way, load the reg table */ 151 status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS, 152 (u8 *) &dev->irq_proc_reg, 153 sizeof(dev->irq_proc_reg), 154 HIF_RD_SYNC_BYTE_INC); 155 156 if (status) { 157 ath6kl_err("failed to read reg table\n"); 158 return status; 159 } 160 161 /* check for MBOX data and valid lookahead */ 162 if (dev->irq_proc_reg.host_int_status & htc_mbox) { 163 if (dev->irq_proc_reg.rx_lkahd_valid & 164 htc_mbox) { 165 /* 166 * Mailbox has a message and the look ahead 167 * is valid. 168 */ 169 rg = &dev->irq_proc_reg; 170 *lk_ahd = 171 le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]); 172 break; 173 } 174 } 175 176 /* delay a little */ 177 mdelay(ATH6KL_TIME_QUANTUM); 178 ath6kl_dbg(ATH6KL_DBG_HIF, "hif retry mbox poll try %d\n", i); 179 } 180 181 if (i == 0) { 182 ath6kl_err("timeout waiting for recv message\n"); 183 status = -ETIME; 184 /* check if the target asserted */ 185 if (dev->irq_proc_reg.counter_int_status & 186 ATH6KL_TARGET_DEBUG_INTR_MASK) 187 /* 188 * Target failure handler will be called in case of 189 * an assert. 190 */ 191 ath6kl_hif_proc_dbg_intr(dev); 192 } 193 194 return status; 195 } 196 197 /* 198 * Disable packet reception (used in case the host runs out of buffers) 199 * using the interrupt enable registers through the host I/F 200 */ 201 int ath6kl_hif_rx_control(struct ath6kl_device *dev, bool enable_rx) 202 { 203 struct ath6kl_irq_enable_reg regs; 204 int status = 0; 205 206 ath6kl_dbg(ATH6KL_DBG_HIF, "hif rx %s\n", 207 enable_rx ? "enable" : "disable"); 208 209 /* take the lock to protect interrupt enable shadows */ 210 spin_lock_bh(&dev->lock); 211 212 if (enable_rx) 213 dev->irq_en_reg.int_status_en |= 214 SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01); 215 else 216 dev->irq_en_reg.int_status_en &= 217 ~SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01); 218 219 memcpy(®s, &dev->irq_en_reg, sizeof(regs)); 220 221 spin_unlock_bh(&dev->lock); 222 223 status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS, 224 ®s.int_status_en, 225 sizeof(struct ath6kl_irq_enable_reg), 226 HIF_WR_SYNC_BYTE_INC); 227 228 return status; 229 } 230 231 int ath6kl_hif_submit_scat_req(struct ath6kl_device *dev, 232 struct hif_scatter_req *scat_req, bool read) 233 { 234 int status = 0; 235 236 if (read) { 237 scat_req->req = HIF_RD_SYNC_BLOCK_FIX; 238 scat_req->addr = dev->ar->mbox_info.htc_addr; 239 } else { 240 scat_req->req = HIF_WR_ASYNC_BLOCK_INC; 241 242 scat_req->addr = 243 (scat_req->len > HIF_MBOX_WIDTH) ? 244 dev->ar->mbox_info.htc_ext_addr : 245 dev->ar->mbox_info.htc_addr; 246 } 247 248 ath6kl_dbg(ATH6KL_DBG_HIF, 249 "hif submit scatter request entries %d len %d mbox 0x%x %s %s\n", 250 scat_req->scat_entries, scat_req->len, 251 scat_req->addr, !read ? "async" : "sync", 252 (read) ? "rd" : "wr"); 253 254 if (!read && scat_req->virt_scat) { 255 status = ath6kl_hif_cp_scat_dma_buf(scat_req, false); 256 if (status) { 257 scat_req->status = status; 258 scat_req->complete(dev->ar->htc_target, scat_req); 259 return 0; 260 } 261 } 262 263 status = ath6kl_hif_scat_req_rw(dev->ar, scat_req); 264 265 if (read) { 266 /* in sync mode, we can touch the scatter request */ 267 scat_req->status = status; 268 if (!status && scat_req->virt_scat) 269 scat_req->status = 270 ath6kl_hif_cp_scat_dma_buf(scat_req, true); 271 } 272 273 return status; 274 } 275 276 static int ath6kl_hif_proc_counter_intr(struct ath6kl_device *dev) 277 { 278 u8 counter_int_status; 279 280 ath6kl_dbg(ATH6KL_DBG_IRQ, "counter interrupt\n"); 281 282 counter_int_status = dev->irq_proc_reg.counter_int_status & 283 dev->irq_en_reg.cntr_int_status_en; 284 285 ath6kl_dbg(ATH6KL_DBG_IRQ, 286 "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", 287 counter_int_status); 288 289 /* 290 * NOTE: other modules like GMBOX may use the counter interrupt for 291 * credit flow control on other counters, we only need to check for 292 * the debug assertion counter interrupt. 293 */ 294 if (counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK) 295 return ath6kl_hif_proc_dbg_intr(dev); 296 297 return 0; 298 } 299 300 static int ath6kl_hif_proc_err_intr(struct ath6kl_device *dev) 301 { 302 int status; 303 u8 error_int_status; 304 u8 reg_buf[4]; 305 306 ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n"); 307 308 error_int_status = dev->irq_proc_reg.error_int_status & 0x0F; 309 if (!error_int_status) { 310 WARN_ON(1); 311 return -EIO; 312 } 313 314 ath6kl_dbg(ATH6KL_DBG_IRQ, 315 "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n", 316 error_int_status); 317 318 if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status)) 319 ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n"); 320 321 if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status)) 322 ath6kl_err("rx underflow\n"); 323 324 if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status)) 325 ath6kl_err("tx overflow\n"); 326 327 /* Clear the interrupt */ 328 dev->irq_proc_reg.error_int_status &= ~error_int_status; 329 330 /* set W1C value to clear the interrupt, this hits the register first */ 331 reg_buf[0] = error_int_status; 332 reg_buf[1] = 0; 333 reg_buf[2] = 0; 334 reg_buf[3] = 0; 335 336 status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS, 337 reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); 338 339 if (status) 340 WARN_ON(1); 341 342 return status; 343 } 344 345 static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev) 346 { 347 int status; 348 u8 cpu_int_status; 349 u8 reg_buf[4]; 350 351 ath6kl_dbg(ATH6KL_DBG_IRQ, "cpu interrupt\n"); 352 353 cpu_int_status = dev->irq_proc_reg.cpu_int_status & 354 dev->irq_en_reg.cpu_int_status_en; 355 if (!cpu_int_status) { 356 WARN_ON(1); 357 return -EIO; 358 } 359 360 ath6kl_dbg(ATH6KL_DBG_IRQ, 361 "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", 362 cpu_int_status); 363 364 /* Clear the interrupt */ 365 dev->irq_proc_reg.cpu_int_status &= ~cpu_int_status; 366 367 /* 368 * Set up the register transfer buffer to hit the register 4 times , 369 * this is done to make the access 4-byte aligned to mitigate issues 370 * with host bus interconnects that restrict bus transfer lengths to 371 * be a multiple of 4-bytes. 372 */ 373 374 /* set W1C value to clear the interrupt, this hits the register first */ 375 reg_buf[0] = cpu_int_status; 376 /* the remaining are set to zero which have no-effect */ 377 reg_buf[1] = 0; 378 reg_buf[2] = 0; 379 reg_buf[3] = 0; 380 381 status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS, 382 reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); 383 384 if (status) 385 WARN_ON(1); 386 387 return status; 388 } 389 390 /* process pending interrupts synchronously */ 391 static int proc_pending_irqs(struct ath6kl_device *dev, bool *done) 392 { 393 struct ath6kl_irq_proc_registers *rg; 394 int status = 0; 395 u8 host_int_status = 0; 396 u32 lk_ahd = 0; 397 u8 htc_mbox = 1 << HTC_MAILBOX; 398 399 ath6kl_dbg(ATH6KL_DBG_IRQ, "proc_pending_irqs: (dev: 0x%p)\n", dev); 400 401 /* 402 * NOTE: HIF implementation guarantees that the context of this 403 * call allows us to perform SYNCHRONOUS I/O, that is we can block, 404 * sleep or call any API that can block or switch thread/task 405 * contexts. This is a fully schedulable context. 406 */ 407 408 /* 409 * Process pending intr only when int_status_en is clear, it may 410 * result in unnecessary bus transaction otherwise. Target may be 411 * unresponsive at the time. 412 */ 413 if (dev->irq_en_reg.int_status_en) { 414 /* 415 * Read the first 28 bytes of the HTC register table. This 416 * will yield us the value of different int status 417 * registers and the lookahead registers. 418 * 419 * length = sizeof(int_status) + sizeof(cpu_int_status) 420 * + sizeof(error_int_status) + 421 * sizeof(counter_int_status) + 422 * sizeof(mbox_frame) + sizeof(rx_lkahd_valid) 423 * + sizeof(hole) + sizeof(rx_lkahd) + 424 * sizeof(int_status_en) + 425 * sizeof(cpu_int_status_en) + 426 * sizeof(err_int_status_en) + 427 * sizeof(cntr_int_status_en); 428 */ 429 status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS, 430 (u8 *) &dev->irq_proc_reg, 431 sizeof(dev->irq_proc_reg), 432 HIF_RD_SYNC_BYTE_INC); 433 if (status) 434 goto out; 435 436 ath6kl_dump_registers(dev, &dev->irq_proc_reg, 437 &dev->irq_en_reg); 438 439 /* Update only those registers that are enabled */ 440 host_int_status = dev->irq_proc_reg.host_int_status & 441 dev->irq_en_reg.int_status_en; 442 443 /* Look at mbox status */ 444 if (host_int_status & htc_mbox) { 445 /* 446 * Mask out pending mbox value, we use "lookAhead as 447 * the real flag for mbox processing. 448 */ 449 host_int_status &= ~htc_mbox; 450 if (dev->irq_proc_reg.rx_lkahd_valid & 451 htc_mbox) { 452 rg = &dev->irq_proc_reg; 453 lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]); 454 if (!lk_ahd) 455 ath6kl_err("lookAhead is zero!\n"); 456 } 457 } 458 } 459 460 if (!host_int_status && !lk_ahd) { 461 *done = true; 462 goto out; 463 } 464 465 if (lk_ahd) { 466 int fetched = 0; 467 468 ath6kl_dbg(ATH6KL_DBG_IRQ, 469 "pending mailbox msg, lk_ahd: 0x%X\n", lk_ahd); 470 /* 471 * Mailbox Interrupt, the HTC layer may issue async 472 * requests to empty the mailbox. When emptying the recv 473 * mailbox we use the async handler above called from the 474 * completion routine of the callers read request. This can 475 * improve performance by reducing context switching when 476 * we rapidly pull packets. 477 */ 478 status = ath6kl_htc_rxmsg_pending_handler(dev->htc_cnxt, 479 lk_ahd, &fetched); 480 if (status) 481 goto out; 482 483 if (!fetched) 484 /* 485 * HTC could not pull any messages out due to lack 486 * of resources. 487 */ 488 dev->htc_cnxt->chk_irq_status_cnt = 0; 489 } 490 491 /* now handle the rest of them */ 492 ath6kl_dbg(ATH6KL_DBG_IRQ, 493 "valid interrupt source(s) for other interrupts: 0x%x\n", 494 host_int_status); 495 496 if (MS(HOST_INT_STATUS_CPU, host_int_status)) { 497 /* CPU Interrupt */ 498 status = ath6kl_hif_proc_cpu_intr(dev); 499 if (status) 500 goto out; 501 } 502 503 if (MS(HOST_INT_STATUS_ERROR, host_int_status)) { 504 /* Error Interrupt */ 505 status = ath6kl_hif_proc_err_intr(dev); 506 if (status) 507 goto out; 508 } 509 510 if (MS(HOST_INT_STATUS_COUNTER, host_int_status)) 511 /* Counter Interrupt */ 512 status = ath6kl_hif_proc_counter_intr(dev); 513 514 out: 515 /* 516 * An optimization to bypass reading the IRQ status registers 517 * unecessarily which can re-wake the target, if upper layers 518 * determine that we are in a low-throughput mode, we can rely on 519 * taking another interrupt rather than re-checking the status 520 * registers which can re-wake the target. 521 * 522 * NOTE : for host interfaces that makes use of detecting pending 523 * mbox messages at hif can not use this optimization due to 524 * possible side effects, SPI requires the host to drain all 525 * messages from the mailbox before exiting the ISR routine. 526 */ 527 528 ath6kl_dbg(ATH6KL_DBG_IRQ, 529 "bypassing irq status re-check, forcing done\n"); 530 531 if (!dev->htc_cnxt->chk_irq_status_cnt) 532 *done = true; 533 534 ath6kl_dbg(ATH6KL_DBG_IRQ, 535 "proc_pending_irqs: (done:%d, status=%d\n", *done, status); 536 537 return status; 538 } 539 540 /* interrupt handler, kicks off all interrupt processing */ 541 int ath6kl_hif_intr_bh_handler(struct ath6kl *ar) 542 { 543 struct ath6kl_device *dev = ar->htc_target->dev; 544 unsigned long timeout; 545 int status = 0; 546 bool done = false; 547 548 /* 549 * Reset counter used to flag a re-scan of IRQ status registers on 550 * the target. 551 */ 552 dev->htc_cnxt->chk_irq_status_cnt = 0; 553 554 /* 555 * IRQ processing is synchronous, interrupt status registers can be 556 * re-read. 557 */ 558 timeout = jiffies + msecs_to_jiffies(ATH6KL_HIF_COMMUNICATION_TIMEOUT); 559 while (time_before(jiffies, timeout) && !done) { 560 status = proc_pending_irqs(dev, &done); 561 if (status) 562 break; 563 } 564 565 return status; 566 } 567 EXPORT_SYMBOL(ath6kl_hif_intr_bh_handler); 568 569 static int ath6kl_hif_enable_intrs(struct ath6kl_device *dev) 570 { 571 struct ath6kl_irq_enable_reg regs; 572 int status; 573 574 spin_lock_bh(&dev->lock); 575 576 /* Enable all but ATH6KL CPU interrupts */ 577 dev->irq_en_reg.int_status_en = 578 SM(INT_STATUS_ENABLE_ERROR, 0x01) | 579 SM(INT_STATUS_ENABLE_CPU, 0x01) | 580 SM(INT_STATUS_ENABLE_COUNTER, 0x01); 581 582 /* 583 * NOTE: There are some cases where HIF can do detection of 584 * pending mbox messages which is disabled now. 585 */ 586 dev->irq_en_reg.int_status_en |= SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01); 587 588 /* Set up the CPU Interrupt status Register */ 589 dev->irq_en_reg.cpu_int_status_en = 0; 590 591 /* Set up the Error Interrupt status Register */ 592 dev->irq_en_reg.err_int_status_en = 593 SM(ERROR_STATUS_ENABLE_RX_UNDERFLOW, 0x01) | 594 SM(ERROR_STATUS_ENABLE_TX_OVERFLOW, 0x1); 595 596 /* 597 * Enable Counter interrupt status register to get fatal errors for 598 * debugging. 599 */ 600 dev->irq_en_reg.cntr_int_status_en = SM(COUNTER_INT_STATUS_ENABLE_BIT, 601 ATH6KL_TARGET_DEBUG_INTR_MASK); 602 memcpy(®s, &dev->irq_en_reg, sizeof(regs)); 603 604 spin_unlock_bh(&dev->lock); 605 606 status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS, 607 ®s.int_status_en, sizeof(regs), 608 HIF_WR_SYNC_BYTE_INC); 609 610 if (status) 611 ath6kl_err("failed to update interrupt ctl reg err: %d\n", 612 status); 613 614 return status; 615 } 616 617 int ath6kl_hif_disable_intrs(struct ath6kl_device *dev) 618 { 619 struct ath6kl_irq_enable_reg regs; 620 621 spin_lock_bh(&dev->lock); 622 /* Disable all interrupts */ 623 dev->irq_en_reg.int_status_en = 0; 624 dev->irq_en_reg.cpu_int_status_en = 0; 625 dev->irq_en_reg.err_int_status_en = 0; 626 dev->irq_en_reg.cntr_int_status_en = 0; 627 memcpy(®s, &dev->irq_en_reg, sizeof(regs)); 628 spin_unlock_bh(&dev->lock); 629 630 return hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS, 631 ®s.int_status_en, sizeof(regs), 632 HIF_WR_SYNC_BYTE_INC); 633 } 634 635 /* enable device interrupts */ 636 int ath6kl_hif_unmask_intrs(struct ath6kl_device *dev) 637 { 638 int status = 0; 639 640 /* 641 * Make sure interrupt are disabled before unmasking at the HIF 642 * layer. The rationale here is that between device insertion 643 * (where we clear the interrupts the first time) and when HTC 644 * is finally ready to handle interrupts, other software can perform 645 * target "soft" resets. The ATH6KL interrupt enables reset back to an 646 * "enabled" state when this happens. 647 */ 648 ath6kl_hif_disable_intrs(dev); 649 650 /* unmask the host controller interrupts */ 651 ath6kl_hif_irq_enable(dev->ar); 652 status = ath6kl_hif_enable_intrs(dev); 653 654 return status; 655 } 656 657 /* disable all device interrupts */ 658 int ath6kl_hif_mask_intrs(struct ath6kl_device *dev) 659 { 660 /* 661 * Mask the interrupt at the HIF layer to avoid any stray interrupt 662 * taken while we zero out our shadow registers in 663 * ath6kl_hif_disable_intrs(). 664 */ 665 ath6kl_hif_irq_disable(dev->ar); 666 667 return ath6kl_hif_disable_intrs(dev); 668 } 669 670 int ath6kl_hif_setup(struct ath6kl_device *dev) 671 { 672 int status = 0; 673 674 spin_lock_init(&dev->lock); 675 676 /* 677 * NOTE: we actually get the block size of a mailbox other than 0, 678 * for SDIO the block size on mailbox 0 is artificially set to 1. 679 * So we use the block size that is set for the other 3 mailboxes. 680 */ 681 dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size; 682 683 /* must be a power of 2 */ 684 if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) { 685 WARN_ON(1); 686 status = -EINVAL; 687 goto fail_setup; 688 } 689 690 /* assemble mask, used for padding to a block */ 691 dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1; 692 693 ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n", 694 dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); 695 696 /* usb doesn't support enabling interrupts */ 697 /* FIXME: remove check once USB support is implemented */ 698 if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) 699 return 0; 700 701 status = ath6kl_hif_disable_intrs(dev); 702 703 fail_setup: 704 return status; 705 706 } 707