diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 129 |
1 files changed, 102 insertions, 27 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 7ac3a720e52c..93005f1d326d 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -59,8 +59,8 @@ | |||
59 | #include "base.h" | 59 | #include "base.h" |
60 | #include "reg.h" | 60 | #include "reg.h" |
61 | #include "debug.h" | 61 | #include "debug.h" |
62 | #include "ani.h" | ||
62 | 63 | ||
63 | static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ | ||
64 | static int modparam_nohwcrypt; | 64 | static int modparam_nohwcrypt; |
65 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); | 65 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); |
66 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 66 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); |
@@ -365,6 +365,7 @@ static void ath5k_beacon_send(struct ath5k_softc *sc); | |||
365 | static void ath5k_beacon_config(struct ath5k_softc *sc); | 365 | static void ath5k_beacon_config(struct ath5k_softc *sc); |
366 | static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); | 366 | static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); |
367 | static void ath5k_tasklet_beacon(unsigned long data); | 367 | static void ath5k_tasklet_beacon(unsigned long data); |
368 | static void ath5k_tasklet_ani(unsigned long data); | ||
368 | 369 | ||
369 | static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) | 370 | static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) |
370 | { | 371 | { |
@@ -830,6 +831,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
830 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); | 831 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); |
831 | tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); | 832 | tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc); |
832 | tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); | 833 | tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); |
834 | tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc); | ||
833 | 835 | ||
834 | ret = ath5k_eeprom_read_mac(ah, mac); | 836 | ret = ath5k_eeprom_read_mac(ah, mac); |
835 | if (ret) { | 837 | if (ret) { |
@@ -1635,7 +1637,6 @@ ath5k_txq_cleanup(struct ath5k_softc *sc) | |||
1635 | sc->txqs[i].link); | 1637 | sc->txqs[i].link); |
1636 | } | 1638 | } |
1637 | } | 1639 | } |
1638 | ieee80211_wake_queues(sc->hw); /* XXX move to callers */ | ||
1639 | 1640 | ||
1640 | for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) | 1641 | for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) |
1641 | if (sc->txqs[i].setup) | 1642 | if (sc->txqs[i].setup) |
@@ -1805,6 +1806,25 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, | |||
1805 | } | 1806 | } |
1806 | } | 1807 | } |
1807 | 1808 | ||
1809 | static void | ||
1810 | ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) | ||
1811 | { | ||
1812 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; | ||
1813 | struct ath5k_hw *ah = sc->ah; | ||
1814 | struct ath_common *common = ath5k_hw_common(ah); | ||
1815 | |||
1816 | /* only beacons from our BSSID */ | ||
1817 | if (!ieee80211_is_beacon(mgmt->frame_control) || | ||
1818 | memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) | ||
1819 | return; | ||
1820 | |||
1821 | ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg, | ||
1822 | rssi); | ||
1823 | |||
1824 | /* in IBSS mode we should keep RSSI statistics per neighbour */ | ||
1825 | /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ | ||
1826 | } | ||
1827 | |||
1808 | /* | 1828 | /* |
1809 | * Compute padding position. skb must contains an IEEE 802.11 frame | 1829 | * Compute padding position. skb must contains an IEEE 802.11 frame |
1810 | */ | 1830 | */ |
@@ -1923,6 +1943,8 @@ ath5k_tasklet_rx(unsigned long data) | |||
1923 | sc->stats.rxerr_fifo++; | 1943 | sc->stats.rxerr_fifo++; |
1924 | if (rs.rs_status & AR5K_RXERR_PHY) { | 1944 | if (rs.rs_status & AR5K_RXERR_PHY) { |
1925 | sc->stats.rxerr_phy++; | 1945 | sc->stats.rxerr_phy++; |
1946 | if (rs.rs_phyerr > 0 && rs.rs_phyerr < 32) | ||
1947 | sc->stats.rxerr_phy_code[rs.rs_phyerr]++; | ||
1926 | goto next; | 1948 | goto next; |
1927 | } | 1949 | } |
1928 | if (rs.rs_status & AR5K_RXERR_DECRYPT) { | 1950 | if (rs.rs_status & AR5K_RXERR_DECRYPT) { |
@@ -2024,6 +2046,8 @@ accept: | |||
2024 | 2046 | ||
2025 | ath5k_debug_dump_skb(sc, skb, "RX ", 0); | 2047 | ath5k_debug_dump_skb(sc, skb, "RX ", 0); |
2026 | 2048 | ||
2049 | ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi); | ||
2050 | |||
2027 | /* check beacons in IBSS mode */ | 2051 | /* check beacons in IBSS mode */ |
2028 | if (sc->opmode == NL80211_IFTYPE_ADHOC) | 2052 | if (sc->opmode == NL80211_IFTYPE_ADHOC) |
2029 | ath5k_check_ibss_tsf(sc, skb, rxs); | 2053 | ath5k_check_ibss_tsf(sc, skb, rxs); |
@@ -2060,6 +2084,17 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
2060 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { | 2084 | list_for_each_entry_safe(bf, bf0, &txq->q, list) { |
2061 | ds = bf->desc; | 2085 | ds = bf->desc; |
2062 | 2086 | ||
2087 | /* | ||
2088 | * It's possible that the hardware can say the buffer is | ||
2089 | * completed when it hasn't yet loaded the ds_link from | ||
2090 | * host memory and moved on. If there are more TX | ||
2091 | * descriptors in the queue, wait for TXDP to change | ||
2092 | * before processing this one. | ||
2093 | */ | ||
2094 | if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr && | ||
2095 | !list_is_last(&bf->list, &txq->q)) | ||
2096 | break; | ||
2097 | |||
2063 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); | 2098 | ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts); |
2064 | if (unlikely(ret == -EINPROGRESS)) | 2099 | if (unlikely(ret == -EINPROGRESS)) |
2065 | break; | 2100 | break; |
@@ -2095,7 +2130,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) | |||
2095 | info->status.rates[ts.ts_final_idx].count++; | 2130 | info->status.rates[ts.ts_final_idx].count++; |
2096 | 2131 | ||
2097 | if (unlikely(ts.ts_status)) { | 2132 | if (unlikely(ts.ts_status)) { |
2098 | sc->ll_stats.dot11ACKFailureCount++; | 2133 | sc->stats.ack_fail++; |
2099 | if (ts.ts_status & AR5K_TXERR_FILT) { | 2134 | if (ts.ts_status & AR5K_TXERR_FILT) { |
2100 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | 2135 | info->flags |= IEEE80211_TX_STAT_TX_FILTERED; |
2101 | sc->stats.txerr_filt++; | 2136 | sc->stats.txerr_filt++; |
@@ -2498,9 +2533,6 @@ ath5k_init(struct ath5k_softc *sc) | |||
2498 | */ | 2533 | */ |
2499 | ath5k_stop_locked(sc); | 2534 | ath5k_stop_locked(sc); |
2500 | 2535 | ||
2501 | /* Set PHY calibration interval */ | ||
2502 | ah->ah_cal_intval = ath5k_calinterval; | ||
2503 | |||
2504 | /* | 2536 | /* |
2505 | * The basic interface to setting the hardware in a good | 2537 | * The basic interface to setting the hardware in a good |
2506 | * state is ``reset''. On return the hardware is known to | 2538 | * state is ``reset''. On return the hardware is known to |
@@ -2512,7 +2544,8 @@ ath5k_init(struct ath5k_softc *sc) | |||
2512 | sc->curband = &sc->sbands[sc->curchan->band]; | 2544 | sc->curband = &sc->sbands[sc->curchan->band]; |
2513 | sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | | 2545 | sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | |
2514 | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | | 2546 | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | |
2515 | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI; | 2547 | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; |
2548 | |||
2516 | ret = ath5k_reset(sc, NULL); | 2549 | ret = ath5k_reset(sc, NULL); |
2517 | if (ret) | 2550 | if (ret) |
2518 | goto done; | 2551 | goto done; |
@@ -2526,8 +2559,7 @@ ath5k_init(struct ath5k_softc *sc) | |||
2526 | for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) | 2559 | for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) |
2527 | ath5k_hw_reset_key(ah, i); | 2560 | ath5k_hw_reset_key(ah, i); |
2528 | 2561 | ||
2529 | /* Set ack to be sent at low bit-rates */ | 2562 | ath5k_hw_set_ack_bitrate_high(ah, true); |
2530 | ath5k_hw_set_ack_bitrate_high(ah, false); | ||
2531 | ret = 0; | 2563 | ret = 0; |
2532 | done: | 2564 | done: |
2533 | mmiowb(); | 2565 | mmiowb(); |
@@ -2624,12 +2656,33 @@ ath5k_stop_hw(struct ath5k_softc *sc) | |||
2624 | tasklet_kill(&sc->restq); | 2656 | tasklet_kill(&sc->restq); |
2625 | tasklet_kill(&sc->calib); | 2657 | tasklet_kill(&sc->calib); |
2626 | tasklet_kill(&sc->beacontq); | 2658 | tasklet_kill(&sc->beacontq); |
2659 | tasklet_kill(&sc->ani_tasklet); | ||
2627 | 2660 | ||
2628 | ath5k_rfkill_hw_stop(sc->ah); | 2661 | ath5k_rfkill_hw_stop(sc->ah); |
2629 | 2662 | ||
2630 | return ret; | 2663 | return ret; |
2631 | } | 2664 | } |
2632 | 2665 | ||
2666 | static void | ||
2667 | ath5k_intr_calibration_poll(struct ath5k_hw *ah) | ||
2668 | { | ||
2669 | if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && | ||
2670 | !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) { | ||
2671 | /* run ANI only when full calibration is not active */ | ||
2672 | ah->ah_cal_next_ani = jiffies + | ||
2673 | msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); | ||
2674 | tasklet_schedule(&ah->ah_sc->ani_tasklet); | ||
2675 | |||
2676 | } else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { | ||
2677 | ah->ah_cal_next_full = jiffies + | ||
2678 | msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); | ||
2679 | tasklet_schedule(&ah->ah_sc->calib); | ||
2680 | } | ||
2681 | /* we could use SWI to generate enough interrupts to meet our | ||
2682 | * calibration interval requirements, if necessary: | ||
2683 | * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ | ||
2684 | } | ||
2685 | |||
2633 | static irqreturn_t | 2686 | static irqreturn_t |
2634 | ath5k_intr(int irq, void *dev_id) | 2687 | ath5k_intr(int irq, void *dev_id) |
2635 | { | 2688 | { |
@@ -2653,7 +2706,20 @@ ath5k_intr(int irq, void *dev_id) | |||
2653 | */ | 2706 | */ |
2654 | tasklet_schedule(&sc->restq); | 2707 | tasklet_schedule(&sc->restq); |
2655 | } else if (unlikely(status & AR5K_INT_RXORN)) { | 2708 | } else if (unlikely(status & AR5K_INT_RXORN)) { |
2656 | tasklet_schedule(&sc->restq); | 2709 | /* |
2710 | * Receive buffers are full. Either the bus is busy or | ||
2711 | * the CPU is not fast enough to process all received | ||
2712 | * frames. | ||
2713 | * Older chipsets need a reset to come out of this | ||
2714 | * condition, but we treat it as RX for newer chips. | ||
2715 | * We don't know exactly which versions need a reset - | ||
2716 | * this guess is copied from the HAL. | ||
2717 | */ | ||
2718 | sc->stats.rxorn_intr++; | ||
2719 | if (ah->ah_mac_srev < AR5K_SREV_AR5212) | ||
2720 | tasklet_schedule(&sc->restq); | ||
2721 | else | ||
2722 | tasklet_schedule(&sc->rxtq); | ||
2657 | } else { | 2723 | } else { |
2658 | if (status & AR5K_INT_SWBA) { | 2724 | if (status & AR5K_INT_SWBA) { |
2659 | tasklet_hi_schedule(&sc->beacontq); | 2725 | tasklet_hi_schedule(&sc->beacontq); |
@@ -2678,15 +2744,10 @@ ath5k_intr(int irq, void *dev_id) | |||
2678 | if (status & AR5K_INT_BMISS) { | 2744 | if (status & AR5K_INT_BMISS) { |
2679 | /* TODO */ | 2745 | /* TODO */ |
2680 | } | 2746 | } |
2681 | if (status & AR5K_INT_SWI) { | ||
2682 | tasklet_schedule(&sc->calib); | ||
2683 | } | ||
2684 | if (status & AR5K_INT_MIB) { | 2747 | if (status & AR5K_INT_MIB) { |
2685 | /* | 2748 | sc->stats.mib_intr++; |
2686 | * These stats are also used for ANI i think | 2749 | ath5k_hw_update_mib_counters(ah); |
2687 | * so how about updating them more often ? | 2750 | ath5k_ani_mib_intr(ah); |
2688 | */ | ||
2689 | ath5k_hw_update_mib_counters(ah, &sc->ll_stats); | ||
2690 | } | 2751 | } |
2691 | if (status & AR5K_INT_GPIO) | 2752 | if (status & AR5K_INT_GPIO) |
2692 | tasklet_schedule(&sc->rf_kill.toggleq); | 2753 | tasklet_schedule(&sc->rf_kill.toggleq); |
@@ -2697,7 +2758,7 @@ ath5k_intr(int irq, void *dev_id) | |||
2697 | if (unlikely(!counter)) | 2758 | if (unlikely(!counter)) |
2698 | ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); | 2759 | ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); |
2699 | 2760 | ||
2700 | ath5k_hw_calibration_poll(ah); | 2761 | ath5k_intr_calibration_poll(ah); |
2701 | 2762 | ||
2702 | return IRQ_HANDLED; | 2763 | return IRQ_HANDLED; |
2703 | } | 2764 | } |
@@ -2721,8 +2782,7 @@ ath5k_tasklet_calibrate(unsigned long data) | |||
2721 | struct ath5k_hw *ah = sc->ah; | 2782 | struct ath5k_hw *ah = sc->ah; |
2722 | 2783 | ||
2723 | /* Only full calibration for now */ | 2784 | /* Only full calibration for now */ |
2724 | if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION) | 2785 | ah->ah_cal_mask |= AR5K_CALIBRATION_FULL; |
2725 | return; | ||
2726 | 2786 | ||
2727 | /* Stop queues so that calibration | 2787 | /* Stop queues so that calibration |
2728 | * doesn't interfere with tx */ | 2788 | * doesn't interfere with tx */ |
@@ -2738,18 +2798,29 @@ ath5k_tasklet_calibrate(unsigned long data) | |||
2738 | * to load new gain values. | 2798 | * to load new gain values. |
2739 | */ | 2799 | */ |
2740 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); | 2800 | ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); |
2741 | ath5k_reset_wake(sc); | 2801 | ath5k_reset(sc, sc->curchan); |
2742 | } | 2802 | } |
2743 | if (ath5k_hw_phy_calibrate(ah, sc->curchan)) | 2803 | if (ath5k_hw_phy_calibrate(ah, sc->curchan)) |
2744 | ATH5K_ERR(sc, "calibration of channel %u failed\n", | 2804 | ATH5K_ERR(sc, "calibration of channel %u failed\n", |
2745 | ieee80211_frequency_to_channel( | 2805 | ieee80211_frequency_to_channel( |
2746 | sc->curchan->center_freq)); | 2806 | sc->curchan->center_freq)); |
2747 | 2807 | ||
2748 | ah->ah_swi_mask = 0; | ||
2749 | |||
2750 | /* Wake queues */ | 2808 | /* Wake queues */ |
2751 | ieee80211_wake_queues(sc->hw); | 2809 | ieee80211_wake_queues(sc->hw); |
2752 | 2810 | ||
2811 | ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; | ||
2812 | } | ||
2813 | |||
2814 | |||
2815 | static void | ||
2816 | ath5k_tasklet_ani(unsigned long data) | ||
2817 | { | ||
2818 | struct ath5k_softc *sc = (void *)data; | ||
2819 | struct ath5k_hw *ah = sc->ah; | ||
2820 | |||
2821 | ah->ah_cal_mask |= AR5K_CALIBRATION_ANI; | ||
2822 | ath5k_ani_calibration(ah); | ||
2823 | ah->ah_cal_mask &= ~AR5K_CALIBRATION_ANI; | ||
2753 | } | 2824 | } |
2754 | 2825 | ||
2755 | 2826 | ||
@@ -2852,6 +2923,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan) | |||
2852 | goto err; | 2923 | goto err; |
2853 | } | 2924 | } |
2854 | 2925 | ||
2926 | ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode); | ||
2927 | |||
2855 | /* | 2928 | /* |
2856 | * Change channels and update the h/w rate map if we're switching; | 2929 | * Change channels and update the h/w rate map if we're switching; |
2857 | * e.g. 11a to 11b/g. | 2930 | * e.g. 11a to 11b/g. |
@@ -3207,12 +3280,14 @@ ath5k_get_stats(struct ieee80211_hw *hw, | |||
3207 | struct ieee80211_low_level_stats *stats) | 3280 | struct ieee80211_low_level_stats *stats) |
3208 | { | 3281 | { |
3209 | struct ath5k_softc *sc = hw->priv; | 3282 | struct ath5k_softc *sc = hw->priv; |
3210 | struct ath5k_hw *ah = sc->ah; | ||
3211 | 3283 | ||
3212 | /* Force update */ | 3284 | /* Force update */ |
3213 | ath5k_hw_update_mib_counters(ah, &sc->ll_stats); | 3285 | ath5k_hw_update_mib_counters(sc->ah); |
3214 | 3286 | ||
3215 | memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats)); | 3287 | stats->dot11ACKFailureCount = sc->stats.ack_fail; |
3288 | stats->dot11RTSFailureCount = sc->stats.rts_fail; | ||
3289 | stats->dot11RTSSuccessCount = sc->stats.rts_ok; | ||
3290 | stats->dot11FCSErrorCount = sc->stats.fcs_error; | ||
3216 | 3291 | ||
3217 | return 0; | 3292 | return 0; |
3218 | } | 3293 | } |