diff options
author | Nick Kossifidis <mick@madwifi.org> | 2008-10-26 14:40:25 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-10-31 19:02:32 -0400 |
commit | 4c674c60bd567597f1224973712b352f4f474890 (patch) | |
tree | 0838978d789d120c3109a1b14a948a7ad4ff9cd8 /drivers | |
parent | 84fa4f43c418d2eaad06734ea780a74c869f79c3 (diff) |
ath5k: Update interrupt masking code
*Properly get/set all available ISR/IMR values and review common/uncommon bits
*Better handling of per-txq interrupts (we can now resolve what q is generating
each interrupt -this will help in debuging wme later)
*Some minor updates from legacy-hal
*Properly handle RXNOFRM and TXNOFRM interrupt masking (even when we don't set
them on IMR they keep showing up, so we disable them by zeroing AR5K_RXNOFRM
and AR5K_TXNOFRM registers). This doesn't exist on legacy-hal but i've tested
it on various cards and it works fine.
Changes-Licensed-under: ISC
Signed-Off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath5k/ath5k.h | 86 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/dma.c | 190 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/qcu.c | 37 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/reg.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/reset.c | 3 |
6 files changed, 247 insertions, 79 deletions
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 53ea439aff48..b11792039911 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h | |||
@@ -507,11 +507,15 @@ enum ath5k_tx_queue_id { | |||
507 | #define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */ | 507 | #define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */ |
508 | #define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */ | 508 | #define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */ |
509 | #define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */ | 509 | #define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */ |
510 | #define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0020 /* Disable random post-backoff */ | 510 | #define AR5K_TXQ_FLAG_CBRORNINT_ENABLE 0x0020 /* Enable CBRORN interrupt */ |
511 | #define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0040 /* Enable ready time expiry policy (?)*/ | 511 | #define AR5K_TXQ_FLAG_CBRURNINT_ENABLE 0x0040 /* Enable CBRURN interrupt */ |
512 | #define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0080 /* Enable backoff while bursting */ | 512 | #define AR5K_TXQ_FLAG_QTRIGINT_ENABLE 0x0080 /* Enable QTRIG interrupt */ |
513 | #define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x0100 /* Disable backoff while bursting */ | 513 | #define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE 0x0100 /* Enable TXNOFRM interrupt */ |
514 | #define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x0200 /* Enable hw compression -not implemented-*/ | 514 | #define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0200 /* Disable random post-backoff */ |
515 | #define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0300 /* Enable ready time expiry policy (?)*/ | ||
516 | #define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0800 /* Enable backoff while bursting */ | ||
517 | #define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */ | ||
518 | #define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/ | ||
515 | 519 | ||
516 | /* | 520 | /* |
517 | * A struct to hold tx queue's parameters | 521 | * A struct to hold tx queue's parameters |
@@ -853,7 +857,7 @@ enum ath5k_ant_setting { | |||
853 | * checked. We should do this with ath5k_hw_update_mib_counters() but | 857 | * checked. We should do this with ath5k_hw_update_mib_counters() but |
854 | * it seems we should also then do some noise immunity work. | 858 | * it seems we should also then do some noise immunity work. |
855 | * @AR5K_INT_RXPHY: RX PHY Error | 859 | * @AR5K_INT_RXPHY: RX PHY Error |
856 | * @AR5K_INT_RXKCM: ?? | 860 | * @AR5K_INT_RXKCM: RX Key cache miss |
857 | * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a | 861 | * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a |
858 | * beacon that must be handled in software. The alternative is if you | 862 | * beacon that must be handled in software. The alternative is if you |
859 | * have VEOL support, in that case you let the hardware deal with things. | 863 | * have VEOL support, in that case you let the hardware deal with things. |
@@ -869,7 +873,7 @@ enum ath5k_ant_setting { | |||
869 | * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA | 873 | * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA |
870 | * errors. These types of errors we can enable seem to be of type | 874 | * errors. These types of errors we can enable seem to be of type |
871 | * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. | 875 | * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. |
872 | * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER | 876 | * @AR5K_INT_GLOBAL: Used to clear and set the IER |
873 | * @AR5K_INT_NOCARD: signals the card has been removed | 877 | * @AR5K_INT_NOCARD: signals the card has been removed |
874 | * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same | 878 | * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same |
875 | * bit value | 879 | * bit value |
@@ -881,36 +885,61 @@ enum ath5k_ant_setting { | |||
881 | * MACs. | 885 | * MACs. |
882 | */ | 886 | */ |
883 | enum ath5k_int { | 887 | enum ath5k_int { |
884 | AR5K_INT_RX = 0x00000001, /* Not common */ | 888 | AR5K_INT_RXOK = 0x00000001, |
885 | AR5K_INT_RXDESC = 0x00000002, | 889 | AR5K_INT_RXDESC = 0x00000002, |
890 | AR5K_INT_RXERR = 0x00000004, | ||
886 | AR5K_INT_RXNOFRM = 0x00000008, | 891 | AR5K_INT_RXNOFRM = 0x00000008, |
887 | AR5K_INT_RXEOL = 0x00000010, | 892 | AR5K_INT_RXEOL = 0x00000010, |
888 | AR5K_INT_RXORN = 0x00000020, | 893 | AR5K_INT_RXORN = 0x00000020, |
889 | AR5K_INT_TX = 0x00000040, /* Not common */ | 894 | AR5K_INT_TXOK = 0x00000040, |
890 | AR5K_INT_TXDESC = 0x00000080, | 895 | AR5K_INT_TXDESC = 0x00000080, |
896 | AR5K_INT_TXERR = 0x00000100, | ||
897 | AR5K_INT_TXNOFRM = 0x00000200, | ||
898 | AR5K_INT_TXEOL = 0x00000400, | ||
891 | AR5K_INT_TXURN = 0x00000800, | 899 | AR5K_INT_TXURN = 0x00000800, |
892 | AR5K_INT_MIB = 0x00001000, | 900 | AR5K_INT_MIB = 0x00001000, |
901 | AR5K_INT_SWI = 0x00002000, | ||
893 | AR5K_INT_RXPHY = 0x00004000, | 902 | AR5K_INT_RXPHY = 0x00004000, |
894 | AR5K_INT_RXKCM = 0x00008000, | 903 | AR5K_INT_RXKCM = 0x00008000, |
895 | AR5K_INT_SWBA = 0x00010000, | 904 | AR5K_INT_SWBA = 0x00010000, |
905 | AR5K_INT_BRSSI = 0x00020000, | ||
896 | AR5K_INT_BMISS = 0x00040000, | 906 | AR5K_INT_BMISS = 0x00040000, |
897 | AR5K_INT_BNR = 0x00100000, /* Not common */ | 907 | AR5K_INT_FATAL = 0x00080000, /* Non common */ |
898 | AR5K_INT_GPIO = 0x01000000, | 908 | AR5K_INT_BNR = 0x00100000, /* Non common */ |
899 | AR5K_INT_FATAL = 0x40000000, /* Not common */ | 909 | AR5K_INT_TIM = 0x00200000, /* Non common */ |
900 | AR5K_INT_GLOBAL = 0x80000000, | 910 | AR5K_INT_DTIM = 0x00400000, /* Non common */ |
901 | 911 | AR5K_INT_DTIM_SYNC = 0x00800000, /* Non common */ | |
902 | AR5K_INT_COMMON = AR5K_INT_RXNOFRM | 912 | AR5K_INT_GPIO = 0x01000000, |
903 | | AR5K_INT_RXDESC | 913 | AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */ |
904 | | AR5K_INT_RXEOL | 914 | AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */ |
905 | | AR5K_INT_RXORN | 915 | AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */ |
906 | | AR5K_INT_TXURN | 916 | AR5K_INT_QCBRORN = 0x10000000, /* Non common */ |
907 | | AR5K_INT_TXDESC | 917 | AR5K_INT_QCBRURN = 0x20000000, /* Non common */ |
908 | | AR5K_INT_MIB | 918 | AR5K_INT_QTRIG = 0x40000000, /* Non common */ |
909 | | AR5K_INT_RXPHY | 919 | AR5K_INT_GLOBAL = 0x80000000, |
910 | | AR5K_INT_RXKCM | 920 | |
911 | | AR5K_INT_SWBA | 921 | AR5K_INT_COMMON = AR5K_INT_RXOK |
912 | | AR5K_INT_BMISS | 922 | | AR5K_INT_RXDESC |
913 | | AR5K_INT_GPIO, | 923 | | AR5K_INT_RXERR |
924 | | AR5K_INT_RXNOFRM | ||
925 | | AR5K_INT_RXEOL | ||
926 | | AR5K_INT_RXORN | ||
927 | | AR5K_INT_TXOK | ||
928 | | AR5K_INT_TXDESC | ||
929 | | AR5K_INT_TXERR | ||
930 | | AR5K_INT_TXNOFRM | ||
931 | | AR5K_INT_TXEOL | ||
932 | | AR5K_INT_TXURN | ||
933 | | AR5K_INT_MIB | ||
934 | | AR5K_INT_SWI | ||
935 | | AR5K_INT_RXPHY | ||
936 | | AR5K_INT_RXKCM | ||
937 | | AR5K_INT_SWBA | ||
938 | | AR5K_INT_BRSSI | ||
939 | | AR5K_INT_BMISS | ||
940 | | AR5K_INT_GPIO | ||
941 | | AR5K_INT_GLOBAL, | ||
942 | |||
914 | AR5K_INT_NOCARD = 0xffffffff | 943 | AR5K_INT_NOCARD = 0xffffffff |
915 | }; | 944 | }; |
916 | 945 | ||
@@ -1081,6 +1110,11 @@ struct ath5k_hw { | |||
1081 | u32 ah_txq_imr_txurn; | 1110 | u32 ah_txq_imr_txurn; |
1082 | u32 ah_txq_imr_txdesc; | 1111 | u32 ah_txq_imr_txdesc; |
1083 | u32 ah_txq_imr_txeol; | 1112 | u32 ah_txq_imr_txeol; |
1113 | u32 ah_txq_imr_cbrorn; | ||
1114 | u32 ah_txq_imr_cbrurn; | ||
1115 | u32 ah_txq_imr_qtrig; | ||
1116 | u32 ah_txq_imr_nofrm; | ||
1117 | u32 ah_txq_isr; | ||
1084 | u32 *ah_rf_banks; | 1118 | u32 *ah_rf_banks; |
1085 | size_t ah_rf_banks_size; | 1119 | size_t ah_rf_banks_size; |
1086 | struct ath5k_gain ah_gain; | 1120 | struct ath5k_gain ah_gain; |
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 6caabebc4c66..7ac5f2847da5 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -2216,7 +2216,7 @@ ath5k_init(struct ath5k_softc *sc, bool is_resume) | |||
2216 | */ | 2216 | */ |
2217 | sc->curchan = sc->hw->conf.channel; | 2217 | sc->curchan = sc->hw->conf.channel; |
2218 | sc->curband = &sc->sbands[sc->curchan->band]; | 2218 | sc->curband = &sc->sbands[sc->curchan->band]; |
2219 | sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL | | 2219 | sc->imask = AR5K_INT_RXOK | AR5K_INT_TXOK | AR5K_INT_RXEOL | |
2220 | AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL | | 2220 | AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL | |
2221 | AR5K_INT_MIB; | 2221 | AR5K_INT_MIB; |
2222 | ret = ath5k_reset(sc, false, false); | 2222 | ret = ath5k_reset(sc, false, false); |
@@ -2410,9 +2410,10 @@ ath5k_intr(int irq, void *dev_id) | |||
2410 | /* bump tx trigger level */ | 2410 | /* bump tx trigger level */ |
2411 | ath5k_hw_update_tx_triglevel(ah, true); | 2411 | ath5k_hw_update_tx_triglevel(ah, true); |
2412 | } | 2412 | } |
2413 | if (status & AR5K_INT_RX) | 2413 | if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) |
2414 | tasklet_schedule(&sc->rxtq); | 2414 | tasklet_schedule(&sc->rxtq); |
2415 | if (status & AR5K_INT_TX) | 2415 | if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC |
2416 | | AR5K_INT_TXERR | AR5K_INT_TXEOL)) | ||
2416 | tasklet_schedule(&sc->txtq); | 2417 | tasklet_schedule(&sc->txtq); |
2417 | if (status & AR5K_INT_BMISS) { | 2418 | if (status & AR5K_INT_BMISS) { |
2418 | } | 2419 | } |
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 | */ |
479 | int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) | 476 | int 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 | } |
diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c index 01bf09176d23..1b7bc50ea8eb 100644 --- a/drivers/net/wireless/ath5k/qcu.c +++ b/drivers/net/wireless/ath5k/qcu.c | |||
@@ -432,13 +432,30 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) | |||
432 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) | 432 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) |
433 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); | 433 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); |
434 | 434 | ||
435 | if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE) | ||
436 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue); | ||
437 | |||
438 | if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE) | ||
439 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue); | ||
440 | |||
441 | if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE) | ||
442 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue); | ||
443 | |||
444 | if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE) | ||
445 | AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue); | ||
435 | 446 | ||
436 | /* Update secondary interrupt mask registers */ | 447 | /* Update secondary interrupt mask registers */ |
448 | |||
449 | /* Filter out inactive queues */ | ||
437 | ah->ah_txq_imr_txok &= ah->ah_txq_status; | 450 | ah->ah_txq_imr_txok &= ah->ah_txq_status; |
438 | ah->ah_txq_imr_txerr &= ah->ah_txq_status; | 451 | ah->ah_txq_imr_txerr &= ah->ah_txq_status; |
439 | ah->ah_txq_imr_txurn &= ah->ah_txq_status; | 452 | ah->ah_txq_imr_txurn &= ah->ah_txq_status; |
440 | ah->ah_txq_imr_txdesc &= ah->ah_txq_status; | 453 | ah->ah_txq_imr_txdesc &= ah->ah_txq_status; |
441 | ah->ah_txq_imr_txeol &= ah->ah_txq_status; | 454 | ah->ah_txq_imr_txeol &= ah->ah_txq_status; |
455 | ah->ah_txq_imr_cbrorn &= ah->ah_txq_status; | ||
456 | ah->ah_txq_imr_cbrurn &= ah->ah_txq_status; | ||
457 | ah->ah_txq_imr_qtrig &= ah->ah_txq_status; | ||
458 | ah->ah_txq_imr_nofrm &= ah->ah_txq_status; | ||
442 | 459 | ||
443 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, | 460 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, |
444 | AR5K_SIMR0_QCU_TXOK) | | 461 | AR5K_SIMR0_QCU_TXOK) | |
@@ -448,8 +465,24 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) | |||
448 | AR5K_SIMR1_QCU_TXERR) | | 465 | AR5K_SIMR1_QCU_TXERR) | |
449 | AR5K_REG_SM(ah->ah_txq_imr_txeol, | 466 | AR5K_REG_SM(ah->ah_txq_imr_txeol, |
450 | AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); | 467 | AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); |
451 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn, | 468 | /* Update simr2 but don't overwrite rest simr2 settings */ |
452 | AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2); | 469 | AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN); |
470 | AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, | ||
471 | AR5K_REG_SM(ah->ah_txq_imr_txurn, | ||
472 | AR5K_SIMR2_QCU_TXURN)); | ||
473 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn, | ||
474 | AR5K_SIMR3_QCBRORN) | | ||
475 | AR5K_REG_SM(ah->ah_txq_imr_cbrurn, | ||
476 | AR5K_SIMR3_QCBRURN), AR5K_SIMR3); | ||
477 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig, | ||
478 | AR5K_SIMR4_QTRIG), AR5K_SIMR4); | ||
479 | /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */ | ||
480 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm, | ||
481 | AR5K_TXNOFRM_QCU), AR5K_TXNOFRM); | ||
482 | /* No queue has TXNOFRM enabled, disable the interrupt | ||
483 | * by setting AR5K_TXNOFRM to zero */ | ||
484 | if (ah->ah_txq_imr_nofrm == 0) | ||
485 | ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM); | ||
453 | } | 486 | } |
454 | 487 | ||
455 | return 0; | 488 | return 0; |
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index e557fe178bbf..0dae54d00f03 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h | |||
@@ -234,6 +234,7 @@ | |||
234 | #define AR5K_TXNOFRM 0x004c | 234 | #define AR5K_TXNOFRM 0x004c |
235 | #define AR5K_TXNOFRM_M 0x000003ff | 235 | #define AR5K_TXNOFRM_M 0x000003ff |
236 | #define AR5K_TXNOFRM_QCU 0x000ffc00 | 236 | #define AR5K_TXNOFRM_QCU 0x000ffc00 |
237 | #define AR5K_TXNOFRM_QCU_S 10 | ||
237 | 238 | ||
238 | /* | 239 | /* |
239 | * Receive frame gap timeout register | 240 | * Receive frame gap timeout register |
@@ -350,7 +351,7 @@ | |||
350 | 351 | ||
351 | #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ | 352 | #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ |
352 | #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ | 353 | #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ |
353 | #define AR5K_SISR3_QCBORN_S 0 | 354 | #define AR5K_SISR3_QCBRORN_S 0 |
354 | #define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ | 355 | #define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ |
355 | #define AR5K_SISR3_QCBRURN_S 16 | 356 | #define AR5K_SISR3_QCBRURN_S 16 |
356 | 357 | ||
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 1b6d45b6772d..b51bc030da02 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c | |||
@@ -864,8 +864,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | |||
864 | 864 | ||
865 | /* Pre-enable interrupts on 5211/5212*/ | 865 | /* Pre-enable interrupts on 5211/5212*/ |
866 | if (ah->ah_version != AR5K_AR5210) | 866 | if (ah->ah_version != AR5K_AR5210) |
867 | ath5k_hw_set_imr(ah, AR5K_INT_RX | AR5K_INT_TX | | 867 | ath5k_hw_set_imr(ah, ah->ah_imr); |
868 | AR5K_INT_FATAL); | ||
869 | 868 | ||
870 | /* | 869 | /* |
871 | * Set RF kill flags if supported by the device (read from the EEPROM) | 870 | * Set RF kill flags if supported by the device (read from the EEPROM) |