ath9k: add stability fixes for long standing hang issues (FS#13, #34, #373, #383)
authorFelix Fietkau <nbd@nbd.name>
Wed, 25 Jan 2017 14:32:18 +0000 (15:32 +0100)
committerFelix Fietkau <nbd@nbd.name>
Wed, 25 Jan 2017 15:25:48 +0000 (16:25 +0100)
The radio would stop communicating completely. This issue was easiest to
trigger on AR913x devices, e.g. the TP-Link TL-WR1043ND, but other
hardware was occasionally affected as well.

The most critical issue was a race condition in disabling/enabling IRQs
between the IRQ handler and the IRQ processing tasklet

Signed-off-by: Felix Fietkau <nbd@nbd.name>
16 files changed:
package/kernel/mac80211/patches/354-ath9k-rename-tx_complete_work-to-hw_check_work.patch [new file with mode: 0644]
package/kernel/mac80211/patches/355-ath9k_hw-check-if-the-chip-failed-to-wake-up.patch [new file with mode: 0644]
package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch [new file with mode: 0644]
package/kernel/mac80211/patches/357-ath9k-fix-race-condition-in-enabling-disabling-IRQs.patch [new file with mode: 0644]
package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch
package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch

diff --git a/package/kernel/mac80211/patches/354-ath9k-rename-tx_complete_work-to-hw_check_work.patch b/package/kernel/mac80211/patches/354-ath9k-rename-tx_complete_work-to-hw_check_work.patch
new file mode 100644 (file)
index 0000000..31a0277
--- /dev/null
@@ -0,0 +1,175 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 25 Jan 2017 12:57:05 +0100
+Subject: [PATCH] ath9k: rename tx_complete_work to hw_check_work
+
+Also include common MAC alive check. This should make the hang checks
+more reliable for modes where beacons are not sent and is used as a
+starting point for further hang check improvements
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -108,7 +108,7 @@ int ath_descdma_setup(struct ath_softc *
+ #define ATH_AGGR_MIN_QDEPTH        2
+ /* minimum h/w qdepth for non-aggregated traffic */
+ #define ATH_NON_AGGR_MIN_QDEPTH    8
+-#define ATH_TX_COMPLETE_POLL_INT   1000
++#define ATH_HW_CHECK_POLL_INT      1000
+ #define ATH_TXFIFO_DEPTH           8
+ #define ATH_TX_ERROR               0x01
+@@ -745,7 +745,7 @@ void ath9k_csa_update(struct ath_softc *
+ #define ATH_PAPRD_TIMEOUT         100 /* msecs */
+ #define ATH_PLL_WORK_INTERVAL     100
+-void ath_tx_complete_poll_work(struct work_struct *work);
++void ath_hw_check_work(struct work_struct *work);
+ void ath_reset_work(struct work_struct *work);
+ bool ath_hw_check(struct ath_softc *sc);
+ void ath_hw_pll_work(struct work_struct *work);
+@@ -1053,7 +1053,7 @@ struct ath_softc {
+ #ifdef CPTCFG_ATH9K_DEBUGFS
+       struct ath9k_debug debug;
+ #endif
+-      struct delayed_work tx_complete_work;
++      struct delayed_work hw_check_work;
+       struct delayed_work hw_pll_work;
+       struct timer_list sleep_timer;
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -681,6 +681,7 @@ static int ath9k_init_softc(u16 devid, s
+       INIT_WORK(&sc->hw_reset_work, ath_reset_work);
+       INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
+       INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
++      INIT_DELAYED_WORK(&sc->hw_check_work, ath_hw_check_work);
+       ath9k_init_channel_context(sc);
+--- a/drivers/net/wireless/ath/ath9k/link.c
++++ b/drivers/net/wireless/ath/ath9k/link.c
+@@ -20,20 +20,13 @@
+  * TX polling - checks if the TX engine is stuck somewhere
+  * and issues a chip reset if so.
+  */
+-void ath_tx_complete_poll_work(struct work_struct *work)
++static bool ath_tx_complete_check(struct ath_softc *sc)
+ {
+-      struct ath_softc *sc = container_of(work, struct ath_softc,
+-                                          tx_complete_work.work);
+       struct ath_txq *txq;
+       int i;
+-      bool needreset = false;
+-
+-      if (sc->tx99_state) {
+-              ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
+-                      "skip tx hung detection on tx99\n");
+-              return;
+-      }
++      if (sc->tx99_state)
++              return true;
+       for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+               txq = sc->tx.txq_map[i];
+@@ -41,25 +34,36 @@ void ath_tx_complete_poll_work(struct wo
+               ath_txq_lock(sc, txq);
+               if (txq->axq_depth) {
+                       if (txq->axq_tx_inprogress) {
+-                              needreset = true;
+                               ath_txq_unlock(sc, txq);
+-                              break;
+-                      } else {
+-                              txq->axq_tx_inprogress = true;
++                              goto reset;
+                       }
++
++                      txq->axq_tx_inprogress = true;
+               }
+               ath_txq_unlock(sc, txq);
+       }
+-      if (needreset) {
+-              ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
+-                      "tx hung, resetting the chip\n");
+-              ath9k_queue_reset(sc, RESET_TYPE_TX_HANG);
++      return true;
++
++reset:
++      ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
++              "tx hung, resetting the chip\n");
++      ath9k_queue_reset(sc, RESET_TYPE_TX_HANG);
++      return false;
++
++}
++
++void ath_hw_check_work(struct work_struct *work)
++{
++      struct ath_softc *sc = container_of(work, struct ath_softc,
++                                          hw_check_work.work);
++
++      if (!ath_hw_check(sc) ||
++          !ath_tx_complete_check(sc))
+               return;
+-      }
+-      ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
+-                                   msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
++      ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
++                                   msecs_to_jiffies(ATH_HW_CHECK_POLL_INT));
+ }
+ /*
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -181,7 +181,7 @@ void ath9k_ps_restore(struct ath_softc *
+ static void __ath_cancel_work(struct ath_softc *sc)
+ {
+       cancel_work_sync(&sc->paprd_work);
+-      cancel_delayed_work_sync(&sc->tx_complete_work);
++      cancel_delayed_work_sync(&sc->hw_check_work);
+       cancel_delayed_work_sync(&sc->hw_pll_work);
+ #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
+@@ -198,7 +198,8 @@ void ath_cancel_work(struct ath_softc *s
+ void ath_restart_work(struct ath_softc *sc)
+ {
+-      ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
++      ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
++                                   ATH_HW_CHECK_POLL_INT);
+       if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah))
+               ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
+@@ -2091,7 +2092,7 @@ void __ath9k_flush(struct ieee80211_hw *
+       int timeout;
+       bool drain_txq;
+-      cancel_delayed_work_sync(&sc->tx_complete_work);
++      cancel_delayed_work_sync(&sc->hw_check_work);
+       if (ah->ah_flags & AH_UNPLUGGED) {
+               ath_dbg(common, ANY, "Device has been unplugged!\n");
+@@ -2129,7 +2130,8 @@ void __ath9k_flush(struct ieee80211_hw *
+               ath9k_ps_restore(sc);
+       }
+-      ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
++      ieee80211_queue_delayed_work(hw, &sc->hw_check_work,
++                                   ATH_HW_CHECK_POLL_INT);
+ }
+ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -2915,8 +2915,6 @@ int ath_tx_init(struct ath_softc *sc, in
+               return error;
+       }
+-      INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
+-
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               error = ath_tx_edma_init(sc);
diff --git a/package/kernel/mac80211/patches/355-ath9k_hw-check-if-the-chip-failed-to-wake-up.patch b/package/kernel/mac80211/patches/355-ath9k_hw-check-if-the-chip-failed-to-wake-up.patch
new file mode 100644 (file)
index 0000000..b0cb74a
--- /dev/null
@@ -0,0 +1,30 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 25 Jan 2017 12:58:17 +0100
+Subject: [PATCH] ath9k_hw: check if the chip failed to wake up
+
+In an RFC patch, Sven Eckelmann and Simon Wunderlich reported:
+
+"QCA 802.11n chips (especially AR9330/AR9340) sometimes end up in a
+state in which a read of AR_CFG always returns 0xdeadbeef.
+This should not happen when when the power_mode of the device is
+ATH9K_PM_AWAKE."
+
+Include the check for the default register state in the existing MAC
+hang check.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1624,6 +1624,10 @@ bool ath9k_hw_check_alive(struct ath_hw
+       int count = 50;
+       u32 reg, last_val;
++      /* Check if chip failed to wake up */
++      if (REG_READ(ah, AR_CFG) == 0xdeadbeef)
++              return false;
++
+       if (AR_SREV_9300(ah))
+               return !ath9k_hw_detect_mac_hang(ah);
diff --git a/package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch b/package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch
new file mode 100644 (file)
index 0000000..347d06e
--- /dev/null
@@ -0,0 +1,100 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 25 Jan 2017 13:00:58 +0100
+Subject: [PATCH] ath9k: check for deaf rx path state
+
+Various chips occasionally run into a state where the tx path still
+appears to be working normally, but the rx path is deaf.
+
+There is no known register signature to check for this state explicitly,
+so use the lack of rx interrupts as an indicator.
+
+This detection is prone to false positives, since a device could also
+simply be in an environment where there are no frames on the air.
+However, in this case doing a reset should be harmless since it's
+obviously not interrupting any real activity. To avoid confusion, call
+the reset counters in this case "Rx path inactive" instead of something
+like "Rx path deaf", since it may not be an indication of a real
+hardware failure.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -1027,6 +1027,7 @@ struct ath_softc {
+       u8 gtt_cnt;
+       u32 intrstatus;
++      u32 rx_active;
+       u16 ps_flags; /* PS_* */
+       bool ps_enabled;
+       bool ps_idle;
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -763,6 +763,7 @@ static int read_file_reset(struct seq_fi
+               [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
+               [RESET_TYPE_MCI] = "MCI Reset",
+               [RESET_TYPE_CALIBRATION] = "Calibration error",
++              [RESET_TYPE_RX_INACTIVE] = "Rx path inactive",
+               [RESET_TX_DMA_ERROR] = "Tx DMA stop error",
+               [RESET_RX_DMA_ERROR] = "Rx DMA stop error",
+       };
+--- a/drivers/net/wireless/ath/ath9k/debug.h
++++ b/drivers/net/wireless/ath/ath9k/debug.h
+@@ -50,6 +50,7 @@ enum ath_reset_type {
+       RESET_TYPE_BEACON_STUCK,
+       RESET_TYPE_MCI,
+       RESET_TYPE_CALIBRATION,
++      RESET_TYPE_RX_INACTIVE,
+       RESET_TX_DMA_ERROR,
+       RESET_RX_DMA_ERROR,
+       __RESET_TYPE_MAX
+--- a/drivers/net/wireless/ath/ath9k/link.c
++++ b/drivers/net/wireless/ath/ath9k/link.c
+@@ -53,13 +53,27 @@ reset:
+ }
++static bool ath_rx_active_check(struct ath_softc *sc)
++{
++      if (sc->rx_active) {
++              sc->rx_active = 0;
++              return true;
++      }
++
++      ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
++              "rx path inactive, resetting the chip\n");
++      ath9k_queue_reset(sc, RESET_TYPE_RX_INACTIVE);
++      return false;
++}
++
+ void ath_hw_check_work(struct work_struct *work)
+ {
+       struct ath_softc *sc = container_of(work, struct ath_softc,
+                                           hw_check_work.work);
+       if (!ath_hw_check(sc) ||
+-          !ath_tx_complete_check(sc))
++          !ath_tx_complete_check(sc) ||
++          !ath_rx_active_check(sc))
+               return;
+       ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -269,6 +269,7 @@ static bool ath_complete_reset(struct at
+       }
+       sc->gtt_cnt = 0;
++      sc->rx_active = 1;
+       ath9k_hw_set_interrupts(ah);
+       ath9k_hw_enable_interrupts(ah);
+@@ -452,6 +453,7 @@ void ath9k_tasklet(unsigned long data)
+                       ath_rx_tasklet(sc, 0, true);
+               ath_rx_tasklet(sc, 0, false);
++              sc->rx_active = 1;
+       }
+       if (status & ATH9K_INT_TX) {
diff --git a/package/kernel/mac80211/patches/357-ath9k-fix-race-condition-in-enabling-disabling-IRQs.patch b/package/kernel/mac80211/patches/357-ath9k-fix-race-condition-in-enabling-disabling-IRQs.patch
new file mode 100644 (file)
index 0000000..962a08a
--- /dev/null
@@ -0,0 +1,165 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 25 Jan 2017 15:10:37 +0100
+Subject: [PATCH] ath9k: fix race condition in enabling/disabling IRQs
+
+The code currently relies on refcounting to disable IRQs from within the
+IRQ handler and re-enabling them again after the tasklet has run.
+
+However, due to race conditions sometimes the IRQ handler might be
+called twice, or the tasklet may not run at all (if interrupted in the
+middle of a reset).
+
+This can cause nasty imbalances in the irq-disable refcount which will
+get the driver permanently stuck until the entire radio has been stopped
+and started again (ath_reset will not recover from this).
+
+Instead of using this fragile logic, change the code to ensure that
+running the irq handler during tasklet processing is safe, and leave the
+refcount untouched.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -998,6 +998,7 @@ struct ath_softc {
+       struct survey_info *cur_survey;
+       struct survey_info survey[ATH9K_NUM_CHANNELS];
++      spinlock_t intr_lock;
+       struct tasklet_struct intr_tq;
+       struct tasklet_struct bcon_tasklet;
+       struct ath_hw *sc_ah;
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -669,6 +669,7 @@ static int ath9k_init_softc(u16 devid, s
+               common->bt_ant_diversity = 1;
+       spin_lock_init(&common->cc_lock);
++      spin_lock_init(&sc->intr_lock);
+       spin_lock_init(&sc->sc_serial_rw);
+       spin_lock_init(&sc->sc_pm_lock);
+       spin_lock_init(&sc->chan_lock);
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -810,21 +810,12 @@ void ath9k_hw_disable_interrupts(struct
+ }
+ EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
+-void ath9k_hw_enable_interrupts(struct ath_hw *ah)
++static void __ath9k_hw_enable_interrupts(struct ath_hw *ah)
+ {
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 sync_default = AR_INTR_SYNC_DEFAULT;
+       u32 async_mask;
+-      if (!(ah->imask & ATH9K_INT_GLOBAL))
+-              return;
+-
+-      if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
+-              ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
+-                      atomic_read(&ah->intr_ref_cnt));
+-              return;
+-      }
+-
+       if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+           AR_SREV_9561(ah))
+               sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
+@@ -846,6 +837,39 @@ void ath9k_hw_enable_interrupts(struct a
+       ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
+               REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
+ }
++
++void ath9k_hw_resume_interrupts(struct ath_hw *ah)
++{
++      struct ath_common *common = ath9k_hw_common(ah);
++
++      if (!(ah->imask & ATH9K_INT_GLOBAL))
++              return;
++
++      if (atomic_read(&ah->intr_ref_cnt) != 0) {
++              ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
++                      atomic_read(&ah->intr_ref_cnt));
++              return;
++      }
++
++      __ath9k_hw_enable_interrupts(ah);
++}
++EXPORT_SYMBOL(ath9k_hw_resume_interrupts);
++
++void ath9k_hw_enable_interrupts(struct ath_hw *ah)
++{
++      struct ath_common *common = ath9k_hw_common(ah);
++
++      if (!(ah->imask & ATH9K_INT_GLOBAL))
++              return;
++
++      if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
++              ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
++                      atomic_read(&ah->intr_ref_cnt));
++              return;
++      }
++
++      __ath9k_hw_enable_interrupts(ah);
++}
+ EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
+ void ath9k_hw_set_interrupts(struct ath_hw *ah)
+--- a/drivers/net/wireless/ath/ath9k/mac.h
++++ b/drivers/net/wireless/ath/ath9k/mac.h
+@@ -744,6 +744,7 @@ void ath9k_hw_set_interrupts(struct ath_
+ void ath9k_hw_enable_interrupts(struct ath_hw *ah);
+ void ath9k_hw_disable_interrupts(struct ath_hw *ah);
+ void ath9k_hw_kill_interrupts(struct ath_hw *ah);
++void ath9k_hw_resume_interrupts(struct ath_hw *ah);
+ void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -375,9 +375,14 @@ void ath9k_tasklet(unsigned long data)
+       struct ath_common *common = ath9k_hw_common(ah);
+       enum ath_reset_type type;
+       unsigned long flags;
+-      u32 status = sc->intrstatus;
++      u32 status;
+       u32 rxmask;
++      spin_lock_irqsave(&sc->intr_lock, flags);
++      status = sc->intrstatus;
++      sc->intrstatus = 0;
++      spin_unlock_irqrestore(&sc->intr_lock, flags);
++
+       ath9k_ps_wakeup(sc);
+       spin_lock(&sc->sc_pcu_lock);
+@@ -480,7 +485,7 @@ void ath9k_tasklet(unsigned long data)
+       ath9k_btcoex_handle_interrupt(sc, status);
+       /* re-enable hardware interrupt */
+-      ath9k_hw_enable_interrupts(ah);
++      ath9k_hw_resume_interrupts(ah);
+ out:
+       spin_unlock(&sc->sc_pcu_lock);
+       ath9k_ps_restore(sc);
+@@ -544,7 +549,9 @@ irqreturn_t ath_isr(int irq, void *dev)
+               return IRQ_NONE;
+       /* Cache the status */
+-      sc->intrstatus = status;
++      spin_lock(&sc->intr_lock);
++      sc->intrstatus |= status;
++      spin_unlock(&sc->intr_lock);
+       if (status & SCHED_INTR)
+               sched = true;
+@@ -590,7 +597,7 @@ chip_reset:
+       if (sched) {
+               /* turn off every interrupt */
+-              ath9k_hw_disable_interrupts(ah);
++              ath9k_hw_kill_interrupts(ah);
+               tasklet_schedule(&sc->intr_tq);
+       }
index f15c451..1d3e4be 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -775,6 +775,7 @@ static const struct ieee80211_iface_limi
+@@ -777,6 +777,7 @@ static const struct ieee80211_iface_limi
                                 BIT(NL80211_IFTYPE_AP) },
        { .max = 1,     .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
                                 BIT(NL80211_IFTYPE_P2P_GO) },
