Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[linux-2.6.git] / drivers / net / wireless / ath / ath5k / base.c
index c085a06..93005f1 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/pci.h>
 #include <linux/ethtool.h>
 #include <linux/uaccess.h>
+#include <linux/slab.h>
 
 #include <net/ieee80211_radiotap.h>
 
@@ -230,7 +231,7 @@ static void ath5k_remove_interface(struct ieee80211_hw *hw,
                struct ieee80211_vif *vif);
 static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
 static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
-                                  int mc_count, struct dev_addr_list *mc_list);
+                                  struct netdev_hw_addr_list *mc_list);
 static void ath5k_configure_filter(struct ieee80211_hw *hw,
                unsigned int changed_flags,
                unsigned int *new_flags,
@@ -1636,7 +1637,6 @@ ath5k_txq_cleanup(struct ath5k_softc *sc)
                                        sc->txqs[i].link);
                        }
        }
-       ieee80211_wake_queues(sc->hw); /* XXX move to callers */
 
        for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
                if (sc->txqs[i].setup)
@@ -2084,6 +2084,17 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
        list_for_each_entry_safe(bf, bf0, &txq->q, list) {
                ds = bf->desc;
 
+               /*
+                * It's possible that the hardware can say the buffer is
+                * completed when it hasn't yet loaded the ds_link from
+                * host memory and moved on.  If there are more TX
+                * descriptors in the queue, wait for TXDP to change
+                * before processing this one.
+                */
+               if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr &&
+                   !list_is_last(&bf->list, &txq->q))
+                       break;
+
                ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
                if (unlikely(ret == -EINPROGRESS))
                        break;
@@ -2548,8 +2559,7 @@ ath5k_init(struct ath5k_softc *sc)
        for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
                ath5k_hw_reset_key(ah, i);
 
-       /* Set ack to be sent at low bit-rates */
-       ath5k_hw_set_ack_bitrate_high(ah, false);
+       ath5k_hw_set_ack_bitrate_high(ah, true);
        ret = 0;
 done:
        mmiowb();
@@ -2696,7 +2706,20 @@ ath5k_intr(int irq, void *dev_id)
                         */
                        tasklet_schedule(&sc->restq);
                } else if (unlikely(status & AR5K_INT_RXORN)) {
-                       tasklet_schedule(&sc->restq);
+                       /*
+                        * Receive buffers are full. Either the bus is busy or
+                        * the CPU is not fast enough to process all received
+                        * frames.
+                        * Older chipsets need a reset to come out of this
+                        * condition, but we treat it as RX for newer chips.
+                        * We don't know exactly which versions need a reset -
+                        * this guess is copied from the HAL.
+                        */
+                       sc->stats.rxorn_intr++;
+                       if (ah->ah_mac_srev < AR5K_SREV_AR5212)
+                               tasklet_schedule(&sc->restq);
+                       else
+                               tasklet_schedule(&sc->rxtq);
                } else {
                        if (status & AR5K_INT_SWBA) {
                                tasklet_hi_schedule(&sc->beacontq);
@@ -2775,7 +2798,7 @@ ath5k_tasklet_calibrate(unsigned long data)
                 * to load new gain values.
                 */
                ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
-               ath5k_reset_wake(sc);
+               ath5k_reset(sc, sc->curchan);
        }
        if (ath5k_hw_phy_calibrate(ah, sc->curchan))
                ATH5K_ERR(sc, "calibration of channel %u failed\n",
@@ -3050,22 +3073,20 @@ unlock:
 }
 
 static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
-                                  int mc_count, struct dev_addr_list *mclist)
+                                  struct netdev_hw_addr_list *mc_list)
 {
        u32 mfilt[2], val;
-       int i;
        u8 pos;
+       struct netdev_hw_addr *ha;
 
        mfilt[0] = 0;
        mfilt[1] = 1;
 
-       for (i = 0; i < mc_count; i++) {
-               if (!mclist)
-                       break;
+       netdev_hw_addr_list_for_each(ha, mc_list) {
                /* calculate XOR of eight 6-bit values */
-               val = get_unaligned_le32(mclist->dmi_addr + 0);
+               val = get_unaligned_le32(ha->addr + 0);
                pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
-               val = get_unaligned_le32(mclist->dmi_addr + 3);
+               val = get_unaligned_le32(ha->addr + 3);
                pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
                pos &= 0x3f;
                mfilt[pos / 32] |= (1 << (pos % 32));
@@ -3073,8 +3094,7 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
                * but not sure, needs testing, if we do use this we'd
                * neet to inform below to not reset the mcast */
                /* ath5k_hw_set_mcast_filterindex(ah,
-                *      mclist->dmi_addr[5]); */
-               mclist = mclist->next;
+                *      ha->addr[5]); */
        }
 
        return ((u64)(mfilt[1]) << 32) | mfilt[0];