aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath5k/dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath5k/dma.c')
-rw-r--r--drivers/net/wireless/ath5k/dma.c190
1 files changed, 145 insertions, 45 deletions
diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c
index 7adceb2c7fab..7e2b1a67e5da 100644
--- a/drivers/net/wireless/ath5k/dma.c
+++ b/drivers/net/wireless/ath5k/dma.c
@@ -472,9 +472,6 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
472 * 472 *
473 * NOTE: We use read-and-clear register, so after this function is called ISR 473 * NOTE: We use read-and-clear register, so after this function is called ISR
474 * is zeroed. 474 * is zeroed.
475 *
476 * XXX: Why filter interrupts in sw with interrupt_mask ? No benefit at all
477 * plus it can be misleading (one might thing that we save interrupts this way)
478 */ 475 */
479int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) 476int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
480{ 477{
@@ -494,11 +491,16 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
494 } 491 }
495 } else { 492 } else {
496 /* 493 /*
497 * Read interrupt status from the Read-And-Clear 494 * Read interrupt status from Interrupt
498 * shadow register. 495 * Status Register shadow copy (Read And Clear)
496 *
499 * Note: PISR/SISR Not available on 5210 497 * Note: PISR/SISR Not available on 5210
500 */ 498 */
501 data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); 499 data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
500 if (unlikely(data == AR5K_INT_NOCARD)) {
501 *interrupt_mask = data;
502 return -ENODEV;
503 }
502 } 504 }
503 505
504 /* 506 /*
@@ -506,17 +508,9 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
506 */ 508 */
507 *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; 509 *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
508 510
509 if (unlikely(data == AR5K_INT_NOCARD))
510 return -ENODEV;
511
512 if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
513 *interrupt_mask |= AR5K_INT_RX;
514
515 if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR
516 | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL))
517 *interrupt_mask |= AR5K_INT_TX;
518
519 if (ah->ah_version != AR5K_AR5210) { 511 if (ah->ah_version != AR5K_AR5210) {
512 u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2);
513
520 /*HIU = Host Interface Unit (PCI etc)*/ 514 /*HIU = Host Interface Unit (PCI etc)*/
521 if (unlikely(data & (AR5K_ISR_HIUERR))) 515 if (unlikely(data & (AR5K_ISR_HIUERR)))
522 *interrupt_mask |= AR5K_INT_FATAL; 516 *interrupt_mask |= AR5K_INT_FATAL;
@@ -524,24 +518,93 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
524 /*Beacon Not Ready*/ 518 /*Beacon Not Ready*/
525 if (unlikely(data & (AR5K_ISR_BNR))) 519 if (unlikely(data & (AR5K_ISR_BNR)))
526 *interrupt_mask |= AR5K_INT_BNR; 520 *interrupt_mask |= AR5K_INT_BNR;
527 }
528 521
529 /* 522 if (unlikely(sisr2 & (AR5K_SISR2_SSERR |
530 * XXX: BMISS interrupts may occur after association. 523 AR5K_SISR2_DPERR |
531 * I found this on 5210 code but it needs testing. If this is 524 AR5K_SISR2_MCABT)))
532 * true we should disable them before assoc and re-enable them 525 *interrupt_mask |= AR5K_INT_FATAL;
533 * after a successfull assoc + some jiffies. 526
534 */ 527 if (data & AR5K_ISR_TIM)
535#if 0 528 *interrupt_mask |= AR5K_INT_TIM;
536 interrupt_mask &= ~AR5K_INT_BMISS; 529
537#endif 530 if (data & AR5K_ISR_BCNMISC) {
531 if (sisr2 & AR5K_SISR2_TIM)
532 *interrupt_mask |= AR5K_INT_TIM;
533 if (sisr2 & AR5K_SISR2_DTIM)
534 *interrupt_mask |= AR5K_INT_DTIM;
535 if (sisr2 & AR5K_SISR2_DTIM_SYNC)
536 *interrupt_mask |= AR5K_INT_DTIM_SYNC;
537 if (sisr2 & AR5K_SISR2_BCN_TIMEOUT)
538 *interrupt_mask |= AR5K_INT_BCN_TIMEOUT;
539 if (sisr2 & AR5K_SISR2_CAB_TIMEOUT)
540 *interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
541 }
542
543 if (data & AR5K_ISR_RXDOPPLER)
544 *interrupt_mask |= AR5K_INT_RX_DOPPLER;
545 if (data & AR5K_ISR_QCBRORN) {
546 *interrupt_mask |= AR5K_INT_QCBRORN;
547 ah->ah_txq_isr |= AR5K_REG_MS(
548 ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
549 AR5K_SISR3_QCBRORN);
550 }
551 if (data & AR5K_ISR_QCBRURN) {
552 *interrupt_mask |= AR5K_INT_QCBRURN;
553 ah->ah_txq_isr |= AR5K_REG_MS(
554 ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
555 AR5K_SISR3_QCBRURN);
556 }
557 if (data & AR5K_ISR_QTRIG) {
558 *interrupt_mask |= AR5K_INT_QTRIG;
559 ah->ah_txq_isr |= AR5K_REG_MS(
560 ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
561 AR5K_SISR4_QTRIG);
562 }
563
564 if (data & AR5K_ISR_TXOK)
565 ah->ah_txq_isr |= AR5K_REG_MS(
566 ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
567 AR5K_SISR0_QCU_TXOK);
568
569 if (data & AR5K_ISR_TXDESC)
570 ah->ah_txq_isr |= AR5K_REG_MS(
571 ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
572 AR5K_SISR0_QCU_TXDESC);
573
574 if (data & AR5K_ISR_TXERR)
575 ah->ah_txq_isr |= AR5K_REG_MS(
576 ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
577 AR5K_SISR1_QCU_TXERR);
578
579 if (data & AR5K_ISR_TXEOL)
580 ah->ah_txq_isr |= AR5K_REG_MS(
581 ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
582 AR5K_SISR1_QCU_TXEOL);
583
584 if (data & AR5K_ISR_TXURN)
585 ah->ah_txq_isr |= AR5K_REG_MS(
586 ath5k_hw_reg_read(ah, AR5K_RAC_SISR2),
587 AR5K_SISR2_QCU_TXURN);
588 } else {
589 if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT
590 | AR5K_ISR_HIUERR | AR5K_ISR_DPERR)))
591 *interrupt_mask |= AR5K_INT_FATAL;
592
593 /*
594 * XXX: BMISS interrupts may occur after association.
595 * I found this on 5210 code but it needs testing. If this is
596 * true we should disable them before assoc and re-enable them
597 * after a successfull assoc + some jiffies.
598 interrupt_mask &= ~AR5K_INT_BMISS;
599 */
600 }
538 601
539 /* 602 /*
540 * In case we didn't handle anything, 603 * In case we didn't handle anything,
541 * print the register value. 604 * print the register value.
542 */ 605 */
543 if (unlikely(*interrupt_mask == 0 && net_ratelimit())) 606 if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
544 ATH5K_PRINTF("0x%08x\n", data); 607 ATH5K_PRINTF("ISR: 0x%08x IMR: 0x%08x\n", data, ah->ah_imr);
545 608
546 return 0; 609 return 0;
547} 610}
@@ -560,14 +623,17 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
560{ 623{
561 enum ath5k_int old_mask, int_mask; 624 enum ath5k_int old_mask, int_mask;
562 625
626 old_mask = ah->ah_imr;
627
563 /* 628 /*
564 * Disable card interrupts to prevent any race conditions 629 * Disable card interrupts to prevent any race conditions
565 * (they will be re-enabled afterwards). 630 * (they will be re-enabled afterwards if AR5K_INT GLOBAL
631 * is set again on the new mask).
566 */ 632 */
567 ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); 633 if (old_mask & AR5K_INT_GLOBAL) {
568 ath5k_hw_reg_read(ah, AR5K_IER); 634 ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
569 635 ath5k_hw_reg_read(ah, AR5K_IER);
570 old_mask = ah->ah_imr; 636 }
571 637
572 /* 638 /*
573 * Add additional, chipset-dependent interrupt mask flags 639 * Add additional, chipset-dependent interrupt mask flags
@@ -575,30 +641,64 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
575 */ 641 */
576 int_mask = new_mask & AR5K_INT_COMMON; 642 int_mask = new_mask & AR5K_INT_COMMON;
577 643
578 if (new_mask & AR5K_INT_RX)
579 int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN |
580 AR5K_IMR_RXDESC;
581
582 if (new_mask & AR5K_INT_TX)
583 int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC |
584 AR5K_IMR_TXURN;
585
586 if (ah->ah_version != AR5K_AR5210) { 644 if (ah->ah_version != AR5K_AR5210) {
645 /* Preserve per queue TXURN interrupt mask */
646 u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
647 & AR5K_SIMR2_QCU_TXURN;
648
587 if (new_mask & AR5K_INT_FATAL) { 649 if (new_mask & AR5K_INT_FATAL) {
588 int_mask |= AR5K_IMR_HIUERR; 650 int_mask |= AR5K_IMR_HIUERR;
589 AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT | 651 simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
590 AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); 652 | AR5K_SIMR2_DPERR);
591 } 653 }
654
655 /*Beacon Not Ready*/
656 if (new_mask & AR5K_INT_BNR)
657 int_mask |= AR5K_INT_BNR;
658
659 if (new_mask & AR5K_INT_TIM)
660 int_mask |= AR5K_IMR_TIM;
661
662 if (new_mask & AR5K_INT_TIM)
663 simr2 |= AR5K_SISR2_TIM;
664 if (new_mask & AR5K_INT_DTIM)
665 simr2 |= AR5K_SISR2_DTIM;
666 if (new_mask & AR5K_INT_DTIM_SYNC)
667 simr2 |= AR5K_SISR2_DTIM_SYNC;
668 if (new_mask & AR5K_INT_BCN_TIMEOUT)
669 simr2 |= AR5K_SISR2_BCN_TIMEOUT;
670 if (new_mask & AR5K_INT_CAB_TIMEOUT)
671 simr2 |= AR5K_SISR2_CAB_TIMEOUT;
672
673 if (new_mask & AR5K_INT_RX_DOPPLER)
674 int_mask |= AR5K_IMR_RXDOPPLER;
675
676 /* Note: Per queue interrupt masks
677 * are set via reset_tx_queue (qcu.c) */
678 ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
679 ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
680
681 } else {
682 if (new_mask & AR5K_INT_FATAL)
683 int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
684 | AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
685
686 ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
592 } 687 }
593 688
594 ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); 689 /* If RXNOFRM interrupt is masked disable it
690 * by setting AR5K_RXNOFRM to zero */
691 if (!(new_mask & AR5K_INT_RXNOFRM))
692 ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM);
595 693
596 /* Store new interrupt mask */ 694 /* Store new interrupt mask */
597 ah->ah_imr = new_mask; 695 ah->ah_imr = new_mask;
598 696
599 /* ..re-enable interrupts */ 697 /* ..re-enable interrupts if AR5K_INT_GLOBAL is set */
600 ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); 698 if (new_mask & AR5K_INT_GLOBAL) {
601 ath5k_hw_reg_read(ah, AR5K_IER); 699 ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
700 ath5k_hw_reg_read(ah, AR5K_IER);
701 }
602 702
603 return old_mask; 703 return old_mask;
604} 704}