1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "hif.h"
18
19#include <linux/export.h>
20
21#include "core.h"
22#include "target.h"
23#include "hif-ops.h"
24#include "debug.h"
25#include "trace.h"
26
27#define MAILBOX_FOR_BLOCK_SIZE 1
28
29#define ATH6KL_TIME_QUANTUM 10
30
31static int ath6kl_hif_cp_scat_dma_buf(struct hif_scatter_req *req,
32 bool from_dma)
33{
34 u8 *buf;
35 int i;
36
37 buf = req->virt_dma_buf;
38
39 for (i = 0; i < req->scat_entries; i++) {
40 if (from_dma)
41 memcpy(req->scat_list[i].buf, buf,
42 req->scat_list[i].len);
43 else
44 memcpy(buf, req->scat_list[i].buf,
45 req->scat_list[i].len);
46
47 buf += req->scat_list[i].len;
48 }
49
50 return 0;
51}
52
53int ath6kl_hif_rw_comp_handler(void *context, int status)
54{
55 struct htc_packet *packet = context;
56
57 ath6kl_dbg(ATH6KL_DBG_HIF, "hif rw completion pkt 0x%p status %d\n",
58 packet, status);
59
60 packet->status = status;
61 packet->completion(packet->context, packet);
62
63 return 0;
64}
65EXPORT_SYMBOL(ath6kl_hif_rw_comp_handler);
66
67#define REG_DUMP_COUNT_AR6003 60
68#define REGISTER_DUMP_LEN_MAX 60
69
70static void ath6kl_hif_dump_fw_crash(struct ath6kl *ar)
71{
72 __le32 regdump_val[REGISTER_DUMP_LEN_MAX];
73 u32 i, address, regdump_addr = 0;
74 int ret;
75
76 if (ar->target_type != TARGET_TYPE_AR6003)
77 return;
78
79
80 address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state));
81 address = TARG_VTOP(ar->target_type, address);
82
83
84 ret = ath6kl_diag_read32(ar, address, ®dump_addr);
85
86 if (ret || !regdump_addr) {
87 ath6kl_warn("failed to get ptr to register dump area: %d\n",
88 ret);
89 return;
90 }
91
92 ath6kl_dbg(ATH6KL_DBG_IRQ, "register dump data address 0x%x\n",
93 regdump_addr);
94 regdump_addr = TARG_VTOP(ar->target_type, regdump_addr);
95
96
97 ret = ath6kl_diag_read(ar, regdump_addr, (u8 *)®dump_val[0],
98 REG_DUMP_COUNT_AR6003 * (sizeof(u32)));
99 if (ret) {
100 ath6kl_warn("failed to get register dump: %d\n", ret);
101 return;
102 }
103
104 ath6kl_info("crash dump:\n");
105 ath6kl_info("hw 0x%x fw %s\n", ar->wiphy->hw_version,
106 ar->wiphy->fw_version);
107
108 BUILD_BUG_ON(REG_DUMP_COUNT_AR6003 % 4);
109
110 for (i = 0; i < REG_DUMP_COUNT_AR6003; i += 4) {
111 ath6kl_info("%d: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
112 i,
113 le32_to_cpu(regdump_val[i]),
114 le32_to_cpu(regdump_val[i + 1]),
115 le32_to_cpu(regdump_val[i + 2]),
116 le32_to_cpu(regdump_val[i + 3]));
117 }
118}
119
120static 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
129
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 ath6kl_read_fwlogs(dev->ar);
138 ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT);
139
140 return ret;
141}
142
143
144int ath6kl_hif_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd,
145 int timeout)
146{
147 struct ath6kl_irq_proc_registers *rg;
148 int status = 0, i;
149 u8 htc_mbox = 1 << HTC_MAILBOX;
150
151 for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) {
152
153 status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS,
154 (u8 *) &dev->irq_proc_reg,
155 sizeof(dev->irq_proc_reg),
156 HIF_RD_SYNC_BYTE_INC);
157
158 if (status) {
159 ath6kl_err("failed to read reg table\n");
160 return status;
161 }
162
163
164 if (dev->irq_proc_reg.host_int_status & htc_mbox) {
165 if (dev->irq_proc_reg.rx_lkahd_valid &
166 htc_mbox) {
167
168
169
170
171 rg = &dev->irq_proc_reg;
172 *lk_ahd =
173 le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
174 break;
175 }
176 }
177
178
179 mdelay(ATH6KL_TIME_QUANTUM);
180 ath6kl_dbg(ATH6KL_DBG_HIF, "hif retry mbox poll try %d\n", i);
181 }
182
183 if (i == 0) {
184 ath6kl_err("timeout waiting for recv message\n");
185 status = -ETIME;
186
187 if (dev->irq_proc_reg.counter_int_status &
188 ATH6KL_TARGET_DEBUG_INTR_MASK)
189
190
191
192
193 ath6kl_hif_proc_dbg_intr(dev);
194 }
195
196 return status;
197}
198
199
200
201
202
203int ath6kl_hif_rx_control(struct ath6kl_device *dev, bool enable_rx)
204{
205 struct ath6kl_irq_enable_reg regs;
206 int status = 0;
207
208 ath6kl_dbg(ATH6KL_DBG_HIF, "hif rx %s\n",
209 enable_rx ? "enable" : "disable");
210
211
212 spin_lock_bh(&dev->lock);
213
214 if (enable_rx)
215 dev->irq_en_reg.int_status_en |=
216 SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
217 else
218 dev->irq_en_reg.int_status_en &=
219 ~SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
220
221 memcpy(®s, &dev->irq_en_reg, sizeof(regs));
222
223 spin_unlock_bh(&dev->lock);
224
225 status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
226 ®s.int_status_en,
227 sizeof(struct ath6kl_irq_enable_reg),
228 HIF_WR_SYNC_BYTE_INC);
229
230 return status;
231}
232
233int ath6kl_hif_submit_scat_req(struct ath6kl_device *dev,
234 struct hif_scatter_req *scat_req, bool read)
235{
236 int status = 0;
237
238 if (read) {
239 scat_req->req = HIF_RD_SYNC_BLOCK_FIX;
240 scat_req->addr = dev->ar->mbox_info.htc_addr;
241 } else {
242 scat_req->req = HIF_WR_ASYNC_BLOCK_INC;
243
244 scat_req->addr =
245 (scat_req->len > HIF_MBOX_WIDTH) ?
246 dev->ar->mbox_info.htc_ext_addr :
247 dev->ar->mbox_info.htc_addr;
248 }
249
250 ath6kl_dbg(ATH6KL_DBG_HIF,
251 "hif submit scatter request entries %d len %d mbox 0x%x %s %s\n",
252 scat_req->scat_entries, scat_req->len,
253 scat_req->addr, !read ? "async" : "sync",
254 (read) ? "rd" : "wr");
255
256 if (!read && scat_req->virt_scat) {
257 status = ath6kl_hif_cp_scat_dma_buf(scat_req, false);
258 if (status) {
259 scat_req->status = status;
260 scat_req->complete(dev->ar->htc_target, scat_req);
261 return 0;
262 }
263 }
264
265 status = ath6kl_hif_scat_req_rw(dev->ar, scat_req);
266
267 if (read) {
268
269 scat_req->status = status;
270 if (!status && scat_req->virt_scat)
271 scat_req->status =
272 ath6kl_hif_cp_scat_dma_buf(scat_req, true);
273 }
274
275 return status;
276}
277
278static int ath6kl_hif_proc_counter_intr(struct ath6kl_device *dev)
279{
280 u8 counter_int_status;
281
282 ath6kl_dbg(ATH6KL_DBG_IRQ, "counter interrupt\n");
283
284 counter_int_status = dev->irq_proc_reg.counter_int_status &
285 dev->irq_en_reg.cntr_int_status_en;
286
287 ath6kl_dbg(ATH6KL_DBG_IRQ,
288 "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
289 counter_int_status);
290
291
292
293
294
295
296 if (counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK)
297 return ath6kl_hif_proc_dbg_intr(dev);
298
299 return 0;
300}
301
302static int ath6kl_hif_proc_err_intr(struct ath6kl_device *dev)
303{
304 int status;
305 u8 error_int_status;
306 u8 reg_buf[4];
307
308 ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n");
309
310 error_int_status = dev->irq_proc_reg.error_int_status & 0x0F;
311 if (!error_int_status) {
312 WARN_ON(1);
313 return -EIO;
314 }
315
316 ath6kl_dbg(ATH6KL_DBG_IRQ,
317 "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
318 error_int_status);
319
320 if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status))
321 ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n");
322
323 if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status))
324 ath6kl_err("rx underflow\n");
325
326 if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status))
327 ath6kl_err("tx overflow\n");
328
329
330 dev->irq_proc_reg.error_int_status &= ~error_int_status;
331
332
333 reg_buf[0] = error_int_status;
334 reg_buf[1] = 0;
335 reg_buf[2] = 0;
336 reg_buf[3] = 0;
337
338 status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,
339 reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
340
341 WARN_ON(status);
342
343 return status;
344}
345
346static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev)
347{
348 int status;
349 u8 cpu_int_status;
350 u8 reg_buf[4];
351
352 ath6kl_dbg(ATH6KL_DBG_IRQ, "cpu interrupt\n");
353
354 cpu_int_status = dev->irq_proc_reg.cpu_int_status &
355 dev->irq_en_reg.cpu_int_status_en;
356 if (!cpu_int_status) {
357 WARN_ON(1);
358 return -EIO;
359 }
360
361 ath6kl_dbg(ATH6KL_DBG_IRQ,
362 "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
363 cpu_int_status);
364
365
366 dev->irq_proc_reg.cpu_int_status &= ~cpu_int_status;
367
368
369
370
371
372
373
374
375
376 reg_buf[0] = cpu_int_status;
377
378 reg_buf[1] = 0;
379 reg_buf[2] = 0;
380 reg_buf[3] = 0;
381
382 status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS,
383 reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
384
385 WARN_ON(status);
386
387 return status;
388}
389
390
391static 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
403
404
405
406
407
408
409
410
411
412
413 if (dev->irq_en_reg.int_status_en) {
414
415
416
417
418
419
420
421
422
423
424
425
426
427
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 trace_ath6kl_sdio_irq(&dev->irq_en_reg,
439 sizeof(dev->irq_en_reg));
440
441
442 host_int_status = dev->irq_proc_reg.host_int_status &
443 dev->irq_en_reg.int_status_en;
444
445
446 if (host_int_status & htc_mbox) {
447
448
449
450
451 host_int_status &= ~htc_mbox;
452 if (dev->irq_proc_reg.rx_lkahd_valid &
453 htc_mbox) {
454 rg = &dev->irq_proc_reg;
455 lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]);
456 if (!lk_ahd)
457 ath6kl_err("lookAhead is zero!\n");
458 }
459 }
460 }
461
462 if (!host_int_status && !lk_ahd) {
463 *done = true;
464 goto out;
465 }
466
467 if (lk_ahd) {
468 int fetched = 0;
469
470 ath6kl_dbg(ATH6KL_DBG_IRQ,
471 "pending mailbox msg, lk_ahd: 0x%X\n", lk_ahd);
472
473
474
475
476
477
478
479
480 status = ath6kl_htc_rxmsg_pending_handler(dev->htc_cnxt,
481 lk_ahd, &fetched);
482 if (status)
483 goto out;
484
485 if (!fetched)
486
487
488
489
490 dev->htc_cnxt->chk_irq_status_cnt = 0;
491 }
492
493
494 ath6kl_dbg(ATH6KL_DBG_IRQ,
495 "valid interrupt source(s) for other interrupts: 0x%x\n",
496 host_int_status);
497
498 if (MS(HOST_INT_STATUS_CPU, host_int_status)) {
499
500 status = ath6kl_hif_proc_cpu_intr(dev);
501 if (status)
502 goto out;
503 }
504
505 if (MS(HOST_INT_STATUS_ERROR, host_int_status)) {
506
507 status = ath6kl_hif_proc_err_intr(dev);
508 if (status)
509 goto out;
510 }
511
512 if (MS(HOST_INT_STATUS_COUNTER, host_int_status))
513
514 status = ath6kl_hif_proc_counter_intr(dev);
515
516out:
517
518
519
520
521
522
523
524
525
526
527
528
529
530 ath6kl_dbg(ATH6KL_DBG_IRQ,
531 "bypassing irq status re-check, forcing done\n");
532
533 if (!dev->htc_cnxt->chk_irq_status_cnt)
534 *done = true;
535
536 ath6kl_dbg(ATH6KL_DBG_IRQ,
537 "proc_pending_irqs: (done:%d, status=%d\n", *done, status);
538
539 return status;
540}
541
542
543int ath6kl_hif_intr_bh_handler(struct ath6kl *ar)
544{
545 struct ath6kl_device *dev = ar->htc_target->dev;
546 unsigned long timeout;
547 int status = 0;
548 bool done = false;
549
550
551
552
553
554 dev->htc_cnxt->chk_irq_status_cnt = 0;
555
556
557
558
559
560 timeout = jiffies + msecs_to_jiffies(ATH6KL_HIF_COMMUNICATION_TIMEOUT);
561 while (time_before(jiffies, timeout) && !done) {
562 status = proc_pending_irqs(dev, &done);
563 if (status)
564 break;
565 }
566
567 return status;
568}
569EXPORT_SYMBOL(ath6kl_hif_intr_bh_handler);
570
571static int ath6kl_hif_enable_intrs(struct ath6kl_device *dev)
572{
573 struct ath6kl_irq_enable_reg regs;
574 int status;
575
576 spin_lock_bh(&dev->lock);
577
578
579 dev->irq_en_reg.int_status_en =
580 SM(INT_STATUS_ENABLE_ERROR, 0x01) |
581 SM(INT_STATUS_ENABLE_CPU, 0x01) |
582 SM(INT_STATUS_ENABLE_COUNTER, 0x01);
583
584
585
586
587
588 dev->irq_en_reg.int_status_en |= SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01);
589
590
591 dev->irq_en_reg.cpu_int_status_en = 0;
592
593
594 dev->irq_en_reg.err_int_status_en =
595 SM(ERROR_STATUS_ENABLE_RX_UNDERFLOW, 0x01) |
596 SM(ERROR_STATUS_ENABLE_TX_OVERFLOW, 0x1);
597
598
599
600
601
602 dev->irq_en_reg.cntr_int_status_en = SM(COUNTER_INT_STATUS_ENABLE_BIT,
603 ATH6KL_TARGET_DEBUG_INTR_MASK);
604 memcpy(®s, &dev->irq_en_reg, sizeof(regs));
605
606 spin_unlock_bh(&dev->lock);
607
608 status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
609 ®s.int_status_en, sizeof(regs),
610 HIF_WR_SYNC_BYTE_INC);
611
612 if (status)
613 ath6kl_err("failed to update interrupt ctl reg err: %d\n",
614 status);
615
616 return status;
617}
618
619int ath6kl_hif_disable_intrs(struct ath6kl_device *dev)
620{
621 struct ath6kl_irq_enable_reg regs;
622
623 spin_lock_bh(&dev->lock);
624
625 dev->irq_en_reg.int_status_en = 0;
626 dev->irq_en_reg.cpu_int_status_en = 0;
627 dev->irq_en_reg.err_int_status_en = 0;
628 dev->irq_en_reg.cntr_int_status_en = 0;
629 memcpy(®s, &dev->irq_en_reg, sizeof(regs));
630 spin_unlock_bh(&dev->lock);
631
632 return hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS,
633 ®s.int_status_en, sizeof(regs),
634 HIF_WR_SYNC_BYTE_INC);
635}
636
637
638int ath6kl_hif_unmask_intrs(struct ath6kl_device *dev)
639{
640 int status = 0;
641
642
643
644
645
646
647
648
649
650 ath6kl_hif_disable_intrs(dev);
651
652
653 ath6kl_hif_irq_enable(dev->ar);
654 status = ath6kl_hif_enable_intrs(dev);
655
656 return status;
657}
658
659
660int ath6kl_hif_mask_intrs(struct ath6kl_device *dev)
661{
662
663
664
665
666
667 ath6kl_hif_irq_disable(dev->ar);
668
669 return ath6kl_hif_disable_intrs(dev);
670}
671
672int ath6kl_hif_setup(struct ath6kl_device *dev)
673{
674 int status = 0;
675
676 spin_lock_init(&dev->lock);
677
678
679
680
681
682
683 dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size;
684
685
686 if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) {
687 WARN_ON(1);
688 status = -EINVAL;
689 goto fail_setup;
690 }
691
692
693 dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1;
694
695 ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
696 dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
697
698 status = ath6kl_hif_disable_intrs(dev);
699
700fail_setup:
701 return status;
702}
703