index f21eed1..7352343 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1315,6 +1315,53 @@ void ath9k_deinit_debug(struct ath_softc
+@@ -1316,6 +1316,53 @@ void ath9k_deinit_debug(struct ath_softc
        ath9k_cmn_spectral_deinit_debug(&sc->spec_priv);
  }
  
@@ -54,7 +54,7 @@
  int ath9k_init_debug(struct ath_hw *ah)
  {
        struct ath_common *common = ath9k_hw_common(ah);
-@@ -1334,6 +1381,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1335,6 +1382,8 @@ int ath9k_init_debug(struct ath_hw *ah)
        ath9k_tx99_init_debug(sc);
        ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy);
  
index 5c357cf..59bc5fc 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -1078,23 +1078,23 @@ static int __init ath9k_init(void)
+@@ -1080,23 +1080,23 @@ static int __init ath9k_init(void)
  {
        int error;
  
index c98072b..d6eb5f1 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1362,6 +1362,52 @@ static const struct file_operations fops
+@@ -1363,6 +1363,52 @@ static const struct file_operations fops
        .owner = THIS_MODULE
  };
  
@@ -53,7 +53,7 @@
  int ath9k_init_debug(struct ath_hw *ah)
  {
        struct ath_common *common = ath9k_hw_common(ah);
-@@ -1383,6 +1429,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1384,6 +1430,8 @@ int ath9k_init_debug(struct ath_hw *ah)
  
        debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_eeprom);
index bbef79d..061288d 100644 (file)
@@ -24,7 +24,7 @@
  struct ath_softc {
        struct ieee80211_hw *hw;
        struct device *dev;
-@@ -1045,9 +1055,8 @@ struct ath_softc {
+@@ -1047,9 +1057,8 @@ struct ath_softc {
        spinlock_t chan_lock;
  
  #ifdef CPTCFG_MAC80211_LEDS
 +                    GFP_KERNEL);
 +      if (!led)
 +              return -ENOMEM;
-+
+-      ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val);
 +      led->gpio = gpio = (struct gpio_led *) (led + 1);
 +      _name = (char *) (led->gpio + 1);
 +
 +      ret = ath_add_led(sc, led);
 +      if (unlikely(ret < 0))
 +              kfree(led);
--      ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val);
++
 +      return ret;
  }
  
  {
 -      if (!sc->led_registered)
 -              return;
-+      struct ath_led *led;
+-
 -      ath_led_brightness(&sc->led_cdev, LED_OFF);
 -      led_classdev_unregister(&sc->led_cdev);
--
++      struct ath_led *led;
 -      ath9k_hw_gpio_free(sc->sc_ah, sc->sc_ah->led_pin);
 +      while (!list_empty(&sc->leds)) {
 +              led = list_first_entry(&sc->leds, struct ath_led, list);
  
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -990,7 +990,7 @@ int ath9k_init_device(u16 devid, struct
+@@ -992,7 +992,7 @@ int ath9k_init_device(u16 devid, struct
  
  #ifdef CPTCFG_MAC80211_LEDS
        /* must be initialized before ieee80211_register_hw */
  #endif
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1407,6 +1407,61 @@ static const struct file_operations fops
+@@ -1408,6 +1408,61 @@ static const struct file_operations fops
        .llseek = default_llseek,
  };
  
  
  int ath9k_init_debug(struct ath_hw *ah)
  {
-@@ -1431,6 +1486,10 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1432,6 +1487,10 @@ int ath9k_init_debug(struct ath_hw *ah)
                            &fops_eeprom);
        debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
                            sc, &fops_chanbw);
index 08acc0e..ea73e6a 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1463,6 +1463,50 @@ static const struct file_operations fops
+@@ -1464,6 +1464,50 @@ static const struct file_operations fops
  #endif
  
  
@@ -51,7 +51,7 @@
  int ath9k_init_debug(struct ath_hw *ah)
  {
        struct ath_common *common = ath9k_hw_common(ah);
-@@ -1490,6 +1534,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1491,6 +1535,8 @@ int ath9k_init_debug(struct ath_hw *ah)
        debugfs_create_file("gpio_led", S_IWUSR,
                           sc->debug.debugfs_phy, sc, &fops_gpio_led);
  #endif
@@ -94,7 +94,7 @@
  struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
 --- a/drivers/net/wireless/ath/ath9k/hw.c
 +++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1838,6 +1838,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
+@@ -1842,6 +1842,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
  }
  EXPORT_SYMBOL(ath9k_hw_get_tsf_offset);
  
  int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                   struct ath9k_hw_cal_data *caldata, bool fastcc)
  {
-@@ -2046,6 +2060,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+@@ -2050,6 +2064,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
                ar9003_hw_disable_phy_restart(ah);
  
        ath9k_hw_apply_gpio_override(ah);
                REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -533,6 +533,11 @@ irqreturn_t ath_isr(int irq, void *dev)
+@@ -541,6 +541,11 @@ irqreturn_t ath_isr(int irq, void *dev)
        if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
                return IRQ_HANDLED;
  
index 7782479..bca23d3 100644 (file)
@@ -55,7 +55,7 @@
        ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
 --- a/drivers/net/wireless/ath/ath9k/init.c
 +++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -763,7 +763,8 @@ static void ath9k_init_txpower_limits(st
+@@ -765,7 +765,8 @@ static void ath9k_init_txpower_limits(st
        if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
                ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ);
  
@@ -65,7 +65,7 @@
  }
  
  static const struct ieee80211_iface_limit if_limits[] = {
-@@ -950,6 +951,18 @@ static void ath9k_set_hw_capab(struct at
+@@ -952,6 +953,18 @@ static void ath9k_set_hw_capab(struct at
        SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
  }
  
@@ -84,7 +84,7 @@
  int ath9k_init_device(u16 devid, struct ath_softc *sc,
                    const struct ath_bus_ops *bus_ops)
  {
-@@ -995,6 +1008,8 @@ int ath9k_init_device(u16 devid, struct
+@@ -997,6 +1010,8 @@ int ath9k_init_device(u16 devid, struct
                ARRAY_SIZE(ath9k_tpt_blink));
  #endif
  
index 200a3a2..680bb6d 100644 (file)
@@ -40,7 +40,7 @@
        return true;
  }
  
-@@ -1816,8 +1835,14 @@ static int ath9k_hw_do_fastcc(struct ath
+@@ -1820,8 +1839,14 @@ static int ath9k_hw_do_fastcc(struct ath
        if (AR_SREV_9271(ah))
                ar9002_hw_load_ani_reg(ah, chan);
  
@@ -55,7 +55,7 @@
        return -EINVAL;
  }
  
-@@ -2071,6 +2096,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+@@ -2075,6 +2100,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
                ath9k_hw_set_radar_params(ah);
        }
  
index 666622d..0b9b7f3 100644 (file)
@@ -33,7 +33,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  struct ath_softc {
        struct ieee80211_hw *hw;
        struct device *dev;
-@@ -1057,6 +1066,9 @@ struct ath_softc {
+@@ -1059,6 +1068,9 @@ struct ath_softc {
  #ifdef CPTCFG_MAC80211_LEDS
        const char *led_default_trigger;
        struct list_head leds;
index b8dd263..0a26699 100644 (file)
@@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 ---
 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -1068,6 +1068,7 @@ struct ath_softc {
+@@ -1070,6 +1070,7 @@ struct ath_softc {
        struct list_head leds;
  #ifdef CONFIG_GPIOLIB
        struct ath9k_gpio_chip *gpiochip;
index 04714f8..292ea8a 100644 (file)
@@ -349,16 +349,6 @@ Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
 -
 -              integer = swab32(eep->modalHeader.antCtrlCommon);
 -              eep->modalHeader.antCtrlCommon = integer;
--
--              for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
--                      integer = swab32(eep->modalHeader.antCtrlChain[i]);
--                      eep->modalHeader.antCtrlChain[i] = integer;
--              }
--
--              for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
--                      word = swab16(eep->modalHeader.spurChans[i].spurChan);
--                      eep->modalHeader.spurChans[i].spurChan = word;
--              }
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.length);
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum);
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.version);
@@ -368,10 +358,18 @@ Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions);
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap);
 +              EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlCommon);
-+
+-              for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
+-                      integer = swab32(eep->modalHeader.antCtrlChain[i]);
+-                      eep->modalHeader.antCtrlChain[i] = integer;
+-              }
 +              for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++)
 +                      EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlChain[i]);
