From: Felix Fietkau Date: Wed, 25 Jan 2017 14:32:18 +0000 (+0100) Subject: ath9k: add stability fixes for long standing hang issues (FS#13, #34, #373, #383) X-Git-Tag: v18.06.0-rc1~3963 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=b94177e10fc72f9309eae7459c3570e5c080e960;p=oweals%2Fopenwrt.git 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 --- 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 +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 +--- + +--- 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 +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 +--- + +--- 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 +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 +--- + +--- 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 +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 +--- + +--- 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 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 --- --- 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 - - 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 + 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 - - 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 + 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 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 - - 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); }