ath9k: fix some issues with ar934x rev 3 (especially ad-hoc mode)
[oweals/openwrt.git] / package / kernel / mac80211 / patches / 300-pending_work.patch
index 0a2e86b1d7bc2f539b84d4b4a23ec5a1eb413ec9..1ee8e9833a1ecd5bdf9c65dd75856cdc8a300163 100644 (file)
-commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873
+commit 4c82fc569cf2f29e6c66d98ef4a1b0f3b6a98e9d
 Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Fri May 23 19:58:14 2014 +0200
+Date:   Sat Sep 27 22:39:27 2014 +0200
 
-    mac80211: reduce packet loss notifications under load
+    ath9k_hw: disable hardware ad-hoc flag on ar934x rev 3
     
-    During strong signal fluctuations under high throughput, few consecutive
-    failed A-MPDU transmissions can easily trigger packet loss notification,
-    and thus (in AP mode) client disconnection.
+    On AR934x rev 3, settin the ad-hoc flag completely messes up hardware
+    state - beacons get stuck, almost no packets make it out, hardware is
+    constantly reset.
     
-    Reduce the number of false positives by checking the A-MPDU status flag
-    and treating a failed A-MPDU as a single packet.
+    When leaving out that flag and setting up the hw like in AP mode, TSF
+    timers won't be automatically synced, but at least the rest works.
+    
+    AR934x rev 2 and older are not affected by this bug
     
     Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit 7b7843a36fbcc568834404c7430ff895d8502131
+commit ecfb4b3fff006372ac5c40871f9bb182fd00444f
 Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Fri May 23 19:26:32 2014 +0200
+Date:   Sat Sep 27 22:15:43 2014 +0200
 
-    mac80211: fix a memory leak on sta rate selection table
+    ath9k: use ah->get_mac_revision for all SoC devices if available
+    
+    It is needed for AR934x as well
     
-    Cc: stable@vger.kernel.org
-    Reported-by: Christophe Prévotaux <cprevotaux@nltinc.com>
     Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
-commit 96892d6aa0a153423070addf3070bc79578b3897
+commit c11113bc25df22898fb995d3205bdc4f27c98073
 Author: Felix Fietkau <nbd@openwrt.org>
-Date:   Mon May 19 21:20:49 2014 +0200
+Date:   Sat Sep 27 18:04:58 2014 +0200
 
-    ath9k: avoid passing buffers to the hardware during flush
+    ath5k: add missing include for debug code
     
-    The commit "ath9k: fix possible hang on flush" changed the receive code
-    to always link rx descriptors of processed frames, even when flushing.
-    In some cases, this leads to flushed rx buffers being passed to the
-    hardware while rx is already stopped.
+    Needed for calling vmalloc()/vfree()
     
     Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -34,7 +34,8 @@ static inline bool ath9k_check_auto_slee