-+
+-              for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+-                      word = swab16(eep->modalHeader.spurChans[i].spurChan);
+-                      eep->modalHeader.spurChans[i].spurChan = word;
+-              }
 +              for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++)
 +                      EEPROM_FIELD_SWAB16(
 +                              eep->modalHeader.spurChans[i].spurChan);
@@ -542,16 +540,6 @@ Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
 -
 -              integer = swab32(eep->modalHeader.antCtrlCommon);
 -              eep->modalHeader.antCtrlCommon = integer;
--
--              for (i = 0; i < AR9287_MAX_CHAINS; i++) {
--                      integer = swab32(eep->modalHeader.antCtrlChain[i]);
--                      eep->modalHeader.antCtrlChain[i] = integer;
--              }
--
--              for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
--                      word = swab16(eep->modalHeader.spurChans[i].spurChan);
--                      eep->modalHeader.spurChans[i].spurChan = word;
--              }
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.length);
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum);
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.version);
@@ -561,10 +549,18 @@ Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions);
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap);
 +              EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlCommon);
-+
+-              for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+-                      integer = swab32(eep->modalHeader.antCtrlChain[i]);
+-                      eep->modalHeader.antCtrlChain[i] = integer;
+-              }
 +              for (i = 0; i < AR9287_MAX_CHAINS; i++)
 +                      EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlChain[i]);
