diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-04-25 14:34:25 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-04-25 14:34:25 -0400 |
commit | cfef6047c4027a8448ec8dafeaf2bb362cc882e4 (patch) | |
tree | c254bd25aa8b4b0696b5b5cc45d8e30c7c1bb9dd /drivers/net/wireless/ath/ath5k/base.c | |
parent | b71d1d426d263b0b6cb5760322efebbfc89d4463 (diff) | |
parent | 73b48099cc265f88fa1255f3f43e52fe6a94fd5c (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 71 |
1 files changed, 56 insertions, 15 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 349a5963931b..203243bacc89 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -1444,6 +1444,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs) | |||
1444 | } | 1444 | } |
1445 | 1445 | ||
1446 | static void | 1446 | static void |
1447 | ath5k_set_current_imask(struct ath5k_softc *sc) | ||
1448 | { | ||
1449 | enum ath5k_int imask = sc->imask; | ||
1450 | unsigned long flags; | ||
1451 | |||
1452 | spin_lock_irqsave(&sc->irqlock, flags); | ||
1453 | if (sc->rx_pending) | ||
1454 | imask &= ~AR5K_INT_RX_ALL; | ||
1455 | if (sc->tx_pending) | ||
1456 | imask &= ~AR5K_INT_TX_ALL; | ||
1457 | ath5k_hw_set_imr(sc->ah, imask); | ||
1458 | spin_unlock_irqrestore(&sc->irqlock, flags); | ||
1459 | } | ||
1460 | |||
1461 | static void | ||
1447 | ath5k_tasklet_rx(unsigned long data) | 1462 | ath5k_tasklet_rx(unsigned long data) |
1448 | { | 1463 | { |
1449 | struct ath5k_rx_status rs = {}; | 1464 | struct ath5k_rx_status rs = {}; |
@@ -1506,6 +1521,8 @@ next: | |||
1506 | } while (ath5k_rxbuf_setup(sc, bf) == 0); | 1521 | } while (ath5k_rxbuf_setup(sc, bf) == 0); |
1507 | unlock: | 1522 | unlock: |
1508 | spin_unlock(&sc->rxbuflock); | 1523 | spin_unlock(&sc->rxbuflock); |
1524 | sc->rx_pending = false; | ||
1525 | ath5k_set_current_imask(sc); | ||
1509 | } | 1526 | } |
1510 | 1527 | ||
1511 | 1528 | ||
@@ -1573,28 +1590,28 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, | |||
1573 | struct ath5k_txq *txq, struct ath5k_tx_status *ts) | 1590 | struct ath5k_txq *txq, struct ath5k_tx_status *ts) |
1574 | { | 1591 | { |
1575 | struct ieee80211_tx_info *info; | 1592 | struct ieee80211_tx_info *info; |
1593 | u8 tries[3]; | ||
1576 | int i; | 1594 | int i; |
1577 | 1595 | ||
1578 | sc->stats.tx_all_count++; | 1596 | sc->stats.tx_all_count++; |
1579 | sc->stats.tx_bytes_count += skb->len; | 1597 | sc->stats.tx_bytes_count += skb->len; |
1580 | info = IEEE80211_SKB_CB(skb); | 1598 | info = IEEE80211_SKB_CB(skb); |
1581 | 1599 | ||
1600 | tries[0] = info->status.rates[0].count; | ||
1601 | tries[1] = info->status.rates[1].count; | ||
1602 | tries[2] = info->status.rates[2].count; | ||
1603 | |||
1582 | ieee80211_tx_info_clear_status(info); | 1604 | ieee80211_tx_info_clear_status(info); |
1583 | for (i = 0; i < 4; i++) { | 1605 | |
1606 | for (i = 0; i < ts->ts_final_idx; i++) { | ||
1584 | struct ieee80211_tx_rate *r = | 1607 | struct ieee80211_tx_rate *r = |
1585 | &info->status.rates[i]; | 1608 | &info->status.rates[i]; |
1586 | 1609 | ||
1587 | if (ts->ts_rate[i]) { | 1610 | r->count = tries[i]; |
1588 | r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]); | ||
1589 | r->count = ts->ts_retry[i]; | ||
1590 | } else { | ||
1591 | r->idx = -1; | ||
1592 | r->count = 0; | ||
1593 | } | ||
1594 | } | 1611 | } |
1595 | 1612 | ||
1596 | /* count the successful attempt as well */ | 1613 | info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry; |
1597 | info->status.rates[ts->ts_final_idx].count++; | 1614 | info->status.rates[ts->ts_final_idx + 1].idx = -1; |
1598 | 1615 | ||
1599 | if (unlikely(ts->ts_status)) { | 1616 | if (unlikely(ts->ts_status)) { |
1600 | sc->stats.ack_fail++; | 1617 | sc->stats.ack_fail++; |
@@ -1609,6 +1626,9 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, | |||
1609 | } else { | 1626 | } else { |
1610 | info->flags |= IEEE80211_TX_STAT_ACK; | 1627 | info->flags |= IEEE80211_TX_STAT_ACK; |
1611 | info->status.ack_signal = ts->ts_rssi; | 1628 | info->status.ack_signal = ts->ts_rssi; |
1629 | |||
1630 | /* count the successful attempt as well */ | ||
1631 | info->status.rates[ts->ts_final_idx].count++; | ||
1612 | } | 1632 | } |
1613 | 1633 | ||
1614 | /* | 1634 | /* |
@@ -1690,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data) | |||
1690 | for (i=0; i < AR5K_NUM_TX_QUEUES; i++) | 1710 | for (i=0; i < AR5K_NUM_TX_QUEUES; i++) |
1691 | if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) | 1711 | if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i))) |
1692 | ath5k_tx_processq(sc, &sc->txqs[i]); | 1712 | ath5k_tx_processq(sc, &sc->txqs[i]); |
1713 | |||
1714 | sc->tx_pending = false; | ||
1715 | ath5k_set_current_imask(sc); | ||
1693 | } | 1716 | } |
1694 | 1717 | ||
1695 | 1718 | ||
@@ -2119,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah) | |||
2119 | * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ | 2142 | * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ |
2120 | } | 2143 | } |
2121 | 2144 | ||
2145 | static void | ||
2146 | ath5k_schedule_rx(struct ath5k_softc *sc) | ||
2147 | { | ||
2148 | sc->rx_pending = true; | ||
2149 | tasklet_schedule(&sc->rxtq); | ||
2150 | } | ||
2151 | |||
2152 | static void | ||
2153 | ath5k_schedule_tx(struct ath5k_softc *sc) | ||
2154 | { | ||
2155 | sc->tx_pending = true; | ||
2156 | tasklet_schedule(&sc->txtq); | ||
2157 | } | ||
2158 | |||
2122 | irqreturn_t | 2159 | irqreturn_t |
2123 | ath5k_intr(int irq, void *dev_id) | 2160 | ath5k_intr(int irq, void *dev_id) |
2124 | { | 2161 | { |
@@ -2161,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id) | |||
2161 | ieee80211_queue_work(sc->hw, &sc->reset_work); | 2198 | ieee80211_queue_work(sc->hw, &sc->reset_work); |
2162 | } | 2199 | } |
2163 | else | 2200 | else |
2164 | tasklet_schedule(&sc->rxtq); | 2201 | ath5k_schedule_rx(sc); |
2165 | } else { | 2202 | } else { |
2166 | if (status & AR5K_INT_SWBA) { | 2203 | if (status & AR5K_INT_SWBA) { |
2167 | tasklet_hi_schedule(&sc->beacontq); | 2204 | tasklet_hi_schedule(&sc->beacontq); |
@@ -2179,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id) | |||
2179 | ath5k_hw_update_tx_triglevel(ah, true); | 2216 | ath5k_hw_update_tx_triglevel(ah, true); |
2180 | } | 2217 | } |
2181 | if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) | 2218 | if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) |
2182 | tasklet_schedule(&sc->rxtq); | 2219 | ath5k_schedule_rx(sc); |
2183 | if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC | 2220 | if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC |
2184 | | AR5K_INT_TXERR | AR5K_INT_TXEOL)) | 2221 | | AR5K_INT_TXERR | AR5K_INT_TXEOL)) |
2185 | tasklet_schedule(&sc->txtq); | 2222 | ath5k_schedule_tx(sc); |
2186 | if (status & AR5K_INT_BMISS) { | 2223 | if (status & AR5K_INT_BMISS) { |
2187 | /* TODO */ | 2224 | /* TODO */ |
2188 | } | 2225 | } |
@@ -2201,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id) | |||
2201 | 2238 | ||
2202 | } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); | 2239 | } while (ath5k_hw_is_intr_pending(ah) && --counter > 0); |
2203 | 2240 | ||
2241 | if (sc->rx_pending || sc->tx_pending) | ||
2242 | ath5k_set_current_imask(sc); | ||
2243 | |||
2204 | if (unlikely(!counter)) | 2244 | if (unlikely(!counter)) |
2205 | ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); | 2245 | ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); |
2206 | 2246 | ||
@@ -2572,6 +2612,8 @@ done: | |||
2572 | 2612 | ||
2573 | static void stop_tasklets(struct ath5k_softc *sc) | 2613 | static void stop_tasklets(struct ath5k_softc *sc) |
2574 | { | 2614 | { |
2615 | sc->rx_pending = false; | ||
2616 | sc->tx_pending = false; | ||
2575 | tasklet_kill(&sc->rxtq); | 2617 | tasklet_kill(&sc->rxtq); |
2576 | tasklet_kill(&sc->txtq); | 2618 | tasklet_kill(&sc->txtq); |
2577 | tasklet_kill(&sc->calib); | 2619 | tasklet_kill(&sc->calib); |
@@ -2838,7 +2880,7 @@ ath5k_init(struct ieee80211_hw *hw) | |||
2838 | INIT_WORK(&sc->reset_work, ath5k_reset_work); | 2880 | INIT_WORK(&sc->reset_work, ath5k_reset_work); |
2839 | INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work); | 2881 | INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work); |
2840 | 2882 | ||
2841 | ret = ath5k_eeprom_read_mac(ah, mac); | 2883 | ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac); |
2842 | if (ret) { | 2884 | if (ret) { |
2843 | ATH5K_ERR(sc, "unable to read address from EEPROM\n"); | 2885 | ATH5K_ERR(sc, "unable to read address from EEPROM\n"); |
2844 | goto err_queues; | 2886 | goto err_queues; |
@@ -2898,7 +2940,6 @@ ath5k_deinit_softc(struct ath5k_softc *sc) | |||
2898 | * XXX: ??? detach ath5k_hw ??? | 2940 | * XXX: ??? detach ath5k_hw ??? |
2899 | * Other than that, it's straightforward... | 2941 | * Other than that, it's straightforward... |
2900 | */ | 2942 | */ |
2901 | ath5k_debug_finish_device(sc); | ||
2902 | ieee80211_unregister_hw(hw); | 2943 | ieee80211_unregister_hw(hw); |
2903 | ath5k_desc_free(sc); | 2944 | ath5k_desc_free(sc); |
2904 | ath5k_txq_release(sc); | 2945 | ath5k_txq_release(sc); |