-  * buffer (or rx fifo). This can incorrectly acknowledge packets
-  * to a sender if last desc is self-linked.
-  */
--static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf)
-+static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf,
-+                          bool flush)
- {
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-@@ -59,18 +60,19 @@ static void ath_rx_buf_link(struct ath_s
-                            common->rx_bufsize,
-                            0);
+commit 83f76a9f9a42773c7eef90bb86b4b2c16b0b3755
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Sat Sep 27 15:58:51 2014 +0200
+
+    ath5k: fix AHB kconfig dependency
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit ddd67f2a5cfd73fad4b78190025402d419b9f0a9
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Sat Sep 27 15:57:09 2014 +0200
+
+    Revert "ath5k: Remove AHB bus support"
+    
+    This reverts commit 093ec3c5337434f40d77c1af06c139da3e5ba6dc.
+
+--- a/drivers/net/wireless/ath/ath5k/Kconfig
++++ b/drivers/net/wireless/ath/ath5k/Kconfig
+@@ -2,12 +2,14 @@ config ATH5K
+       tristate "Atheros 5xxx wireless cards support"
+       depends on m
+       depends on PCI && MAC80211
++      depends on (PCI || ATHEROS_AR231X) && MAC80211
+       select ATH_COMMON
+       select MAC80211_LEDS
+       select BACKPORT_LEDS_CLASS
+       select BACKPORT_NEW_LEDS
+       select BACKPORT_AVERAGE
+-      select ATH5K_PCI
++      select ATH5K_AHB if ATHEROS_AR231X
++      select ATH5K_PCI if !ATHEROS_AR231X
+       ---help---
+         This module adds support for wireless adapters based on
+         Atheros 5xxx chipset.
+@@ -52,9 +54,16 @@ config ATH5K_TRACER
  
--      if (sc->rx.rxlink == NULL)
--              ath9k_hw_putrxbuf(ah, bf->bf_daddr);
--      else
-+      if (sc->rx.rxlink)
-               *sc->rx.rxlink = bf->bf_daddr;
-+      else if (!flush)
-+              ath9k_hw_putrxbuf(ah, bf->bf_daddr);
+         If unsure, say N.
  
-       sc->rx.rxlink = &ds->ds_link;
++config ATH5K_AHB
++      bool "Atheros 5xxx AHB bus support"
++      depends on ATHEROS_AR231X
++      ---help---
++        This adds support for WiSoC type chipsets of the 5xxx Atheros
++        family.
++
+ config ATH5K_PCI
+       bool "Atheros 5xxx PCI bus support"
+-      depends on PCI
++      depends on !ATHEROS_AR231X
+       ---help---
+         This adds support for PCI type chipsets of the 5xxx Atheros
+         family.
+--- /dev/null
++++ b/drivers/net/wireless/ath/ath5k/ahb.c
+@@ -0,0 +1,234 @@
++/*
++ * Copyright (c) 2008-2009 Atheros Communications Inc.
++ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#include <linux/nl80211.h>
++#include <linux/platform_device.h>
++#include <linux/etherdevice.h>
++#include <linux/export.h>
++#include <ar231x_platform.h>
++#include "ath5k.h"
++#include "debug.h"
++#include "base.h"
++#include "reg.h"
++
++/* return bus cachesize in 4B word units */
++static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz)
++{
++      *csz = L1_CACHE_BYTES >> 2;
++}
++
++static bool
++ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
++{
++      struct ath5k_hw *ah = common->priv;
++      struct platform_device *pdev = to_platform_device(ah->dev);
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      u16 *eeprom, *eeprom_end;
++
++      eeprom = (u16 *) bcfg->radio;
++      eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ;
++
++      eeprom += off;
++      if (eeprom > eeprom_end)
++              return false;
++
++      *data = *eeprom;
++      return true;
++}
++
++int ath5k_hw_read_srev(struct ath5k_hw *ah)
++{
++      struct platform_device *pdev = to_platform_device(ah->dev);
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      ah->ah_mac_srev = bcfg->devid;
++      return 0;
++}
++
++static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
++{
++      struct platform_device *pdev = to_platform_device(ah->dev);
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      u8 *cfg_mac;
++
++      if (to_platform_device(ah->dev)->id == 0)
++              cfg_mac = bcfg->config->wlan0_mac;
++      else
++              cfg_mac = bcfg->config->wlan1_mac;
++
++      memcpy(mac, cfg_mac, ETH_ALEN);
++      return 0;
++}
++
++static const struct ath_bus_ops ath_ahb_bus_ops = {
++      .ath_bus_type = ATH_AHB,
++      .read_cachesize = ath5k_ahb_read_cachesize,
++      .eeprom_read = ath5k_ahb_eeprom_read,
++      .eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
++};
++
++/*Initialization*/
++static int ath_ahb_probe(struct platform_device *pdev)
++{
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      struct ath5k_hw *ah;
++      struct ieee80211_hw *hw;
++      struct resource *res;
++      void __iomem *mem;
++      int irq;
++      int ret = 0;
++      u32 reg;
++
++      if (!dev_get_platdata(&pdev->dev)) {
++              dev_err(&pdev->dev, "no platform data specified\n");
++              ret = -EINVAL;
++              goto err_out;
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (res == NULL) {
++              dev_err(&pdev->dev, "no memory resource found\n");
++              ret = -ENXIO;
++              goto err_out;
++      }
++
++      mem = ioremap_nocache(res->start, resource_size(res));
++      if (mem == NULL) {
++              dev_err(&pdev->dev, "ioremap failed\n");
++              ret = -ENOMEM;
++              goto err_out;
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++      if (res == NULL) {
++              dev_err(&pdev->dev, "no IRQ resource found\n");
++              ret = -ENXIO;
++              goto err_iounmap;
++      }
++
++      irq = res->start;
++
++      hw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), &ath5k_hw_ops);
++      if (hw == NULL) {
++              dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
++              ret = -ENOMEM;
++              goto err_iounmap;
++      }
++
++      ah = hw->priv;
++      ah->hw = hw;
++      ah->dev = &pdev->dev;
++      ah->iobase = mem;
++      ah->irq = irq;
++      ah->devid = bcfg->devid;
++
++      if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
++              /* Enable WMAC AHB arbitration */
++              reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
++              reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
++              iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
++
++              /* Enable global WMAC swapping */
++              reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP);
++              reg |= AR5K_AR2315_BYTESWAP_WMAC;
++              iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
++      } else {
++              /* Enable WMAC DMA access (assuming 5312 or 231x*/
++              /* TODO: check other platforms */
++              reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
++              if (to_platform_device(ah->dev)->id == 0)
++                      reg |= AR5K_AR5312_ENABLE_WLAN0;
++              else
++                      reg |= AR5K_AR5312_ENABLE_WLAN1;
++              iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
++
++              /*
++               * On a dual-band AR5312, the multiband radio is only
++               * used as pass-through. Disable 2 GHz support in the
++               * driver for it
++               */
++              if (to_platform_device(ah->dev)->id == 0 &&
++                  (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) ==
++                   (BD_WLAN1 | BD_WLAN0))
++                      ah->ah_capabilities.cap_needs_2GHz_ovr = true;
++              else
++                      ah->ah_capabilities.cap_needs_2GHz_ovr = false;
++      }
++
++      ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
++      if (ret != 0) {
++              dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
++              ret = -ENODEV;
++              goto err_free_hw;
++      }
++
++      platform_set_drvdata(pdev, hw);
++
++      return 0;
++
++ err_free_hw:
++      ieee80211_free_hw(hw);
++ err_iounmap:
++        iounmap(mem);
++ err_out:
++      return ret;
++}
++
++static int ath_ahb_remove(struct platform_device *pdev)
++{
++      struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
++      struct ieee80211_hw *hw = platform_get_drvdata(pdev);
++      struct ath5k_hw *ah;
++      u32 reg;
++
++      if (!hw)
++              return 0;
++
++      ah = hw->priv;
++
++      if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
++              /* Disable WMAC AHB arbitration */
++              reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
++              reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
++              iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
++      } else {
++              /*Stop DMA access */
++              reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
++              if (to_platform_device(ah->dev)->id == 0)
++                      reg &= ~AR5K_AR5312_ENABLE_WLAN0;
++              else
++                      reg &= ~AR5K_AR5312_ENABLE_WLAN1;
++              iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
++      }
++
++      ath5k_deinit_ah(ah);
++      iounmap(ah->iobase);
++      ieee80211_free_hw(hw);
++
++      return 0;
++}
++
++static struct platform_driver ath_ahb_driver = {
++      .probe      = ath_ahb_probe,
++      .remove     = ath_ahb_remove,
++      .driver         = {
++              .name   = "ar231x-wmac",
++              .owner  = THIS_MODULE,
++      },
++};
++
++module_platform_driver(ath_ahb_driver);
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -1647,6 +1647,32 @@ static inline struct ath_regulatory *ath
+       return &(ath5k_hw_common(ah)->regulatory);
  }
  