-+
+-              for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+-                      word = swab16(eep->modalHeader.spurChans[i].spurChan);
+-                      eep->modalHeader.spurChans[i].spurChan = word;
+-              }
 +              for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++)
 +                      EEPROM_FIELD_SWAB16(
 +                              eep->modalHeader.spurChans[i].spurChan);
@@ -716,8 +712,7 @@ Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
        if (need_swap) {
 -              u32 integer, j;
 -              u16 word;
-+              u32 j;
+-
 -              word = swab16(eep->baseEepHeader.length);
 -              eep->baseEepHeader.length = word;
 -
@@ -738,7 +733,8 @@ Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
 -
 -              word = swab16(eep->baseEepHeader.blueToothOptions);
 -              eep->baseEepHeader.blueToothOptions = word;
--
++              u32 j;
 -              word = swab16(eep->baseEepHeader.deviceCap);
 -              eep->baseEepHeader.deviceCap = word;
 +              EEPROM_FIELD_SWAB16(eep->baseEepHeader.length);
index 7237492..51fe1bd 100644 (file)
  
  u8 ath9k_parse_mpdudensity(u8 mpdudensity)
  {
-@@ -652,6 +654,7 @@ void ath_reset_work(struct work_struct *
+@@ -662,6 +664,7 @@ void ath_reset_work(struct work_struct *
  static int ath9k_start(struct ieee80211_hw *hw)
  {
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
-@@ -730,6 +733,11 @@ static int ath9k_start(struct ieee80211_
+@@ -740,6 +743,11 @@ static int ath9k_start(struct ieee80211_
                                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
        }