0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include "hif.h"
0018
0019 #include <linux/export.h>
0020
0021 #include "core.h"
0022 #include "target.h"
0023 #include "hif-ops.h"
0024 #include "debug.h"
0025 #include "trace.h"
0026
0027 #define MAILBOX_FOR_BLOCK_SIZE 1
0028
0029 #define ATH6KL_TIME_QUANTUM 10
0030
0031 static int ath6kl_hif_cp_scat_dma_buf(struct hif_scatter_req *req,
0032 bool from_dma)
0033 {
0034 u8 *buf;
0035 int i;
0036
0037 buf = req->virt_dma_buf;
0038
0039 for (i = 0; i < req->scat_entries; i++) {
0040 if (from_dma)
0041 memcpy(req->scat_list[i].buf, buf,
0042 req->scat_list[i].len);
0043 else
0044 memcpy(buf, req->scat_list[i].buf,
0045 req->scat_list[i].len);
0046
0047 buf += req->scat_list[i].len;
0048 }
0049
0050 return 0;
0051 }
0052
0053 int ath6kl_hif_rw_comp_handler(void *context, int status)
0054 {
0055 struct htc_packet *packet = context;
0056
0057 ath6kl_dbg(ATH6KL_DBG_HIF, "hif rw completion pkt 0x%p status %d\n",
0058 packet, status);
0059
0060 packet->status = status;
0061 packet->completion(packet->context, packet);
0062
0063 return 0;
0064 }
0065 EXPORT_SYMBOL(ath6kl_hif_rw_comp_handler);
0066
0067 #define REGISTER_DUMP_COUNT 60
0068 #define REGISTER_DUMP_LEN_MAX 60
0069
0070 static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
0071 {
0072 __le32 regdump_val[REGISTER_DUMP_LEN_MAX];
0073 u32 i, address, regdump_addr = 0;
0074 int ret;
0075
0076
0077 address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state));
0078 address = TARG_VTOP(ar->target_type, address);
0079
0080
0081 ret = ath6kl_diag_read32(ar, address, ®dump_addr);
0082
0083 if (ret || !regdump_addr) {
0084 ath6kl_warn("failed to get ptr to register dump area: %d\n",
0085 ret);
0086 return;
0087 }
0088
0089 ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n",
0090 regdump_addr);
0091 regdump_addr = TARG_VTOP(ar->target_type, regdump_addr);
0092
0093
0094 ret = ath6kl_diag_read(ar, regdump_addr, (u8 *)®dump_val[0],
0095 REGISTER_DUMP_COUNT * (sizeof(u32)));
0096 if (ret) {
0097 ath6kl_warn("failed to get register dump: %d\n", ret);
0098 return;
0099 }
0100
0101 ath6kl_info("crash dump:\n");
0102 ath6kl_info("hw 0x%x fw %s\n", ar->wiphy->hw_version,
0103 ar->wiphy->fw_version);
0104
0105 BUILD_BUG_ON(REGISTER_DUMP_COUNT % 4);
0106
0107 for (i = 0; i < REGISTER_DUMP_COUNT; i += 4) {
0108 ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
0109 i,
0110 le32_to_cpu(regdump_val[i]),
0111 le32_to_cpu(regdump_val[i + 1]),
0112 le32_to_cpu(regdump_val[i + 2]),
0113 le32_to_cpu(regdump_val[i + 3]));
0114 }
0115 }
0116
0117 static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
0118 {
0119 u32 dummy;
0120 int ret;
0121
0122 ath6kl_warn("firmware crashed\n");
0123
0124
0125
0126
0127
0128 ret = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS,
0129 (u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC);
0130 if (ret)
0131 ath6kl_warn("Failed to clear debug interrupt: %d\n", ret);
0132
0133 ath6kl_hif_dump_fw_crash(dev->ar);
0134 ath6kl_read_fwlogs(dev->ar);
0135 ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT);
0136
0137 return ret;
0138 }
0139
0140
0141 int ath6kl_hif_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
0142 int timeout)
0143 {
0144 struct ath6kl_irq_proc_registers *rg;
0145 int status = 0, i;
0146 u8 htc_mbox = 1 << HTC_MAILBOX;
0147
0148 for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) {
0149
0150 status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
0151 (u8 *) &dev->irq_proc_reg,
0152 sizeof(dev->irq_proc_reg),
0153 HIF_RD_SYNC_BYTE_INC);
0154
0155 if (status) {
0156 ath6kl_err("failed to read reg table\n");
0157 return status;
0158 }
0159
0160
0161 if (dev->irq_proc_reg.host_int_status & htc_mbox) {
0162 if (dev->irq_proc_reg.rx_lkahd_valid &
0163 htc_mbox) {
0164
0165
0166
0167
0168 rg = &dev->irq_proc_reg;
0169 *lk_ahd =
0170 le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
0171 break;
0172 }
0173 }
0174
0175
0176 mdelay(ATH6KL_TIME_QUANTUM);
0177 ath6kl_dbg(ATH6KL_DBG_HIF, "hif retry mbox poll try %d\n", i);
0178 }
0179
0180 if (i == 0) {
0181 ath6kl_err("timeout waiting for recv message\n");
0182 status = -ETIME;
0183
0184 if (dev->irq_proc_reg.counter_int_status &
0185 ATH6KL_TARGET_DEBUG_INTR_MASK)
0186
0187
0188
0189
0190 ath6kl_hif_proc_dbg_intr(dev);
0191 }
0192
0193 return status;
0194 }
0195
0196
0197
0198
0199
0200 int ath6kl_hif_rx_control(struct ath6kl_device *dev, bool enable_rx)
0201 {
0202 struct ath6kl_irq_enable_reg regs;
0203 int status = 0;
0204
0205 ath6kl_dbg(ATH6KL_DBG_HIF, "hif rx %s\n",
0206 enable_rx ? "enable" : "disable");
0207
0208
0209 spin_lock_bh(&dev->lock);
0210
0211 if (enable_rx)
0212 dev->irq_en_reg.int_status_en |=
0213 SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
0214 else
0215 dev->irq_en_reg.int_status_en &=
0216 ~SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
0217
0218 memcpy(®s, &dev->irq_en_reg, sizeof(regs));
0219
0220 spin_unlock_bh(&dev->lock);
0221
0222 status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
0223 ®s.int_status_en,
0224 sizeof(struct ath6kl_irq_enable_reg),
0225 HIF_WR_SYNC_BYTE_INC);
0226
0227 return status;
0228 }
0229
0230 int ath6kl_hif_submit_scat_req(struct ath6kl_device *dev,
0231 struct hif_scatter_req *scat_req, bool read)
0232 {
0233 int status = 0;
0234
0235 if (read) {
0236 scat_req->req = HIF_RD_SYNC_BLOCK_FIX;
0237 scat_req->addr = dev->ar->mbox_info.htc_addr;
0238 } else {
0239 scat_req->req = HIF_WR_ASYNC_BLOCK_INC;
0240
0241 scat_req->addr =
0242 (scat_req->len > HIF_MBOX_WIDTH) ?
0243 dev->ar->mbox_info.htc_ext_addr :
0244 dev->ar->mbox_info.htc_addr;
0245 }
0246
0247 ath6kl_dbg(ATH6KL_DBG_HIF,
0248 "hif submit scatter request entries %d len %d mbox 0x%x %s %s\n",
0249 scat_req->scat_entries, scat_req->len,
0250 scat_req->addr, !read ? "async" : "sync",
0251 (read) ? "rd" : "wr");
0252
0253 if (!read && scat_req->virt_scat) {
0254 status = ath6kl_hif_cp_scat_dma_buf(scat_req, false);
0255 if (status) {
0256 scat_req->status = status;
0257 scat_req->complete(dev->ar->htc_target, scat_req);
0258 return 0;
0259 }
0260 }
0261
0262 status = ath6kl_hif_scat_req_rw(dev->ar, scat_req);
0263
0264 if (read) {
0265
0266 scat_req->status = status;
0267 if (!status && scat_req->virt_scat)
0268 scat_req->status =
0269 ath6kl_hif_cp_scat_dma_buf(scat_req, true);
0270 }
0271
0272 return status;
0273 }
0274
0275 static int ath6kl_hif_proc_counter_intr(struct ath6kl_device *dev)
0276 {
0277 u8 counter_int_status;
0278
0279 ath6kl_dbg(ATH6KL_DBG_IRQ, "counter interrupt\n");
0280
0281 counter_int_status = dev->irq_proc_reg.counter_int_status &
0282 dev->irq_en_reg.cntr_int_status_en;
0283
0284 ath6kl_dbg(ATH6KL_DBG_IRQ,
0285 "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
0286 counter_int_status);
0287
0288
0289
0290
0291
0292
0293 if (counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK)
0294 return ath6kl_hif_proc_dbg_intr(dev);
0295
0296 return 0;
0297 }
0298
0299 static int ath6kl_hif_proc_err_intr(struct ath6kl_device *dev)
0300 {
0301 int status;
0302 u8 error_int_status;
0303 u8 reg_buf[4];
0304
0305 ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n");
0306
0307 error_int_status = dev->irq_proc_reg.error_int_status & 0x0F;
0308 if (!error_int_status) {
0309 WARN_ON(1);
0310 return -EIO;
0311 }
0312
0313 ath6kl_dbg(ATH6KL_DBG_IRQ,
0314 "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
0315 error_int_status);
0316
0317 if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status))
0318 ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n");
0319
0320 if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status))
0321 ath6kl_err("rx underflow\n");
0322
0323 if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status))
0324 ath6kl_err("tx overflow\n");
0325
0326
0327 dev->irq_proc_reg.error_int_status &= ~error_int_status;
0328
0329
0330 reg_buf[0] = error_int_status;
0331 reg_buf[1] = 0;
0332 reg_buf[2] = 0;
0333 reg_buf[3] = 0;
0334
0335 status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,
0336 reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
0337
0338 WARN_ON(status);
0339
0340 return status;
0341 }
0342
0343 static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev)
0344 {
0345 int status;
0346 u8 cpu_int_status;
0347 u8 reg_buf[4];
0348
0349 ath6kl_dbg(ATH6KL_DBG_IRQ, "cpu interrupt\n");
0350
0351 cpu_int_status = dev->irq_proc_reg.cpu_int_status &
0352 dev->irq_en_reg.cpu_int_status_en;
0353 if (!cpu_int_status) {
0354 WARN_ON(1);
0355 return -EIO;
0356 }
0357
0358 ath6kl_dbg(ATH6KL_DBG_IRQ,
0359 "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
0360 cpu_int_status);
0361
0362
0363 dev->irq_proc_reg.cpu_int_status &= ~cpu_int_status;
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373 reg_buf[0] = cpu_int_status;
0374
0375 reg_buf[1] = 0;
0376 reg_buf[2] = 0;
0377 reg_buf[3] = 0;
0378
0379 status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS,
0380 reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
0381
0382 WARN_ON(status);
0383
0384 return status;
0385 }
0386
0387
0388 static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
0389 {
0390 struct ath6kl_irq_proc_registers *rg;
0391 int status = 0;
0392 u8 host_int_status = 0;
0393 u32 lk_ahd = 0;
0394 u8 htc_mbox = 1 << HTC_MAILBOX;
0395
0396 ath6kl_dbg(ATH6KL_DBG_IRQ, "proc_pending_irqs: (dev: 0x%p)\n", dev);
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410 if (dev->irq_en_reg.int_status_en) {
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426 status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
0427 (u8 *) &dev->irq_proc_reg,
0428 sizeof(dev->irq_proc_reg),
0429 HIF_RD_SYNC_BYTE_INC);
0430 if (status)
0431 goto out;
0432
0433 ath6kl_dump_registers(dev, &dev->irq_proc_reg,
0434 &dev->irq_en_reg);
0435 trace_ath6kl_sdio_irq(&dev->irq_en_reg,
0436 sizeof(dev->irq_en_reg));
0437
0438
0439 host_int_status = dev->irq_proc_reg.host_int_status &
0440 dev->irq_en_reg.int_status_en;
0441
0442
0443 if (host_int_status & htc_mbox) {
0444
0445
0446
0447
0448 host_int_status &= ~htc_mbox;
0449 if (dev->irq_proc_reg.rx_lkahd_valid &
0450 htc_mbox) {
0451 rg = &dev->irq_proc_reg;
0452 lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
0453 if (!lk_ahd)
0454 ath6kl_err("lookAhead is zero!\n");
0455 }
0456 }
0457 }
0458
0459 if (!host_int_status && !lk_ahd) {
0460 *done = true;
0461 goto out;
0462 }
0463
0464 if (lk_ahd) {
0465 int fetched = 0;
0466
0467 ath6kl_dbg(ATH6KL_DBG_IRQ,
0468 "pending mailbox msg, lk_ahd: 0x%X\n", lk_ahd);
0469
0470
0471
0472
0473
0474
0475
0476
0477 status = ath6kl_htc_rxmsg_pending_handler(dev->htc_cnxt,
0478 lk_ahd, &fetched);
0479 if (status)
0480 goto out;
0481
0482 if (!fetched)
0483
0484
0485
0486
0487 dev->htc_cnxt->chk_irq_status_cnt = 0;
0488 }
0489
0490
0491 ath6kl_dbg(ATH6KL_DBG_IRQ,
0492 "valid interrupt source(s) for other interrupts: 0x%x\n",
0493 host_int_status);
0494
0495 if (MS(HOST_INT_STATUS_CPU, host_int_status)) {
0496
0497 status = ath6kl_hif_proc_cpu_intr(dev);
0498 if (status)
0499 goto out;
0500 }
0501
0502 if (MS(HOST_INT_STATUS_ERROR, host_int_status)) {
0503
0504 status = ath6kl_hif_proc_err_intr(dev);
0505 if (status)
0506 goto out;
0507 }
0508
0509 if (MS(HOST_INT_STATUS_COUNTER, host_int_status))
0510
0511 status = ath6kl_hif_proc_counter_intr(dev);
0512
0513 out:
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527 ath6kl_dbg(ATH6KL_DBG_IRQ,
0528 "bypassing irq status re-check, forcing done\n");
0529
0530 if (!dev->htc_cnxt->chk_irq_status_cnt)
0531 *done = true;
0532
0533 ath6kl_dbg(ATH6KL_DBG_IRQ,
0534 "proc_pending_irqs: (done:%d, status=%d\n", *done, status);
0535
0536 return status;
0537 }
0538
0539
0540 int ath6kl_hif_intr_bh_handler(struct ath6kl *ar)
0541 {
0542 struct ath6kl_device *dev = ar->htc_target->dev;
0543 unsigned long timeout;
0544 int status = 0;
0545 bool done = false;
0546
0547
0548
0549
0550
0551 dev->htc_cnxt->chk_irq_status_cnt = 0;
0552
0553
0554
0555
0556
0557 timeout = jiffies + msecs_to_jiffies(ATH6KL_HIF_COMMUNICATION_TIMEOUT);
0558 while (time_before(jiffies, timeout) && !done) {
0559 status = proc_pending_irqs(dev, &done);
0560 if (status)
0561 break;
0562 }
0563
0564 return status;
0565 }
0566 EXPORT_SYMBOL(ath6kl_hif_intr_bh_handler);
0567
0568 static int ath6kl_hif_enable_intrs(struct ath6kl_device *dev)
0569 {
0570 struct ath6kl_irq_enable_reg regs;
0571 int status;
0572
0573 spin_lock_bh(&dev->lock);
0574
0575
0576 dev->irq_en_reg.int_status_en =
0577 SM(INT_STATUS_ENABLE_ERROR, 0x01) |
0578 SM(INT_STATUS_ENABLE_CPU, 0x01) |
0579 SM(INT_STATUS_ENABLE_COUNTER, 0x01);
0580
0581
0582
0583
0584
0585 dev->irq_en_reg.int_status_en |= SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
0586
0587
0588 dev->irq_en_reg.cpu_int_status_en = 0;
0589
0590
0591 dev->irq_en_reg.err_int_status_en =
0592 SM(ERROR_STATUS_ENABLE_RX_UNDERFLOW, 0x01) |
0593 SM(ERROR_STATUS_ENABLE_TX_OVERFLOW, 0x1);
0594
0595
0596
0597
0598
0599 dev->irq_en_reg.cntr_int_status_en = SM(COUNTER_INT_STATUS_ENABLE_BIT,
0600 ATH6KL_TARGET_DEBUG_INTR_MASK);
0601 memcpy(®s, &dev->irq_en_reg, sizeof(regs));
0602
0603 spin_unlock_bh(&dev->lock);
0604
0605 status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
0606 ®s.int_status_en, sizeof(regs),
0607 HIF_WR_SYNC_BYTE_INC);
0608
0609 if (status)
0610 ath6kl_err("failed to update interrupt ctl reg err: %d\n",
0611 status);
0612
0613 return status;
0614 }
0615
0616 int ath6kl_hif_disable_intrs(struct ath6kl_device *dev)
0617 {
0618 struct ath6kl_irq_enable_reg regs;
0619
0620 spin_lock_bh(&dev->lock);
0621
0622 dev->irq_en_reg.int_status_en = 0;
0623 dev->irq_en_reg.cpu_int_status_en = 0;
0624 dev->irq_en_reg.err_int_status_en = 0;
0625 dev->irq_en_reg.cntr_int_status_en = 0;
0626 memcpy(®s, &dev->irq_en_reg, sizeof(regs));
0627 spin_unlock_bh(&dev->lock);
0628
0629 return hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
0630 ®s.int_status_en, sizeof(regs),
0631 HIF_WR_SYNC_BYTE_INC);
0632 }
0633
0634
0635 int ath6kl_hif_unmask_intrs(struct ath6kl_device *dev)
0636 {
0637 int status = 0;
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647 ath6kl_hif_disable_intrs(dev);
0648
0649
0650 ath6kl_hif_irq_enable(dev->ar);
0651 status = ath6kl_hif_enable_intrs(dev);
0652
0653 return status;
0654 }
0655
0656
0657 int ath6kl_hif_mask_intrs(struct ath6kl_device *dev)
0658 {
0659
0660
0661
0662
0663
0664 ath6kl_hif_irq_disable(dev->ar);
0665
0666 return ath6kl_hif_disable_intrs(dev);
0667 }
0668
0669 int ath6kl_hif_setup(struct ath6kl_device *dev)
0670 {
0671 int status = 0;
0672
0673 spin_lock_init(&dev->lock);
0674
0675
0676
0677
0678
0679
0680 dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size;
0681
0682
0683 if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) {
0684 WARN_ON(1);
0685 status = -EINVAL;
0686 goto fail_setup;
0687 }
0688
0689
0690 dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1;
0691
0692 ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
0693 dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
0694
0695 status = ath6kl_hif_disable_intrs(dev);
0696
0697 fail_setup:
0698 return status;
0699 }