--static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf)
-+static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf,
-+                            bool flush)
++#ifdef CONFIG_ATHEROS_AR231X
++#define AR5K_AR2315_PCI_BASE  ((void __iomem *)0xb0100000)
++
++static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
++{
++      /* On AR2315 and AR2317 the PCI clock domain registers
++       * are outside of the WMAC register space */
++      if (unlikely((reg >= 0x4000) && (reg < 0x5000) &&
++          (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6)))
++              return AR5K_AR2315_PCI_BASE + reg;
++
++      return ah->iobase + reg;
++}
++
++static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
++{
++      return ioread32(ath5k_ahb_reg(ah, reg));
++}
++
++static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
++{
++      iowrite32(val, ath5k_ahb_reg(ah, reg));
++}
++
++#else
++
+ static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
  {
-       if (sc->rx.buf_hold)
--              ath_rx_buf_link(sc, sc->rx.buf_hold);
-+              ath_rx_buf_link(sc, sc->rx.buf_hold, flush);
-       sc->rx.buf_hold = bf;
+       return ioread32(ah->iobase + reg);
+@@ -1657,6 +1683,8 @@ static inline void ath5k_hw_reg_write(st
+       iowrite32(val, ah->iobase + reg);
  }
-@@ -442,7 +444,7 @@ int ath_startrecv(struct ath_softc *sc)
-       sc->rx.buf_hold = NULL;
-       sc->rx.rxlink = NULL;
-       list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
--              ath_rx_buf_link(sc, bf);
-+              ath_rx_buf_link(sc, bf, false);
-       }
  
