aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2017-01-25 15:32:18 +0100
committerFelix Fietkau <nbd@nbd.name>2017-01-25 16:25:48 +0100
commitb94177e10fc72f9309eae7459c3570e5c080e960 (patch)
tree26efa9c6172b394c2113926cfa7b6aad6c9ebc1f /package/kernel/mac80211/patches
parent4cacc1c5f5e01594d4e9148a7b34946845424e24 (diff)
downloadupstream-b94177e10fc72f9309eae7459c3570e5c080e960.tar.gz
upstream-b94177e10fc72f9309eae7459c3570e5c080e960.tar.bz2
upstream-b94177e10fc72f9309eae7459c3570e5c080e960.zip
ath9k: add stability fixes for long standing hang issues (FS#13, #34, #373, #383)
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>
Diffstat (limited to 'package/kernel/mac80211/patches')
-rw-r--r--package/kernel/mac80211/patches/354-ath9k-rename-tx_complete_work-to-hw_check_work.patch175
-rw-r--r--package/kernel/mac80211/patches/355-ath9k_hw-check-if-the-chip-failed-to-wake-up.patch30
-rw-r--r--package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch100
-rw-r--r--package/kernel/mac80211/patches/357-ath9k-fix-race-condition-in-enabling-disabling-IRQs.patch165
-rw-r--r--package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch2
-rw-r--r--package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch4
-rw-r--r--package/kernel/mac80211/patches/501-ath9k_ahb_init.patch2
-rw-r--r--package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch4
-rw-r--r--package/kernel/mac80211/patches/530-ath9k_extra_leds.patch20
-rw-r--r--package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch10
-rw-r--r--package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch6
-rw-r--r--package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch4
-rw-r--r--package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch2
-rw-r--r--package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch2
-rw-r--r--package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch50
-rw-r--r--package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch4
16 files changed, 523 insertions, 57 deletions
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
index 0000000000..31a0277e1c
--- /dev/null
+++ b/package/kernel/mac80211/patches/354-ath9k-rename-tx_complete_work-to-hw_check_work.patch
@@ -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
index 0000000000..b0cb74ad05
--- /dev/null
+++ b/package/kernel/mac80211/patches/355-ath9k_hw-check-if-the-chip-failed-to-wake-up.patch
@@ -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
index 0000000000..347d06ec88
--- /dev/null
+++ b/package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch
@@ -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
index 0000000000..962a08ae36
--- /dev/null
+++ b/package/kernel/mac80211/patches/357-ath9k-fix-race-condition-in-enabling-disabling-IRQs.patch
@@ -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);
+ }
+
diff --git a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
index f15c451e50..1d3e4bea13 100644
--- a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
+++ b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
@@ -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) },
diff --git a/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch b/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
index f21eed18c3..73523437d7 100644
--- a/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
+++ b/package/kernel/mac80211/patches/500-ath9k_eeprom_debugfs.patch
@@ -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);
diff --git a/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
index 5c357cfcda..59bc5fc577 100644
--- a/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
+++ b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch
@@ -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;
diff --git a/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
index c98072bac9..d6eb5f1d24 100644
--- a/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
+++ b/package/kernel/mac80211/patches/512-ath9k_channelbw_debugfs.patch
@@ -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);
diff --git a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
index bbef79d9f6..061288dd87 100644
--- a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
+++ b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch
@@ -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
@@ -103,7 +103,8 @@
+ 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);
+
@@ -116,8 +117,7 @@
+ 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;
}
@@ -125,11 +125,11 @@
{
- 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);
@@ -181,7 +181,7 @@
--- 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 */
@@ -192,7 +192,7 @@
#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,
};
@@ -254,7 +254,7 @@
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);
diff --git a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
index 08acc0e0c9..ea73e6a000 100644
--- a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
+++ b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
@@ -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);
@@ -115,7 +115,7 @@
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);
@@ -125,7 +125,7 @@
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;
diff --git a/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
index 77824795d6..bca23d3d3d 100644
--- a/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
+++ b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch
@@ -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
diff --git a/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch b/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
index 200a3a28f6..680bb6d590 100644
--- a/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
+++ b/package/kernel/mac80211/patches/544-ath9k-ar933x-usb-hang-workaround.patch
@@ -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);
}
diff --git a/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
index 666622d416..0b9b7f3db0 100644
--- a/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
+++ b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch
@@ -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;
diff --git a/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
index b8dd2639f8..0a266999e0 100644
--- a/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
+++ b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch
@@ -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;
diff --git a/package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch b/package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch
index 04714f8169..292ea8a558 100644
--- a/package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch
+++ b/package/kernel/mac80211/patches/556-ath9k-define-all-EEPROM-fields-in-Little-Endian-form.patch
@@ -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);
diff --git a/package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch b/package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch
index 723749259c..51fe1bd6cc 100644
--- a/package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch
+++ b/package/kernel/mac80211/patches/560-ath9k_ubnt_uap_plus_hsr.patch
@@ -343,7 +343,7 @@
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;
@@ -351,7 +351,7 @@
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);
}