]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/ath5k/base.c
ath5k: properly free rx dma descriptors
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / ath5k / base.c
index fa39f21c36c3f024b419fe271ca3e569bdb186c4..f9d486ff04f20e496681dc683ea98fd6aed94373 100644 (file)
@@ -239,6 +239,7 @@ static int ath5k_get_stats(struct ieee80211_hw *hw,
 static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
                struct ieee80211_tx_queue_stats *stats);
 static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
+static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf);
 static void ath5k_reset_tsf(struct ieee80211_hw *hw);
 static int ath5k_beacon_update(struct ath5k_softc *sc,
                struct sk_buff *skb);
@@ -261,6 +262,7 @@ static struct ieee80211_ops ath5k_hw_ops = {
        .conf_tx        = NULL,
        .get_tx_stats   = ath5k_get_tx_stats,
        .get_tsf        = ath5k_get_tsf,
+       .set_tsf        = ath5k_set_tsf,
        .reset_tsf      = ath5k_reset_tsf,
        .bss_info_changed = ath5k_bss_info_changed,
 };
@@ -308,6 +310,19 @@ static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
        bf->skb = NULL;
 }
 
+static inline void ath5k_rxbuf_free(struct ath5k_softc *sc,
+                               struct ath5k_buf *bf)
+{
+       BUG_ON(!bf);
+       if (!bf->skb)
+               return;
+       pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
+                       PCI_DMA_FROMDEVICE);
+       dev_kfree_skb_any(bf->skb);
+       bf->skb = NULL;
+}
+
+
 /* Queues setup */
 static struct  ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc,
                                int qtype, int subtype);
@@ -1021,6 +1036,8 @@ ath5k_setup_bands(struct ieee80211_hw *hw)
  * it's done by reseting the chip.  To accomplish this we must
  * first cleanup any pending DMA, then restart stuff after a la
  * ath5k_init.
+ *
+ * Called with sc->lock.
  */
 static int
 ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
@@ -1339,7 +1356,7 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
        list_for_each_entry(bf, &sc->txbuf, list)
                ath5k_txbuf_free(sc, bf);
        list_for_each_entry(bf, &sc->rxbuf, list)
-               ath5k_txbuf_free(sc, bf);
+               ath5k_rxbuf_free(sc, bf);
 
        /* Free memory associated with all descriptors */
        pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
@@ -2624,8 +2641,12 @@ ath5k_init_leds(struct ath5k_softc *sc)
                sc->led_pin = 1;
                sc->led_on = 1;  /* active high */
        }
-       /* Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) */
-       if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN) {
+       /*
+        * Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) and
+        * in emachines notebooks with AMBIT subsystem.
+        */
+       if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN ||
+           pdev->subsystem_vendor == PCI_VENDOR_ID_AMBIT) {
                __set_bit(ATH_STAT_LEDSOFT, sc->status);
                sc->led_pin = 3;
                sc->led_on = 0;  /* active low */
@@ -2849,11 +2870,17 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct ath5k_softc *sc = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
+       int ret;
+
+       mutex_lock(&sc->lock);
 
        sc->bintval = conf->beacon_int;
        sc->power_level = conf->power_level;
 
-       return ath5k_chan_set(sc, conf->channel);
+       ret = ath5k_chan_set(sc, conf->channel);
+
+       mutex_unlock(&sc->lock);
+       return ret;
 }
 
 static int
@@ -3110,6 +3137,14 @@ ath5k_get_tsf(struct ieee80211_hw *hw)
        return ath5k_hw_get_tsf64(sc->ah);
 }
 
+static void
+ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+{
+       struct ath5k_softc *sc = hw->priv;
+
+       ath5k_hw_set_tsf64(sc->ah, tsf);
+}
+
 static void
 ath5k_reset_tsf(struct ieee80211_hw *hw)
 {