-       /* We could have deleted elements so the list may be empty now */
-@@ -1118,12 +1120,12 @@ requeue_drop_frag:
- requeue:
-               list_add_tail(&bf->list, &sc->rx.rxbuf);
++#endif
++
+ static inline enum ath_bus_type ath5k_get_bus_type(struct ath5k_hw *ah)
+ {
+       return ath5k_hw_common(ah)->bus_ops->ath_bus_type;
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -99,6 +99,15 @@ static int ath5k_reset(struct ath5k_hw *
  
--              if (edma) {
--                      ath_rx_edma_buf_link(sc, qtype);
--              } else {
--                      ath_rx_buf_relink(sc, bf);
-+              if (!edma) {
-+                      ath_rx_buf_relink(sc, bf, flush);
-                       if (!flush)
-                               ath9k_hw_rxena(ah);
-+              } else if (!flush) {
-+                      ath_rx_edma_buf_link(sc, qtype);
-               }
+ /* Known SREVs */
+ static const struct ath5k_srev_name srev_names[] = {
++#ifdef CONFIG_ATHEROS_AR231X
++      { "5312",       AR5K_VERSION_MAC,       AR5K_SREV_AR5312_R2 },
++      { "5312",       AR5K_VERSION_MAC,       AR5K_SREV_AR5312_R7 },
++      { "2313",       AR5K_VERSION_MAC,       AR5K_SREV_AR2313_R8 },
++      { "2315",       AR5K_VERSION_MAC,       AR5K_SREV_AR2315_R6 },
++      { "2315",       AR5K_VERSION_MAC,       AR5K_SREV_AR2315_R7 },
++      { "2317",       AR5K_VERSION_MAC,       AR5K_SREV_AR2317_R1 },
++      { "2317",       AR5K_VERSION_MAC,       AR5K_SREV_AR2317_R2 },
++#else
+       { "5210",       AR5K_VERSION_MAC,       AR5K_SREV_AR5210 },
+       { "5311",       AR5K_VERSION_MAC,       AR5K_SREV_AR5311 },
+       { "5311A",      AR5K_VERSION_MAC,       AR5K_SREV_AR5311A },
+@@ -117,6 +126,7 @@ static const struct ath5k_srev_name srev
+       { "5418",       AR5K_VERSION_MAC,       AR5K_SREV_AR5418 },
+       { "2425",       AR5K_VERSION_MAC,       AR5K_SREV_AR2425 },
+       { "2417",       AR5K_VERSION_MAC,       AR5K_SREV_AR2417 },
++#endif
+       { "xxxxx",      AR5K_VERSION_MAC,       AR5K_SREV_UNKNOWN },
+       { "5110",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5110 },
+       { "5111",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5111 },
+@@ -132,6 +142,10 @@ static const struct ath5k_srev_name srev
+       { "5413",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5413 },
+       { "5424",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5424 },
+       { "5133",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5133 },
++#ifdef CONFIG_ATHEROS_AR231X
++      { "2316",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2316 },
++      { "2317",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2317 },
++#endif
+       { "xxxxx",      AR5K_VERSION_RAD,       AR5K_SREV_UNKNOWN },
+ };
  
-               if (!budget--)
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -227,6 +227,7 @@ struct sta_info *sta_info_get_by_idx(str
-  */
- void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
+--- a/drivers/net/wireless/ath/ath5k/led.c
++++ b/drivers/net/wireless/ath/ath5k/led.c
+@@ -163,14 +163,20 @@ int ath5k_init_leds(struct ath5k_hw *ah)
  {
-+      struct ieee80211_sta_rates *rates;
-       int i;
+       int ret = 0;
+       struct ieee80211_hw *hw = ah->hw;
++#ifndef CONFIG_ATHEROS_AR231X
+       struct pci_dev *pdev = ah->pdev;
++#endif
+       char name[ATH5K_LED_MAX_NAME_LEN + 1];
+       const struct pci_device_id *match;
  
-       if (sta->rate_ctrl)
-@@ -238,6 +239,10 @@ void sta_info_free(struct ieee80211_loca
-               kfree(sta->tx_lat);
-       }
+       if (!ah->pdev)
+               return 0;
  
-+      rates = rcu_dereference_protected(sta->sta.rates, true);
-+      if (rates)
-+              kfree(rates);
-+
-       sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
++#ifdef CONFIG_ATHEROS_AR231X
++      match = NULL;
++#else
+       match = pci_match_id(&ath5k_led_devices[0], pdev);
++#endif
+       if (match) {
+               __set_bit(ATH_STAT_LEDSOFT, ah->status);
+               ah->led_pin = ATH_PIN(match->driver_data);
+--- a/drivers/net/wireless/ath/ath5k/debug.c
++++ b/drivers/net/wireless/ath/ath5k/debug.c
+@@ -65,6 +65,7 @@
  
-       kfree(sta);
---- a/net/mac80211/status.c
-+++ b/net/mac80211/status.c
-@@ -541,6 +541,23 @@ static void ieee80211_tx_latency_end_msr
-  */
- #define STA_LOST_PKT_THRESHOLD        50
+ #include <linux/seq_file.h>
+ #include <linux/list.h>
++#include <linux/vmalloc.h>
+ #include "debug.h"
+ #include "ath5k.h"
+ #include "reg.h"
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -222,31 +222,28 @@ static void ath9k_hw_read_revisions(stru
+ {
+       u32 val;
  
-+static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
-+{
-+      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-+
-+      /* This packet was aggregated but doesn't carry status info */
-+      if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
-+          !(info->flags & IEEE80211_TX_STAT_AMPDU))
-+              return;
-+
-+      if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD)
-+              return;
++      if (ah->get_mac_revision)
++              ah->hw_version.macRev = ah->get_mac_revision();
 +
-+      cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
-+                                  sta->lost_packets, GFP_ATOMIC);
-+      sta->lost_packets = 0;
-+}
-+
- void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
- {
-       struct sk_buff *skb2;
-@@ -680,12 +697,8 @@ void ieee80211_tx_status(struct ieee8021
-                       if (info->flags & IEEE80211_TX_STAT_ACK) {
-                               if (sta->lost_packets)
-                                       sta->lost_packets = 0;
--                      } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) {
--                              cfg80211_cqm_pktloss_notify(sta->sdata->dev,
--                                                          sta->sta.addr,
--                                                          sta->lost_packets,
--                                                          GFP_ATOMIC);
--                              sta->lost_packets = 0;
-+                      } else {
-+                              ieee80211_lost_packet(sta, skb);
-                       }
+       switch (ah->hw_version.devid) {
+       case AR5416_AR9100_DEVID:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9100;
+               break;
+       case AR9300_DEVID_AR9330:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9330;
+-              if (ah->get_mac_revision) {
+-                      ah->hw_version.macRev = ah->get_mac_revision();
+-              } else {
++              if (!ah->get_mac_revision) {
+                       val = REG_READ(ah, AR_SREV);
+                       ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
                }
+               return;
+       case AR9300_DEVID_AR9340:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9340;
+-              val = REG_READ(ah, AR_SREV);
+-              ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
+               return;
+       case AR9300_DEVID_QCA955X:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9550;
+               return;
+       case AR9300_DEVID_AR953X:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9531;
+-              if (ah->get_mac_revision)
+-                      ah->hw_version.macRev = ah->get_mac_revision();
+               return;
+       }
+@@ -1192,9 +1189,12 @@ static void ath9k_hw_set_operating_mode(
  
+       switch (opmode) {
+       case NL80211_IFTYPE_ADHOC:
+-              set |= AR_STA_ID1_ADHOC;
+-              REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+-              break;
++              if (!AR_SREV_9340_13(ah)) {
++                      set |= AR_STA_ID1_ADHOC;
++                      REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
++                      break;
++              }
++              /* fall through */
+       case NL80211_IFTYPE_MESH_POINT:
+       case NL80211_IFTYPE_AP:
+               set |= AR_STA_ID1_STA_AP;
+--- a/drivers/net/wireless/ath/ath9k/reg.h
++++ b/drivers/net/wireless/ath/ath9k/reg.h
+@@ -903,6 +903,10 @@
+ #define AR_SREV_9340(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340))
++#define AR_SREV_9340_13(_ah) \
++      (AR_SREV_9340((_ah)) && \
++       ((_ah)->hw_version.macRev == AR_SREV_REVISION_9340_13))
++
+ #define AR_SREV_9340_13_OR_LATER(_ah) \
+       (AR_SREV_9340((_ah)) && \
+        ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9340_13))