diff options
Diffstat (limited to 'package/kernel/mac80211/patches/ath')
60 files changed, 4860 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/ath/070-ath_common_config.patch b/package/kernel/mac80211/patches/ath/070-ath_common_config.patch new file mode 100644 index 0000000000..41774fe53e --- /dev/null +++ b/package/kernel/mac80211/patches/ath/070-ath_common_config.patch @@ -0,0 +1,9 @@ +--- a/drivers/net/wireless/ath/Kconfig ++++ b/drivers/net/wireless/ath/Kconfig +@@ -1,5 +1,5 @@ + config ATH_COMMON +- tristate ++ tristate "ath.ko" + depends on m + + config WLAN_VENDOR_ATH diff --git a/package/kernel/mac80211/patches/ath/080-ath10k_thermal_config.patch b/package/kernel/mac80211/patches/ath/080-ath10k_thermal_config.patch new file mode 100644 index 0000000000..f008a795d8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/080-ath10k_thermal_config.patch @@ -0,0 +1,55 @@ +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/Kconfig +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/Kconfig ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/Kconfig +@@ -85,6 +85,12 @@ config ATH10K_TRACING + ---help--- + Select this to ath10k use tracing infrastructure. + ++config ATH10K_THERMAL ++ bool "Atheros ath10k thermal monitoring support" ++ depends on THERMAL ++ ---help--- ++ Select this to ath10k use hwmon for thermal measurement. ++ + config ATH10K_DFS_CERTIFIED + bool "Atheros DFS support for certified platforms" + depends on ATH10K && CFG80211_CERTIFICATION_ONUS +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/Makefile +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/Makefile ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/Makefile +@@ -18,7 +18,7 @@ ath10k_core-y += mac.o \ + ath10k_core-$(CPTCFG_ATH10K_SPECTRAL) += spectral.o + ath10k_core-$(CPTCFG_NL80211_TESTMODE) += testmode.o + ath10k_core-$(CPTCFG_ATH10K_TRACING) += trace.o +-ath10k_core-$(CONFIG_THERMAL) += thermal.o ++ath10k_core-$(CPTCFG_ATH10K_THERMAL) += thermal.o + ath10k_core-$(CPTCFG_MAC80211_DEBUGFS) += debugfs_sta.o + ath10k_core-$(CONFIG_PM) += wow.o + ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/thermal.h +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/thermal.h ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/thermal.h +@@ -36,7 +36,7 @@ struct ath10k_thermal { + int temperature; + }; + +-#if IS_REACHABLE(CONFIG_THERMAL) ++#if IS_REACHABLE(CPTCFG_ATH10K_THERMAL) + int ath10k_thermal_register(struct ath10k *ar); + void ath10k_thermal_unregister(struct ath10k *ar); + void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature); +Index: backports-v4.18-rc7/local-symbols +=================================================================== +--- backports-v4.18-rc7.orig/local-symbols ++++ backports-v4.18-rc7/local-symbols +@@ -144,6 +144,7 @@ ATH10K_SNOC= + ATH10K_DEBUG= + ATH10K_DEBUGFS= + ATH10K_SPECTRAL= ++ATH10K_THERMAL= + ATH10K_TRACING= + ATH10K_DFS_CERTIFIED= + WCN36XX= diff --git a/package/kernel/mac80211/patches/ath/201-ath5k-WAR-for-AR71xx-PCI-bug.patch b/package/kernel/mac80211/patches/ath/201-ath5k-WAR-for-AR71xx-PCI-bug.patch new file mode 100644 index 0000000000..21516ffde9 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/201-ath5k-WAR-for-AR71xx-PCI-bug.patch @@ -0,0 +1,38 @@ +--- a/drivers/net/wireless/ath/ath5k/initvals.c ++++ b/drivers/net/wireless/ath/ath5k/initvals.c +@@ -62,8 +62,14 @@ static const struct ath5k_ini ar5210_ini + { AR5K_IMR, 0 }, + { AR5K_IER, AR5K_IER_DISABLE }, + { AR5K_BSR, 0, AR5K_INI_READ }, ++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79) + { AR5K_TXCFG, AR5K_DMASIZE_128B }, + { AR5K_RXCFG, AR5K_DMASIZE_128B }, ++#else ++ /* WAR for AR71xx PCI bug */ ++ { AR5K_TXCFG, AR5K_DMASIZE_128B }, ++ { AR5K_RXCFG, AR5K_DMASIZE_4B }, ++#endif + { AR5K_CFG, AR5K_INIT_CFG }, + { AR5K_TOPS, 8 }, + { AR5K_RXNOFRM, 8 }, +--- a/drivers/net/wireless/ath/ath5k/dma.c ++++ b/drivers/net/wireless/ath/ath5k/dma.c +@@ -869,10 +869,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah) + * guess we can tweak it and see how it goes ;-) + */ + if (ah->ah_version != AR5K_AR5210) { ++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79) + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B); + AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, + AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B); ++#else ++ /* WAR for AR71xx PCI bug */ ++ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, ++ AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B); ++ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, ++ AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_4B); ++#endif + } + + /* Pre-enable interrupts on 5211/5212*/ diff --git a/package/kernel/mac80211/patches/ath/350-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch b/package/kernel/mac80211/patches/ath/350-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch new file mode 100644 index 0000000000..a7bcfa549b --- /dev/null +++ b/package/kernel/mac80211/patches/ath/350-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch @@ -0,0 +1,25 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Sat, 9 Jul 2016 15:25:24 +0200 +Subject: [PATCH] ath9k_hw: reset AHB-WMAC interface on AR91xx + +Should fix a few stability issues + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1394,8 +1394,12 @@ static bool ath9k_hw_set_reset(struct at + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, 0); + +- if (AR_SREV_9100(ah)) ++ if (AR_SREV_9100(ah)) { ++ /* Reset the AHB-WMAC interface */ ++ if (ah->external_reset) ++ ah->external_reset(); + udelay(50); ++ } + + return true; + } diff --git a/package/kernel/mac80211/patches/ath/351-ath9k_hw-issue-external-reset-for-QCA955x.patch b/package/kernel/mac80211/patches/ath/351-ath9k_hw-issue-external-reset-for-QCA955x.patch new file mode 100644 index 0000000000..5eb69b898d --- /dev/null +++ b/package/kernel/mac80211/patches/ath/351-ath9k_hw-issue-external-reset-for-QCA955x.patch @@ -0,0 +1,129 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Sat, 9 Jul 2016 15:26:44 +0200 +Subject: [PATCH] ath9k_hw: issue external reset for QCA955x + +The RTC interface on the SoC needs to be reset along with the rest of +the WMAC. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1271,39 +1271,56 @@ void ath9k_hw_get_delta_slope_vals(struc + *coef_exponent = coef_exp - 16; + } + +-/* AR9330 WAR: +- * call external reset function to reset WMAC if: +- * - doing a cold reset +- * - we have pending frames in the TX queues. +- */ +-static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type) ++static bool ath9k_hw_need_external_reset(struct ath_hw *ah, int type) + { +- int i, npend = 0; ++ int i; + +- for (i = 0; i < AR_NUM_QCU; i++) { +- npend = ath9k_hw_numtxpending(ah, i); +- if (npend) +- break; +- } +- +- if (ah->external_reset && +- (npend || type == ATH9K_RESET_COLD)) { +- int reset_err = 0; +- +- ath_dbg(ath9k_hw_common(ah), RESET, +- "reset MAC via external reset\n"); +- +- reset_err = ah->external_reset(); +- if (reset_err) { +- ath_err(ath9k_hw_common(ah), +- "External reset failed, err=%d\n", +- reset_err); +- return false; ++ if (type == ATH9K_RESET_COLD) ++ return true; ++ ++ if (AR_SREV_9550(ah)) ++ return true; ++ ++ /* AR9330 WAR: ++ * call external reset function to reset WMAC if: ++ * - doing a cold reset ++ * - we have pending frames in the TX queues. ++ */ ++ if (AR_SREV_9330(ah)) { ++ for (i = 0; i < AR_NUM_QCU; i++) { ++ if (ath9k_hw_numtxpending(ah, i)) ++ return true; + } ++ } ++ ++ return false; ++} ++ ++static bool ath9k_hw_external_reset(struct ath_hw *ah, int type) ++{ ++ int err; ++ ++ if (!ah->external_reset || !ath9k_hw_need_external_reset(ah, type)) ++ return true; ++ ++ ath_dbg(ath9k_hw_common(ah), RESET, ++ "reset MAC via external reset\n"); + +- REG_WRITE(ah, AR_RTC_RESET, 1); ++ err = ah->external_reset(); ++ if (err) { ++ ath_err(ath9k_hw_common(ah), ++ "External reset failed, err=%d\n", err); ++ return false; + } + ++ if (AR_SREV_9550(ah)) { ++ REG_WRITE(ah, AR_RTC_RESET, 0); ++ udelay(10); ++ } ++ ++ REG_WRITE(ah, AR_RTC_RESET, 1); ++ udelay(10); ++ + return true; + } + +@@ -1356,24 +1373,24 @@ static bool ath9k_hw_set_reset(struct at + rst_flags |= AR_RTC_RC_MAC_COLD; + } + +- if (AR_SREV_9330(ah)) { +- if (!ath9k_hw_ar9330_reset_war(ah, type)) +- return false; +- } +- + if (ath9k_hw_mci_is_enabled(ah)) + ar9003_mci_check_gpm_offset(ah); + + /* DMA HALT added to resolve ar9300 and ar9580 bus error during +- * RTC_RC reg read ++ * RTC_RC reg read. Also needed for AR9550 external reset + */ +- if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) { ++ if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) { + REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); + ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK, + 20 * AH_WAIT_TIMEOUT); +- REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); + } + ++ if (!AR_SREV_9100(ah)) ++ ath9k_hw_external_reset(ah, type); ++ ++ if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) ++ REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); ++ + REG_WRITE(ah, AR_RTC_RC, rst_flags); + + REGWRITE_BUFFER_FLUSH(ah); diff --git a/package/kernel/mac80211/patches/ath/352-ath9k_hw-set-spectral-scan-enable-bit-on-trigger-for.patch b/package/kernel/mac80211/patches/ath/352-ath9k_hw-set-spectral-scan-enable-bit-on-trigger-for.patch new file mode 100644 index 0000000000..dfe9aae268 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/352-ath9k_hw-set-spectral-scan-enable-bit-on-trigger-for.patch @@ -0,0 +1,21 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Mon, 11 Jul 2016 12:07:40 +0200 +Subject: [PATCH] ath9k_hw: set spectral scan enable bit on trigger for + AR9003+ + +AR9002 code and QCA AR9003+ code do the same. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -1800,6 +1800,8 @@ static void ar9003_hw_spectral_scan_conf + + static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah) + { ++ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, ++ AR_PHY_SPECTRAL_SCAN_ENABLE); + /* Activate spectral scan */ + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_ACTIVE); diff --git a/package/kernel/mac80211/patches/ath/353-ath9k-don-t-run-periodic-and-nf-calibation-at-the-sa.patch b/package/kernel/mac80211/patches/ath/353-ath9k-don-t-run-periodic-and-nf-calibation-at-the-sa.patch new file mode 100644 index 0000000000..22f5154146 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/353-ath9k-don-t-run-periodic-and-nf-calibation-at-the-sa.patch @@ -0,0 +1,27 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Tue, 27 Dec 2016 23:16:23 +0100 +Subject: [PATCH] ath9k: don't run periodic and nf calibation at the same + time + +The checks already prevents periodic cal from being started while noise +floor calibration runs. It is missing checks for the other way around. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c ++++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c +@@ -676,10 +676,10 @@ static int ar9002_hw_calibrate(struct at + return 0; + + ah->cal_list_curr = currCal = currCal->calNext; +- if (currCal->calState == CAL_WAITING) { ++ if (currCal->calState == CAL_WAITING) + ath9k_hw_reset_calibration(ah, currCal); +- return 0; +- } ++ ++ return 0; + } + + /* Do NF cal only at longer intervals */ diff --git a/package/kernel/mac80211/patches/ath/354-ath9k-force-rx_clear-when-disabling-rx.patch b/package/kernel/mac80211/patches/ath/354-ath9k-force-rx_clear-when-disabling-rx.patch new file mode 100644 index 0000000000..8aaccf49b4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/354-ath9k-force-rx_clear-when-disabling-rx.patch @@ -0,0 +1,35 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Sun, 7 Jun 2015 13:53:35 +0200 +Subject: [PATCH] ath9k: force rx_clear when disabling rx + +This makes stopping Rx more reliable and should reduce the frequency of +Rx related DMA stop warnings. Don't use rx_clear in TX99 mode. + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau <nbd@nbd.name> +Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com> +--- + +--- a/drivers/net/wireless/ath/ath9k/mac.c ++++ b/drivers/net/wireless/ath/ath9k/mac.c +@@ -678,13 +678,18 @@ void ath9k_hw_startpcureceive(struct ath + + ath9k_ani_reset(ah, is_scanning); + +- REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); ++ REG_CLR_BIT(ah, AR_DIAG_SW, ++ AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR); + } + EXPORT_SYMBOL(ath9k_hw_startpcureceive); + + void ath9k_hw_abortpcurecv(struct ath_hw *ah) + { +- REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS); ++ u32 reg = AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT; ++ ++ if (!IS_ENABLED(CPTCFG_ATH9K_TX99)) ++ reg |= AR_DIAG_FORCE_RX_CLEAR; ++ REG_SET_BIT(ah, AR_DIAG_SW, reg); + + ath9k_hw_disable_mib_counters(ah); + } diff --git a/package/kernel/mac80211/patches/ath/356-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch b/package/kernel/mac80211/patches/ath/356-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch new file mode 100644 index 0000000000..35d07430eb --- /dev/null +++ b/package/kernel/mac80211/patches/ath/356-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch @@ -0,0 +1,37 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Sat, 14 May 2016 14:51:02 +0200 +Subject: [PATCH] Revert "ath9k: interpret requested txpower in EIRP + domain" + +This reverts commit 71f5137bf010c6faffab50c0ec15374c59c4a411. +--- + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -2935,7 +2935,8 @@ void ath9k_hw_apply_txpower(struct ath_h + { + struct ath_regulatory *reg = ath9k_hw_regulatory(ah); + struct ieee80211_channel *channel; +- int chan_pwr, new_pwr; ++ int chan_pwr, new_pwr, max_gain; ++ int ant_gain, ant_reduction = 0; + + if (!chan) + return; +@@ -2943,10 +2944,15 @@ void ath9k_hw_apply_txpower(struct ath_h + channel = chan->chan; + chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER); + new_pwr = min_t(int, chan_pwr, reg->power_limit); ++ max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2; ++ ++ ant_gain = get_antenna_gain(ah, chan); ++ if (ant_gain > max_gain) ++ ant_reduction = ant_gain - max_gain; + + ah->eep_ops->set_txpower(ah, chan, + ath9k_regd_get_ctl(reg, chan), +- get_antenna_gain(ah, chan), new_pwr, test); ++ ant_reduction, new_pwr, test); + } + + void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) diff --git a/package/kernel/mac80211/patches/ath/360-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch b/package/kernel/mac80211/patches/ath/360-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch new file mode 100644 index 0000000000..d651e6ce30 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/360-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch @@ -0,0 +1,50 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Sun, 28 Aug 2016 13:13:01 +0200 +Subject: [PATCH] ath9k: fix moredata bit in PS buffered frame release + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -1659,6 +1659,22 @@ void ath_tx_aggr_wakeup(struct ath_softc + } + } + ++ ++static void ++ath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val) ++{ ++ struct ieee80211_hdr *hdr; ++ u16 mask = cpu_to_le16(IEEE80211_FCTL_MOREDATA); ++ u16 mask_val = mask * val; ++ ++ hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; ++ if ((hdr->frame_control & mask) != mask_val) { ++ hdr->frame_control = (hdr->frame_control & ~mask) | mask_val; ++ dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, ++ sizeof(*hdr), DMA_TO_DEVICE); ++ } ++} ++ + void ath9k_release_buffered_frames(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u16 tids, int nframes, +@@ -1689,6 +1705,7 @@ void ath9k_release_buffered_frames(struc + if (!bf) + break; + ++ ath9k_set_moredata(sc, bf, true); + list_add_tail(&bf->list, &bf_q); + ath_set_rates(tid->an->vif, tid->an->sta, bf); + if (bf_isampdu(bf)) { +@@ -1712,6 +1729,9 @@ void ath9k_release_buffered_frames(struc + if (list_empty(&bf_q)) + return; + ++ if (!more_data) ++ ath9k_set_moredata(sc, bf_tail, false); ++ + info = IEEE80211_SKB_CB(bf_tail->bf_mpdu); + info->flags |= IEEE80211_TX_STATUS_EOSP; + diff --git a/package/kernel/mac80211/patches/ath/361-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch b/package/kernel/mac80211/patches/ath/361-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch new file mode 100644 index 0000000000..319de2a767 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/361-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Sun, 28 Aug 2016 13:13:42 +0200 +Subject: [PATCH] ath9k: clear potentially stale EOSP status bit in + intermediate queues + +Prevents spurious ieee80211_sta_eosp calls. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -969,7 +969,8 @@ ath_tx_get_tid_subframe(struct ath_softc + bf->bf_lastbf = bf; + + tx_info = IEEE80211_SKB_CB(skb); +- tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; ++ tx_info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | ++ IEEE80211_TX_STATUS_EOSP); + + /* + * No aggregation session is running, but there may be frames diff --git a/package/kernel/mac80211/patches/ath/362-ath9k-report-tx-status-on-EOSP.patch b/package/kernel/mac80211/patches/ath/362-ath9k-report-tx-status-on-EOSP.patch new file mode 100644 index 0000000000..80a3074a4d --- /dev/null +++ b/package/kernel/mac80211/patches/ath/362-ath9k-report-tx-status-on-EOSP.patch @@ -0,0 +1,19 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Sun, 28 Aug 2016 13:23:27 +0200 +Subject: [PATCH] ath9k: report tx status on EOSP + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -86,7 +86,8 @@ static void ath_tx_status(struct ieee802 + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->status.status_driver_data[0]; + +- if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { ++ if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | ++ IEEE80211_TX_STATUS_EOSP)) { + ieee80211_tx_status(hw, skb); + return; + } diff --git a/package/kernel/mac80211/patches/ath/363-ath9k-fix-block-ack-window-tracking-issues.patch b/package/kernel/mac80211/patches/ath/363-ath9k-fix-block-ack-window-tracking-issues.patch new file mode 100644 index 0000000000..e25e92dda9 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/363-ath9k-fix-block-ack-window-tracking-issues.patch @@ -0,0 +1,114 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Tue, 30 Aug 2016 12:44:08 +0200 +Subject: [PATCH] ath9k: fix block-ack window tracking issues + +Ensure that a buffer gets tracked as part of the block-ack window as +soon as it's dequeued from the tid for the first time. Ensure that +double calls to ath_tx_addto_baw (e.g. on retransmission) don't cause +any issues. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -62,7 +62,7 @@ static void ath_tx_rc_status(struct ath_ + struct ath_tx_status *ts, int nframes, int nbad, + int txok); + static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, +- int seqno); ++ struct ath_buf *bf); + static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, + struct ath_txq *txq, + struct ath_atx_tid *tid, +@@ -296,7 +296,7 @@ static void ath_tx_flush_tid(struct ath_ + } + + if (fi->baw_tracked) { +- ath_tx_update_baw(sc, tid, bf->bf_state.seqno); ++ ath_tx_update_baw(sc, tid, bf); + sendbar = true; + } + +@@ -312,10 +312,15 @@ static void ath_tx_flush_tid(struct ath_ + } + + static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, +- int seqno) ++ struct ath_buf *bf) + { ++ struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); ++ u16 seqno = bf->bf_state.seqno; + int index, cindex; + ++ if (!fi->baw_tracked) ++ return; ++ + index = ATH_BA_INDEX(tid->seq_start, seqno); + cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); + +@@ -336,6 +341,9 @@ static void ath_tx_addto_baw(struct ath_ + u16 seqno = bf->bf_state.seqno; + int index, cindex; + ++ if (fi->baw_tracked) ++ return; ++ + index = ATH_BA_INDEX(tid->seq_start, seqno); + cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); + __set_bit(cindex, tid->tx_buf); +@@ -612,7 +620,7 @@ static void ath_tx_complete_aggr(struct + * complete the acked-ones/xretried ones; update + * block-ack window + */ +- ath_tx_update_baw(sc, tid, seqno); ++ ath_tx_update_baw(sc, tid, bf); + + if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { + memcpy(tx_info->control.rates, rates, sizeof(rates)); +@@ -642,7 +650,7 @@ static void ath_tx_complete_aggr(struct + * run out of tx buf. + */ + if (!tbf) { +- ath_tx_update_baw(sc, tid, seqno); ++ ath_tx_update_baw(sc, tid, bf); + + ath_tx_complete_buf(sc, bf, txq, + &bf_head, NULL, ts, +@@ -1011,11 +1019,14 @@ ath_tx_get_tid_subframe(struct ath_softc + + INIT_LIST_HEAD(&bf_head); + list_add(&bf->list, &bf_head); +- ath_tx_update_baw(sc, tid, seqno); ++ ath_tx_update_baw(sc, tid, bf); + ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); + continue; + } + ++ if (bf_isampdu(bf)) ++ ath_tx_addto_baw(sc, tid, bf); ++ + return bf; + } + +@@ -1073,8 +1084,6 @@ ath_tx_form_aggr(struct ath_softc *sc, s + bf->bf_next = NULL; + + /* link buffers of this frame to the aggregate */ +- if (!fi->baw_tracked) +- ath_tx_addto_baw(sc, tid, bf); + bf->bf_state.ndelim = ndelim; + + list_add_tail(&bf->list, bf_q); +@@ -1710,10 +1719,8 @@ void ath9k_release_buffered_frames(struc + ath9k_set_moredata(sc, bf, true); + list_add_tail(&bf->list, &bf_q); + ath_set_rates(tid->an->vif, tid->an->sta, bf); +- if (bf_isampdu(bf)) { +- ath_tx_addto_baw(sc, tid, bf); ++ if (bf_isampdu(bf)) + bf->bf_state.bf_type &= ~BUF_AGGR; +- } + if (bf_tail) + bf_tail->bf_next = bf; + diff --git a/package/kernel/mac80211/patches/ath/364-ath9k_hw-fix-channel-maximum-power-level-test.patch b/package/kernel/mac80211/patches/ath/364-ath9k_hw-fix-channel-maximum-power-level-test.patch new file mode 100644 index 0000000000..67cbe92e59 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/364-ath9k_hw-fix-channel-maximum-power-level-test.patch @@ -0,0 +1,47 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Wed, 22 Mar 2017 20:37:04 +0100 +Subject: [PATCH] ath9k_hw: fix channel maximum power level test + +The tx power applied by set_txpower is limited by the CTL (conformance +test limit) entries in the EEPROM. These can change based on the user +configured regulatory domain. +Depending on the EEPROM data this can cause the tx power to become too +limited, if the original regdomain CTLs impose lowr limits than the CTLs +of the user configured regdomain. + +To fix this issue, set the initial channel limits without any CTL +restrictions and only apply the CTL at run time when setting the channel +and the real tx power. + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -2937,10 +2937,14 @@ void ath9k_hw_apply_txpower(struct ath_h + struct ieee80211_channel *channel; + int chan_pwr, new_pwr, max_gain; + int ant_gain, ant_reduction = 0; ++ u16 ctl = NO_CTL; + + if (!chan) + return; + ++ if (!test) ++ ctl = ath9k_regd_get_ctl(reg, chan); ++ + channel = chan->chan; + chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER); + new_pwr = min_t(int, chan_pwr, reg->power_limit); +@@ -2950,9 +2954,7 @@ void ath9k_hw_apply_txpower(struct ath_h + if (ant_gain > max_gain) + ant_reduction = ant_gain - max_gain; + +- ah->eep_ops->set_txpower(ah, chan, +- ath9k_regd_get_ctl(reg, chan), +- ant_reduction, new_pwr, test); ++ ah->eep_ops->set_txpower(ah, chan, ctl, ant_reduction, new_pwr, test); + } + + void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) diff --git a/package/kernel/mac80211/patches/ath/365-ath9k-adjust-tx-power-reduction-for-US-regulatory-do.patch b/package/kernel/mac80211/patches/ath/365-ath9k-adjust-tx-power-reduction-for-US-regulatory-do.patch new file mode 100644 index 0000000000..78083517bc --- /dev/null +++ b/package/kernel/mac80211/patches/ath/365-ath9k-adjust-tx-power-reduction-for-US-regulatory-do.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Wed, 19 Jul 2017 08:49:31 +0200 +Subject: [PATCH] ath9k: adjust tx power reduction for US regulatory + domain + +FCC regulatory rules allow for up to 3 dBi antenna gain. Account for +this in the EEPROM based tx power reduction code. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -2954,6 +2954,10 @@ void ath9k_hw_apply_txpower(struct ath_h + if (ant_gain > max_gain) + ant_reduction = ant_gain - max_gain; + ++ /* FCC allows maximum antenna gain of 3 dBi */ ++ if (reg->region == NL80211_DFS_FCC) ++ ant_reduction = max_t(int, ant_reduction - 6, 0); ++ + ah->eep_ops->set_txpower(ah, chan, ctl, ant_reduction, new_pwr, test); + } + diff --git a/package/kernel/mac80211/patches/ath/366-ath9k-fix-more-data-flag-for-buffered-multicast-pack.patch b/package/kernel/mac80211/patches/ath/366-ath9k-fix-more-data-flag-for-buffered-multicast-pack.patch new file mode 100644 index 0000000000..0f3120d671 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/366-ath9k-fix-more-data-flag-for-buffered-multicast-pack.patch @@ -0,0 +1,41 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Sun, 23 Jul 2017 14:58:22 +0200 +Subject: [PATCH] ath9k: fix more-data flag for buffered multicast + packets + +The flag needs to be cleared for the last packet in the list, not the +first one. Fixes some issues with multicast packet loss for powersave +clients connected to an ath9k AP. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -2436,7 +2436,6 @@ void ath_tx_cabq(struct ieee80211_hw *hw + .txq = sc->beacon.cabq + }; + struct ath_tx_info info = {}; +- struct ieee80211_hdr *hdr; + struct ath_buf *bf_tail = NULL; + struct ath_buf *bf; + LIST_HEAD(bf_q); +@@ -2480,15 +2479,10 @@ void ath_tx_cabq(struct ieee80211_hw *hw + if (list_empty(&bf_q)) + return; + +- bf = list_first_entry(&bf_q, struct ath_buf, list); +- hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; +- +- if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) { +- hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); +- dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, +- sizeof(*hdr), DMA_TO_DEVICE); +- } ++ bf = list_last_entry(&bf_q, struct ath_buf, list); ++ ath9k_set_moredata(sc, bf, false); + ++ bf = list_first_entry(&bf_q, struct ath_buf, list); + ath_txq_lock(sc, txctl.txq); + ath_tx_fill_desc(sc, bf, txctl.txq, 0); + ath_tx_txqaddbuf(sc, txctl.txq, &bf_q, false); diff --git a/package/kernel/mac80211/patches/ath/381-ath9k-fix-tx99-with-monitor-mode-interface.patch b/package/kernel/mac80211/patches/ath/381-ath9k-fix-tx99-with-monitor-mode-interface.patch new file mode 100644 index 0000000000..777b73417f --- /dev/null +++ b/package/kernel/mac80211/patches/ath/381-ath9k-fix-tx99-with-monitor-mode-interface.patch @@ -0,0 +1,92 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Mon, 20 Aug 2018 11:35:05 +0200 +Subject: [PATCH] ath9k: fix tx99 with monitor mode interface + +Tx99 is typically configured via a monitor mode interface, which does +not get added to the driver as a vif. Since the code currently expects +a configured virtual interface for tx99, enabling tx99 via debugfs fails. +Since the vif is not needed anyway, remove all checks for it. + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -1074,7 +1074,6 @@ struct ath_softc { + + struct ath_spec_scan_priv spec_priv; + +- struct ieee80211_vif *tx99_vif; + struct sk_buff *tx99_skb; + bool tx99_state; + s16 tx99_power; +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -1251,15 +1251,10 @@ static int ath9k_add_interface(struct ie + struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_node *an = &avp->mcast_node; + +- mutex_lock(&sc->mutex); ++ if (IS_ENABLED(CPTCFG_ATH9K_TX99)) ++ return -EOPNOTSUPP; + +- if (IS_ENABLED(CPTCFG_ATH9K_TX99)) { +- if (sc->cur_chan->nvifs >= 1) { +- mutex_unlock(&sc->mutex); +- return -EOPNOTSUPP; +- } +- sc->tx99_vif = vif; +- } ++ mutex_lock(&sc->mutex); + + ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); + sc->cur_chan->nvifs++; +@@ -1342,7 +1337,6 @@ static void ath9k_remove_interface(struc + ath9k_p2p_remove_vif(sc, vif); + + sc->cur_chan->nvifs--; +- sc->tx99_vif = NULL; + if (!ath9k_is_chanctx_enabled()) + list_del(&avp->list); + +--- a/drivers/net/wireless/ath/ath9k/tx99.c ++++ b/drivers/net/wireless/ath/ath9k/tx99.c +@@ -54,12 +54,6 @@ static struct sk_buff *ath9k_build_tx99_ + struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *tx_info; + struct sk_buff *skb; +- struct ath_vif *avp; +- +- if (!sc->tx99_vif) +- return NULL; +- +- avp = (struct ath_vif *)sc->tx99_vif->drv_priv; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) +@@ -77,14 +71,11 @@ static struct sk_buff *ath9k_build_tx99_ + memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); + memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); + +- hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); +- + tx_info = IEEE80211_SKB_CB(skb); + memset(tx_info, 0, sizeof(*tx_info)); + rate = &tx_info->control.rates[0]; + tx_info->band = sc->cur_chan->chandef.chan->band; + tx_info->flags = IEEE80211_TX_CTL_NO_ACK; +- tx_info->control.vif = sc->tx99_vif; + rate->count = 1; + if (ah->curchan && IS_CHAN_HT(ah->curchan)) { + rate->flags |= IEEE80211_TX_RC_MCS; +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -2973,7 +2973,7 @@ int ath9k_tx99_send(struct ath_softc *sc + return -EINVAL; + } + +- ath_set_rates(sc->tx99_vif, NULL, bf); ++ ath_set_rates(NULL, NULL, bf); + + ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr); + ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum); diff --git a/package/kernel/mac80211/patches/ath/400-ath_move_debug_code.patch b/package/kernel/mac80211/patches/ath/400-ath_move_debug_code.patch new file mode 100644 index 0000000000..ed65053d77 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/400-ath_move_debug_code.patch @@ -0,0 +1,31 @@ +--- a/drivers/net/wireless/ath/Makefile ++++ b/drivers/net/wireless/ath/Makefile +@@ -13,10 +13,10 @@ ath-objs := main.o \ + regd.o \ + hw.o \ + key.o \ ++ debug.o \ + dfs_pattern_detector.o \ + dfs_pri_detector.o + +-ath-$(CPTCFG_ATH_DEBUG) += debug.o + ath-$(CPTCFG_ATH_TRACEPOINTS) += trace.o + + CFLAGS_trace.o := -I$(src) +--- a/drivers/net/wireless/ath/ath.h ++++ b/drivers/net/wireless/ath/ath.h +@@ -318,14 +318,7 @@ void _ath_dbg(struct ath_common *common, + #endif /* CPTCFG_ATH_DEBUG */ + + /** Returns string describing opmode, or NULL if unknown mode. */ +-#ifdef CPTCFG_ATH_DEBUG + const char *ath_opmode_to_string(enum nl80211_iftype opmode); +-#else +-static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode) +-{ +- return "UNKNOWN"; +-} +-#endif + + extern const char *ath_bus_type_strings[]; + static inline const char *ath_bus_type_to_string(enum ath_bus_type bustype) diff --git a/package/kernel/mac80211/patches/ath/401-ath9k_blink_default.patch b/package/kernel/mac80211/patches/ath/401-ath9k_blink_default.patch new file mode 100644 index 0000000000..7405e594fe --- /dev/null +++ b/package/kernel/mac80211/patches/ath/401-ath9k_blink_default.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -47,7 +47,7 @@ int ath9k_modparam_nohwcrypt; + module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); + MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); + +-int ath9k_led_blink; ++int ath9k_led_blink = 1; + module_param_named(blink, ath9k_led_blink, int, 0444); + MODULE_PARM_DESC(blink, "Enable LED blink on activity"); + diff --git a/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch b/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch new file mode 100644 index 0000000000..8fa56f40a4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch @@ -0,0 +1,92 @@ +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -24,6 +24,7 @@ + #include "regd_common.h" + + static int __ath_regd_init(struct ath_regulatory *reg); ++static struct reg_dmn_pair_mapping *ath_get_regpair(int regdmn); + + /* + * This is a set of common rules used by our world regulatory domains. +@@ -116,6 +117,9 @@ static const struct ieee80211_regdomain + + static bool dynamic_country_user_possible(struct ath_regulatory *reg) + { ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return true; ++ + if (IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) + return true; + +@@ -188,6 +192,8 @@ static bool dynamic_country_user_possibl + + static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg) + { ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return true; + if (!IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_REG_HINTS)) + return false; + if (!dynamic_country_user_possible(reg)) +@@ -345,6 +351,9 @@ ath_reg_apply_beaconing_flags(struct wip + struct ieee80211_channel *ch; + unsigned int i; + ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return; ++ + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!wiphy->bands[band]) + continue; +@@ -378,6 +387,9 @@ ath_reg_apply_ir_flags(struct wiphy *wip + { + struct ieee80211_supported_band *sband; + ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return; ++ + sband = wiphy->bands[NL80211_BAND_2GHZ]; + if (!sband) + return; +@@ -407,6 +419,9 @@ static void ath_reg_apply_radar_flags(st + struct ieee80211_channel *ch; + unsigned int i; + ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return; ++ + if (!wiphy->bands[NL80211_BAND_5GHZ]) + return; + +@@ -639,6 +654,10 @@ ath_regd_init_wiphy(struct ath_regulator + const struct ieee80211_regdomain *regd; + + wiphy->reg_notifier = reg_notifier; ++ ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return 0; ++ + wiphy->regulatory_flags |= REGULATORY_STRICT_REG | + REGULATORY_CUSTOM_REG; + +--- a/drivers/net/wireless/ath/Kconfig ++++ b/drivers/net/wireless/ath/Kconfig +@@ -23,6 +23,9 @@ config WLAN_VENDOR_ATH + + if WLAN_VENDOR_ATH + ++config ATH_USER_REGD ++ bool "Do not enforce EEPROM regulatory restrictions" ++ + config ATH_DEBUG + bool "Atheros wireless debugging" + ---help--- +--- a/local-symbols ++++ b/local-symbols +@@ -87,6 +87,7 @@ ADM8211= + ATH_COMMON= + WLAN_VENDOR_ATH= + ATH_DEBUG= ++ATH_USER_REGD= + ATH_TRACEPOINTS= + ATH_REG_DYNAMIC_USER_REG_HINTS= + ATH_REG_DYNAMIC_USER_CERT_TESTING= diff --git a/package/kernel/mac80211/patches/ath/403-world_regd_fixup.patch b/package/kernel/mac80211/patches/ath/403-world_regd_fixup.patch new file mode 100644 index 0000000000..2043083158 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/403-world_regd_fixup.patch @@ -0,0 +1,84 @@ +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -44,7 +44,8 @@ static struct reg_dmn_pair_mapping *ath_ + NL80211_RRF_NO_OFDM) + + /* We allow IBSS on these on a case by case basis by regulatory domain */ +-#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ ++#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\ ++ REG_RULE(5260-10, 5350+10, 80, 0, 30,\ + NL80211_RRF_NO_IR) + #define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ + NL80211_RRF_NO_IR) +@@ -62,57 +63,56 @@ static struct reg_dmn_pair_mapping *ath_ + #define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \ + ATH9K_5GHZ_5725_5850 + ++#define REGD_RULES(...) \ ++ .reg_rules = { __VA_ARGS__ }, \ ++ .n_reg_rules = ARRAY_SIZE(((struct ieee80211_reg_rule[]) { __VA_ARGS__ })) ++ + /* Can be used for: + * 0x60, 0x61, 0x62 */ + static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = { +- .n_reg_rules = 5, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH9K_2GHZ_ALL, + ATH9K_5GHZ_ALL, +- } ++ ) + }; + + /* Can be used by 0x63 and 0x65 */ + static const struct ieee80211_regdomain ath_world_regdom_63_65 = { +- .n_reg_rules = 4, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH9K_2GHZ_CH01_11, + ATH9K_2GHZ_CH12_13, + ATH9K_5GHZ_NO_MIDBAND, +- } ++ ) + }; + + /* Can be used by 0x64 only */ + static const struct ieee80211_regdomain ath_world_regdom_64 = { +- .n_reg_rules = 3, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH9K_2GHZ_CH01_11, + ATH9K_5GHZ_NO_MIDBAND, +- } ++ ) + }; + + /* Can be used by 0x66 and 0x69 */ + static const struct ieee80211_regdomain ath_world_regdom_66_69 = { +- .n_reg_rules = 3, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH9K_2GHZ_CH01_11, + ATH9K_5GHZ_ALL, +- } ++ ) + }; + + /* Can be used by 0x67, 0x68, 0x6A and 0x6C */ + static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { +- .n_reg_rules = 4, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH9K_2GHZ_CH01_11, + ATH9K_2GHZ_CH12_13, + ATH9K_5GHZ_ALL, +- } ++ ) + }; + + static bool dynamic_country_user_possible(struct ath_regulatory *reg) diff --git a/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch b/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch new file mode 100644 index 0000000000..00be2ef98d --- /dev/null +++ b/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch @@ -0,0 +1,19 @@ +--- a/net/wireless/reg.c ++++ b/net/wireless/reg.c +@@ -2860,6 +2860,8 @@ void regulatory_hint_country_ie(struct w + enum environment_cap env = ENVIRON_ANY; + struct regulatory_request *request = NULL, *lr; + ++ return; ++ + /* IE len must be evenly divisible by 2 */ + if (country_ie_len & 0x01) + return; +@@ -3066,6 +3068,7 @@ static void restore_regulatory_settings( + + void regulatory_hint_disconnect(void) + { ++ return; + pr_debug("All devices are disconnected, going to restore regulatory settings\n"); + restore_regulatory_settings(false); + } diff --git a/package/kernel/mac80211/patches/ath/405-ath_regd_us.patch b/package/kernel/mac80211/patches/ath/405-ath_regd_us.patch new file mode 100644 index 0000000000..cc55877809 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/405-ath_regd_us.patch @@ -0,0 +1,26 @@ +--- a/drivers/net/wireless/ath/regd_common.h ++++ b/drivers/net/wireless/ath/regd_common.h +@@ -32,6 +32,7 @@ enum EnumRd { + FCC2_WORLD = 0x21, + FCC2_ETSIC = 0x22, + FCC6_WORLD = 0x23, ++ FCC3_FCCA_2 = 0x2A, + FRANCE_RES = 0x31, + FCC3_FCCA = 0x3A, + FCC3_WORLD = 0x3B, +@@ -167,6 +168,7 @@ static struct reg_dmn_pair_mapping regDo + {FCC2_WORLD, CTL_FCC, CTL_ETSI}, + {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, + {FCC3_FCCA, CTL_FCC, CTL_FCC}, ++ {FCC3_FCCA_2, CTL_FCC, CTL_FCC}, + {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC4_FCCA, CTL_FCC, CTL_FCC}, + {FCC5_FCCA, CTL_FCC, CTL_FCC}, +@@ -463,6 +465,7 @@ static struct country_code_to_enum_rd al + {CTRY_UAE, NULL1_WORLD, "AE"}, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, + {CTRY_UNITED_STATES, FCC3_FCCA, "US"}, ++ {CTRY_UNITED_STATES, FCC3_FCCA_2, "US"}, + /* This "PS" is for US public safety actually... to support this we + * would need to assign new special alpha2 to CRDA db as with the world + * regdomain and use another alpha2 */ diff --git a/package/kernel/mac80211/patches/ath/406-ath_relax_default_regd.patch b/package/kernel/mac80211/patches/ath/406-ath_relax_default_regd.patch new file mode 100644 index 0000000000..35b0f2b76e --- /dev/null +++ b/package/kernel/mac80211/patches/ath/406-ath_relax_default_regd.patch @@ -0,0 +1,51 @@ +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -115,6 +115,16 @@ static const struct ieee80211_regdomain + ) + }; + ++static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) ++{ ++ return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; ++} ++ ++static bool is_default_regd(struct ath_regulatory *reg) ++{ ++ return ath_regd_get_eepromRD(reg) == CTRY_DEFAULT; ++} ++ + static bool dynamic_country_user_possible(struct ath_regulatory *reg) + { + if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) +@@ -123,6 +133,9 @@ static bool dynamic_country_user_possibl + if (IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) + return true; + ++ if (is_default_regd(reg)) ++ return true; ++ + switch (reg->country_code) { + case CTRY_UNITED_STATES: + case CTRY_JAPAN1: +@@ -208,11 +221,6 @@ static inline bool is_wwr_sku(u16 regd) + (regd == WORLD)); + } + +-static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) +-{ +- return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; +-} +- + bool ath_is_world_regd(struct ath_regulatory *reg) + { + return is_wwr_sku(ath_regd_get_eepromRD(reg)); +@@ -658,6 +666,9 @@ ath_regd_init_wiphy(struct ath_regulator + if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) + return 0; + ++ if (is_default_regd(reg)) ++ return 0; ++ + wiphy->regulatory_flags |= REGULATORY_STRICT_REG | + REGULATORY_CUSTOM_REG; + diff --git a/package/kernel/mac80211/patches/ath/410-ath9k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/ath/410-ath9k_allow_adhoc_and_ap.patch new file mode 100644 index 0000000000..86f96e8e97 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/410-ath9k_allow_adhoc_and_ap.patch @@ -0,0 +1,10 @@ +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -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) }, ++ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + }; + + #ifdef CPTCFG_WIRELESS_WDS diff --git a/package/kernel/mac80211/patches/ath/411-ath5k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/ath/411-ath5k_allow_adhoc_and_ap.patch new file mode 100644 index 0000000000..2a5ab3d428 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/411-ath5k_allow_adhoc_and_ap.patch @@ -0,0 +1,46 @@ +--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c ++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c +@@ -86,13 +86,8 @@ ath5k_add_interface(struct ieee80211_hw + goto end; + } + +- /* Don't allow other interfaces if one ad-hoc is configured. +- * TODO: Fix the problems with ad-hoc and multiple other interfaces. +- * We would need to operate the HW in ad-hoc mode to allow TSF updates +- * for the IBSS, but this breaks with additional AP or STA interfaces +- * at the moment. */ +- if (ah->num_adhoc_vifs || +- (ah->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { ++ /* Don't allow more than one ad-hoc interface */ ++ if (ah->num_adhoc_vifs && vif->type == NL80211_IFTYPE_ADHOC) { + ATH5K_ERR(ah, "Only one single ad-hoc interface is allowed.\n"); + ret = -ELNRNG; + goto end; +--- a/drivers/net/wireless/ath/ath5k/base.c ++++ b/drivers/net/wireless/ath/ath5k/base.c +@@ -1965,7 +1965,7 @@ ath5k_beacon_send(struct ath5k_hw *ah) + } + + if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + +- ah->num_mesh_vifs > 1) || ++ ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) || + ah->opmode == NL80211_IFTYPE_MESH_POINT) { + u64 tsf = ath5k_hw_get_tsf64(ah); + u32 tsftu = TSF_TO_TU(tsf); +@@ -2051,7 +2051,7 @@ ath5k_beacon_update_timers(struct ath5k_ + + intval = ah->bintval & AR5K_BEACON_PERIOD; + if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs +- + ah->num_mesh_vifs > 1) { ++ + ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) { + intval /= ATH_BCBUF; /* staggered multi-bss beacons */ + if (intval < 15) + ATH5K_WARN(ah, "intval %u is too low, min 15\n", +@@ -2518,6 +2518,7 @@ static const struct ieee80211_iface_limi + BIT(NL80211_IFTYPE_MESH_POINT) | + #endif + BIT(NL80211_IFTYPE_AP) }, ++ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + }; + + static const struct ieee80211_iface_combination if_comb = { diff --git a/package/kernel/mac80211/patches/ath/420-ath5k_disable_fast_cc.patch b/package/kernel/mac80211/patches/ath/420-ath5k_disable_fast_cc.patch new file mode 100644 index 0000000000..414f49508f --- /dev/null +++ b/package/kernel/mac80211/patches/ath/420-ath5k_disable_fast_cc.patch @@ -0,0 +1,18 @@ +--- a/drivers/net/wireless/ath/ath5k/reset.c ++++ b/drivers/net/wireless/ath/ath5k/reset.c +@@ -1154,6 +1154,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum + tsf_lo = 0; + mode = 0; + ++#if 0 + /* + * Sanity check for fast flag + * Fast channel change only available +@@ -1161,6 +1162,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum + */ + if (fast && (ah->ah_radio != AR5K_RF2413) && + (ah->ah_radio != AR5K_RF5413)) ++#endif + fast = false; + + /* Disable sleep clock operation diff --git a/package/kernel/mac80211/patches/ath/430-add_ath5k_platform.patch b/package/kernel/mac80211/patches/ath/430-add_ath5k_platform.patch new file mode 100644 index 0000000000..b213e2a819 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/430-add_ath5k_platform.patch @@ -0,0 +1,33 @@ +--- /dev/null ++++ b/include/linux/ath5k_platform.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2008 Atheros Communications Inc. ++ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org> ++ * Copyright (c) 2010 Daniel Golle <daniel.golle@gmail.com> ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _LINUX_ATH5K_PLATFORM_H ++#define _LINUX_ATH5K_PLATFORM_H ++ ++#define ATH5K_PLAT_EEP_MAX_WORDS 2048 ++ ++struct ath5k_platform_data { ++ u16 *eeprom_data; ++ u8 *macaddr; ++}; ++ ++#endif /* _LINUX_ATH5K_PLATFORM_H */ diff --git a/package/kernel/mac80211/patches/ath/431-add_platform_eeprom_support_to_ath5k.patch b/package/kernel/mac80211/patches/ath/431-add_platform_eeprom_support_to_ath5k.patch new file mode 100644 index 0000000000..cdc9315cd6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/431-add_platform_eeprom_support_to_ath5k.patch @@ -0,0 +1,56 @@ +--- a/drivers/net/wireless/ath/ath5k/pci.c ++++ b/drivers/net/wireless/ath/ath5k/pci.c +@@ -21,6 +21,7 @@ + #include <linux/pci-aspm.h> + #include <linux/etherdevice.h> + #include <linux/module.h> ++#include <linux/ath5k_platform.h> + #include "../ath.h" + #include "ath5k.h" + #include "debug.h" +@@ -72,7 +73,7 @@ static void ath5k_pci_read_cachesize(str + } + + /* +- * Read from eeprom ++ * Read from eeprom or platform_data + */ + static bool + ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) +@@ -80,6 +81,19 @@ ath5k_pci_eeprom_read(struct ath_common + struct ath5k_hw *ah = (struct ath5k_hw *) common->ah; + u32 status, timeout; + ++ struct ath5k_platform_data *pdata = NULL; ++ ++ if (ah->pdev) ++ pdata = ah->pdev->dev.platform_data; ++ ++ if (pdata && pdata->eeprom_data && pdata->eeprom_data[61] == AR5K_EEPROM_MAGIC_VALUE) { ++ if (offset >= ATH5K_PLAT_EEP_MAX_WORDS) ++ return false; ++ ++ *data = pdata->eeprom_data[offset]; ++ return true; ++ } ++ + /* + * Initialize EEPROM access + */ +@@ -123,6 +137,16 @@ static int ath5k_pci_eeprom_read_mac(str + u16 data; + int octet; + ++ struct ath5k_platform_data *pdata = NULL; ++ ++ if (ah->pdev) ++ pdata = ah->pdev->dev.platform_data; ++ ++ if (pdata && pdata->macaddr) { ++ memcpy(mac, pdata->macaddr, ETH_ALEN); ++ return 0; ++ } ++ + AR5K_EEPROM_READ(0x20, data); + + for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { diff --git a/package/kernel/mac80211/patches/ath/432-ath5k_add_pciids.patch b/package/kernel/mac80211/patches/ath/432-ath5k_add_pciids.patch new file mode 100644 index 0000000000..d82f8001d4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/432-ath5k_add_pciids.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ath/ath5k/pci.c ++++ b/drivers/net/wireless/ath/ath5k/pci.c +@@ -48,6 +48,8 @@ static const struct pci_device_id ath5k_ + { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */ + { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */ + { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */ ++ { PCI_VDEVICE(ATHEROS, 0xff16) }, /* 2413,2414 sx76x on lantiq_danube */ ++ { PCI_VDEVICE(ATHEROS, 0xff1a) }, /* 2417 arv45xx on lantiq_danube */ + { PCI_VDEVICE(ATHEROS, 0xff1b) }, /* AR5BXB63 */ + { 0 } + }; diff --git a/package/kernel/mac80211/patches/ath/440-ath5k_channel_bw_debugfs.patch b/package/kernel/mac80211/patches/ath/440-ath5k_channel_bw_debugfs.patch new file mode 100644 index 0000000000..20d67d2762 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/440-ath5k_channel_bw_debugfs.patch @@ -0,0 +1,148 @@ +This adds a bwmode debugfs file which can be used to set alternate +channel operating bandwidths. Only tested with AR5413 and only at +5 and 20 mhz channels. + +Signed-off-by: Pat Erley <pat-lkml at erley.org> +--- +Other devices will need to be added to the switch in write_file_bwmode + +drivers/net/wireless/ath/ath5k/debug.c | 86 ++++++++++++++++++++++++++++++++ + 1 files changed, 86 insertions(+), 0 deletions(-) + +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath5k/debug.c +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath5k/debug.c ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath5k/debug.c +@@ -822,6 +822,97 @@ static const struct file_operations fops + .llseek = default_llseek, + }; + ++/* debugfs: bwmode */ ++ ++static ssize_t read_file_bwmode(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath5k_hw *ah = file->private_data; ++ char buf[15]; ++ unsigned int len = 0; ++ ++ int cur_ah_bwmode = ah->ah_bwmode_debug; ++ ++#define print_selected(MODE, LABEL) \ ++ if (cur_ah_bwmode == MODE) \ ++ len += snprintf(buf+len, sizeof(buf)-len, "[%s]", LABEL); \ ++ else \ ++ len += snprintf(buf+len, sizeof(buf)-len, "%s", LABEL); \ ++ len += snprintf(buf+len, sizeof(buf)-len, " "); ++ ++ print_selected(AR5K_BWMODE_5MHZ, "5"); ++ print_selected(AR5K_BWMODE_10MHZ, "10"); ++ print_selected(AR5K_BWMODE_DEFAULT, "20"); ++ print_selected(AR5K_BWMODE_40MHZ, "40"); ++#undef print_selected ++ ++ len += snprintf(buf+len, sizeof(buf)-len, "\n"); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t write_file_bwmode(struct file *file, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath5k_hw *ah = file->private_data; ++ char buf[3]; ++ int bw = 20; ++ int tobwmode = AR5K_BWMODE_DEFAULT; ++ ++ if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) ++ return -EFAULT; ++ ++ /* TODO: Add check for active interface */ ++ ++ if(strncmp(buf, "5", 1) == 0 ) { ++ tobwmode = AR5K_BWMODE_5MHZ; ++ bw = 5; ++ } else if ( strncmp(buf, "10", 2) == 0 ) { ++ tobwmode = AR5K_BWMODE_10MHZ; ++ bw = 10; ++ } else if ( strncmp(buf, "20", 2) == 0 ) { ++ tobwmode = AR5K_BWMODE_DEFAULT; ++ bw = 20; ++ } else if ( strncmp(buf, "40", 2) == 0 ) { ++ tobwmode = AR5K_BWMODE_40MHZ; ++ bw = 40; ++ } else ++ return -EINVAL; ++ ++ ATH5K_INFO(ah, "Changing to %imhz channel width[%i]\n", ++ bw, tobwmode); ++ ++ switch (ah->ah_radio) { ++ /* TODO: only define radios that actually support 5/10mhz channels */ ++ case AR5K_RF5413: ++ case AR5K_RF5110: ++ case AR5K_RF5111: ++ case AR5K_RF5112: ++ case AR5K_RF2413: ++ case AR5K_RF2316: ++ case AR5K_RF2317: ++ case AR5K_RF2425: ++ if(ah->ah_bwmode_debug != tobwmode) { ++ mutex_lock(&ah->lock); ++ ah->ah_bwmode = tobwmode; ++ ah->ah_bwmode_debug = tobwmode; ++ mutex_unlock(&ah->lock); ++ } ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return count; ++} ++ ++static const struct file_operations fops_bwmode = { ++ .read = read_file_bwmode, ++ .write = write_file_bwmode, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; + + /* debugfs: queues etc */ + +@@ -1016,6 +1107,8 @@ ath5k_debug_init_device(struct ath5k_hw + debugfs_create_file("queue", 0600, phydir, ah, &fops_queue); + debugfs_create_bool("32khz_clock", 0600, phydir, + &ah->ah_use_32khz_clock); ++ debugfs_create_file("bwmode", S_IWUSR | S_IRUSR, phydir, ah, ++ &fops_bwmode); + } + + /* functions used in other places */ +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath5k/ath5k.h +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath5k/ath5k.h ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath5k/ath5k.h +@@ -1372,6 +1372,7 @@ struct ath5k_hw { + u8 ah_coverage_class; + bool ah_ack_bitrate_high; + u8 ah_bwmode; ++ u8 ah_bwmode_debug; + bool ah_short_slot; + + /* Antenna Control */ +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath5k/base.c +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath5k/base.c ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath5k/base.c +@@ -466,6 +466,9 @@ ath5k_chan_set(struct ath5k_hw *ah, stru + return -EINVAL; + } + ++ if (ah->ah_bwmode_debug != AR5K_BWMODE_DEFAULT) ++ ah->ah_bwmode = ah->ah_bwmode_debug; ++ + /* + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the diff --git a/package/kernel/mac80211/patches/ath/500-ath9k_eeprom_debugfs.patch b/package/kernel/mac80211/patches/ath/500-ath9k_eeprom_debugfs.patch new file mode 100644 index 0000000000..b6dc45cd96 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/500-ath9k_eeprom_debugfs.patch @@ -0,0 +1,65 @@ +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1374,6 +1374,53 @@ void ath9k_deinit_debug(struct ath_softc + ath9k_cmn_spectral_deinit_debug(&sc->spec_priv); + } + ++static ssize_t read_file_eeprom(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ struct ath_hw *ah = sc->sc_ah; ++ struct ath_common *common = ath9k_hw_common(ah); ++ int bytes = 0; ++ int pos = *ppos; ++ int size = 4096; ++ u16 val; ++ int i; ++ ++ if (AR_SREV_9300_20_OR_LATER(ah)) ++ size = 16384; ++ ++ if (*ppos < 0) ++ return -EINVAL; ++ ++ if (count > size - *ppos) ++ count = size - *ppos; ++ ++ for (i = *ppos / 2; count > 0; count -= bytes, *ppos += bytes, i++) { ++ void *from = &val; ++ ++ if (!common->bus_ops->eeprom_read(common, i, &val)) ++ val = 0xffff; ++ ++ if (*ppos % 2) { ++ from++; ++ bytes = 1; ++ } else if (count == 1) { ++ bytes = 1; ++ } else { ++ bytes = 2; ++ } ++ copy_to_user(user_buf, from, bytes); ++ user_buf += bytes; ++ } ++ return *ppos - pos; ++} ++ ++static const struct file_operations fops_eeprom = { ++ .read = read_file_eeprom, ++ .open = simple_open, ++ .owner = THIS_MODULE ++}; ++ + int ath9k_init_debug(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); +@@ -1393,6 +1440,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); + ++ debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, ++ &fops_eeprom); + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, diff --git a/package/kernel/mac80211/patches/ath/501-ath9k_ahb_init.patch b/package/kernel/mac80211/patches/ath/501-ath9k_ahb_init.patch new file mode 100644 index 0000000000..9c194b07b8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/501-ath9k_ahb_init.patch @@ -0,0 +1,36 @@ +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath9k/init.c +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath9k/init.c ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath9k/init.c +@@ -1144,25 +1144,25 @@ static int __init ath9k_init(void) + { + int error; + +- error = ath_pci_init(); ++ error = ath_ahb_init(); + if (error < 0) { +- pr_err("No PCI devices found, driver not installed\n"); + error = -ENODEV; + goto err_out; + } + +- error = ath_ahb_init(); ++ error = ath_pci_init(); + if (error < 0) { ++ pr_err("No PCI devices found, driver not installed\n"); + error = -ENODEV; +- goto err_pci_exit; ++ goto err_ahb_exit; + } + + dmi_check_system(ath9k_quirks); + + return 0; + +- err_pci_exit: +- ath_pci_exit(); ++ err_ahb_exit: ++ ath_ahb_exit(); + err_out: + return error; + } diff --git a/package/kernel/mac80211/patches/ath/510-ath9k_intr_mitigation_tweak.patch b/package/kernel/mac80211/patches/ath/510-ath9k_intr_mitigation_tweak.patch new file mode 100644 index 0000000000..d2a3b96570 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/510-ath9k_intr_mitigation_tweak.patch @@ -0,0 +1,18 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -390,13 +390,8 @@ static void ath9k_hw_init_config(struct + + ah->config.rx_intr_mitigation = true; + +- if (AR_SREV_9300_20_OR_LATER(ah)) { +- ah->config.rimt_last = 500; +- ah->config.rimt_first = 2000; +- } else { +- ah->config.rimt_last = 250; +- ah->config.rimt_first = 700; +- } ++ ah->config.rimt_last = 250; ++ ah->config.rimt_first = 500; + + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) + ah->config.pll_pwrsave = 7; diff --git a/package/kernel/mac80211/patches/ath/511-ath9k_reduce_rxbuf.patch b/package/kernel/mac80211/patches/ath/511-ath9k_reduce_rxbuf.patch new file mode 100644 index 0000000000..15b8d7b86b --- /dev/null +++ b/package/kernel/mac80211/patches/ath/511-ath9k_reduce_rxbuf.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -88,7 +88,7 @@ int ath_descdma_setup(struct ath_softc * + (_l) &= ((_sz) - 1); \ + } while (0) + +-#define ATH_RXBUF 512 ++#define ATH_RXBUF 256 + #define ATH_TXBUF 512 + #define ATH_TXBUF_RESERVE 5 + #define ATH_TXMAXTRY 13 diff --git a/package/kernel/mac80211/patches/ath/512-ath9k_channelbw_debugfs.patch b/package/kernel/mac80211/patches/ath/512-ath9k_channelbw_debugfs.patch new file mode 100644 index 0000000000..2ebb73d689 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/512-ath9k_channelbw_debugfs.patch @@ -0,0 +1,125 @@ +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1421,6 +1421,52 @@ static const struct file_operations fops + .owner = THIS_MODULE + }; + ++ ++static ssize_t read_file_chan_bw(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ char buf[32]; ++ unsigned int len; ++ ++ len = sprintf(buf, "0x%08x\n", common->chan_bw); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t write_file_chan_bw(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ unsigned long chan_bw; ++ char buf[32]; ++ ssize_t len; ++ ++ len = min(count, sizeof(buf) - 1); ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ if (kstrtoul(buf, 0, &chan_bw)) ++ return -EINVAL; ++ ++ common->chan_bw = chan_bw; ++ if (!test_bit(ATH_OP_INVALID, &common->op_flags)) ++ ath9k_ops.config(sc->hw, IEEE80211_CONF_CHANGE_CHANNEL); ++ ++ return count; ++} ++ ++static const struct file_operations fops_chanbw = { ++ .read = read_file_chan_bw, ++ .write = write_file_chan_bw, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++ + int ath9k_init_debug(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); +@@ -1442,6 +1488,8 @@ int ath9k_init_debug(struct ath_hw *ah) + + debugfs_create_file("eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_eeprom); ++ debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++ sc, &fops_chanbw); + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, +--- a/drivers/net/wireless/ath/ath.h ++++ b/drivers/net/wireless/ath/ath.h +@@ -151,6 +151,7 @@ struct ath_common { + int debug_mask; + enum ath_device_state state; + unsigned long op_flags; ++ u32 chan_bw; + + struct ath_ani ani; + +--- a/drivers/net/wireless/ath/ath9k/common.c ++++ b/drivers/net/wireless/ath/ath9k/common.c +@@ -297,11 +297,13 @@ EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_ke + /* + * Update internal channel flags. + */ +-static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, ++static void ath9k_cmn_update_ichannel(struct ath_common *common, ++ struct ath9k_channel *ichan, + struct cfg80211_chan_def *chandef) + { + struct ieee80211_channel *chan = chandef->chan; + u16 flags = 0; ++ int width; + + ichan->channel = chan->center_freq; + ichan->chan = chan; +@@ -309,7 +311,19 @@ static void ath9k_cmn_update_ichannel(st + if (chan->band == NL80211_BAND_5GHZ) + flags |= CHANNEL_5GHZ; + +- switch (chandef->width) { ++ switch (common->chan_bw) { ++ case 5: ++ width = NL80211_CHAN_WIDTH_5; ++ break; ++ case 10: ++ width = NL80211_CHAN_WIDTH_10; ++ break; ++ default: ++ width = chandef->width; ++ break; ++ } ++ ++ switch (width) { + case NL80211_CHAN_WIDTH_5: + flags |= CHANNEL_QUARTER; + break; +@@ -342,10 +356,11 @@ struct ath9k_channel *ath9k_cmn_get_chan + struct cfg80211_chan_def *chandef) + { + struct ieee80211_channel *curchan = chandef->chan; ++ struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_channel *channel; + + channel = &ah->channels[curchan->hw_value]; +- ath9k_cmn_update_ichannel(channel, chandef); ++ ath9k_cmn_update_ichannel(common, channel, chandef); + + return channel; + } diff --git a/package/kernel/mac80211/patches/ath/513-ath9k_add_pci_ids.patch b/package/kernel/mac80211/patches/ath/513-ath9k_add_pci_ids.patch new file mode 100644 index 0000000000..fdeaed05e8 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/513-ath9k_add_pci_ids.patch @@ -0,0 +1,30 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -647,6 +647,7 @@ int ath9k_hw_init(struct ath_hw *ah) + + /* These are all the AR5008/AR9001/AR9002/AR9003 hardware family of chipsets */ + switch (ah->hw_version.devid) { ++ case AR9300_DEVID_INVALID: + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR5416_AR9100_DEVID: +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -36,6 +36,7 @@ + + #define ATHEROS_VENDOR_ID 0x168c + ++#define AR9300_DEVID_INVALID 0xabcd + #define AR5416_DEVID_PCI 0x0023 + #define AR5416_DEVID_PCIE 0x0024 + #define AR9160_DEVID_PCI 0x0027 +--- a/drivers/net/wireless/ath/ath9k/pci.c ++++ b/drivers/net/wireless/ath/ath9k/pci.c +@@ -773,6 +773,7 @@ static const struct pci_device_id ath_pc + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + #endif + ++ { PCI_VDEVICE(ATHEROS, 0xabcd) }, /* PCI-E internal chip default ID */ + { 0 } + }; + diff --git a/package/kernel/mac80211/patches/ath/530-ath9k_extra_leds.patch b/package/kernel/mac80211/patches/ath/530-ath9k_extra_leds.patch new file mode 100644 index 0000000000..8ea2f79a20 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/530-ath9k_extra_leds.patch @@ -0,0 +1,267 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -850,6 +850,9 @@ static inline int ath9k_dump_btcoex(stru + #ifdef CPTCFG_MAC80211_LEDS + void ath_init_leds(struct ath_softc *sc); + void ath_deinit_leds(struct ath_softc *sc); ++int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name, ++ const char *trigger, bool active_low); ++ + #else + static inline void ath_init_leds(struct ath_softc *sc) + { +@@ -991,6 +994,13 @@ void ath_ant_comb_scan(struct ath_softc + #define AIRTIME_USE_NEW_QUEUES BIT(2) + #define AIRTIME_ACTIVE(flags) (!!(flags & (AIRTIME_USE_TX|AIRTIME_USE_RX))) + ++struct ath_led { ++ struct list_head list; ++ struct ath_softc *sc; ++ const struct gpio_led *gpio; ++ struct led_classdev cdev; ++}; ++ + struct ath_softc { + struct ieee80211_hw *hw; + struct device *dev; +@@ -1046,9 +1056,8 @@ struct ath_softc { + spinlock_t chan_lock; + + #ifdef CPTCFG_MAC80211_LEDS +- bool led_registered; +- char led_name[32]; +- struct led_classdev led_cdev; ++ const char *led_default_trigger; ++ struct list_head leds; + #endif + + #ifdef CPTCFG_ATH9K_DEBUGFS +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -39,61 +39,111 @@ static void ath_fill_led_pin(struct ath_ + else + ah->led_pin = ATH_LED_PIN_DEF; + } ++} ++ ++static void ath_led_brightness(struct led_classdev *led_cdev, ++ enum led_brightness brightness) ++{ ++ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev); ++ struct ath_softc *sc = led->sc; ++ ++ ath9k_ps_wakeup(sc); ++ ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio, ++ (brightness != LED_OFF) ^ led->gpio->active_low); ++ ath9k_ps_restore(sc); ++} ++ ++static int ath_add_led(struct ath_softc *sc, struct ath_led *led) ++{ ++ const struct gpio_led *gpio = led->gpio; ++ int ret; ++ ++ led->cdev.name = gpio->name; ++ led->cdev.default_trigger = gpio->default_trigger; ++ led->cdev.brightness_set = ath_led_brightness; ++ ++ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev); ++ if (ret < 0) ++ return ret; ++ ++ led->sc = sc; ++ list_add(&led->list, &sc->leds); + + /* Configure gpio for output */ +- ath9k_hw_gpio_request_out(ah, ah->led_pin, "ath9k-led", ++ ath9k_hw_gpio_request_out(sc->sc_ah, gpio->gpio, gpio->name, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + +- /* LED off, active low */ +- ath9k_hw_set_gpio(ah, ah->led_pin, ah->config.led_active_high ? 0 : 1); ++ /* LED off */ ++ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low); ++ ++ return 0; + } + +-static void ath_led_brightness(struct led_classdev *led_cdev, +- enum led_brightness brightness) ++int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name, ++ const char *trigger, bool active_low) + { +- struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev); +- u32 val = (brightness == LED_OFF); ++ struct ath_led *led; ++ struct gpio_led *gpio; ++ char *_name; ++ int ret; + +- if (sc->sc_ah->config.led_active_high) +- val = !val; ++ led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1, ++ GFP_KERNEL); ++ if (!led) ++ return -ENOMEM; ++ ++ led->gpio = gpio = (struct gpio_led *) (led + 1); ++ _name = (char *) (led->gpio + 1); ++ ++ strcpy(_name, name); ++ gpio->name = _name; ++ gpio->gpio = gpio_num; ++ gpio->active_low = active_low; ++ gpio->default_trigger = trigger; ++ ++ 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; + } + + void ath_deinit_leds(struct ath_softc *sc) + { +- if (!sc->led_registered) +- return; ++ struct ath_led *led; + +- ath_led_brightness(&sc->led_cdev, LED_OFF); +- led_classdev_unregister(&sc->led_cdev); +- +- 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); ++ list_del(&led->list); ++ ath_led_brightness(&led->cdev, LED_OFF); ++ led_classdev_unregister(&led->cdev); ++ ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio); ++ kfree(led); ++ } + } + + void ath_init_leds(struct ath_softc *sc) + { +- int ret; ++ char led_name[32]; ++ const char *trigger; ++ ++ INIT_LIST_HEAD(&sc->leds); + + if (AR_SREV_9100(sc->sc_ah)) + return; + + ath_fill_led_pin(sc); + +- if (!ath9k_led_blink) +- sc->led_cdev.default_trigger = +- ieee80211_get_radio_led_name(sc->hw); +- +- snprintf(sc->led_name, sizeof(sc->led_name), +- "ath9k-%s", wiphy_name(sc->hw->wiphy)); +- sc->led_cdev.name = sc->led_name; +- sc->led_cdev.brightness_set = ath_led_brightness; ++ snprintf(led_name, sizeof(led_name), "ath9k-%s", ++ wiphy_name(sc->hw->wiphy)); + +- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev); +- if (ret < 0) +- return; ++ if (ath9k_led_blink) ++ trigger = sc->led_default_trigger; ++ else ++ trigger = ieee80211_get_radio_led_name(sc->hw); + +- sc->led_registered = true; ++ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, ++ !sc->sc_ah->config.led_active_high); + } + #endif + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -1000,7 +1000,7 @@ int ath9k_init_device(u16 devid, struct + + #ifdef CPTCFG_MAC80211_LEDS + /* must be initialized before ieee80211_register_hw */ +- sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw, ++ sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw, + IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink, + ARRAY_SIZE(ath9k_tpt_blink)); + #endif +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1466,6 +1466,61 @@ static const struct file_operations fops + .llseek = default_llseek, + }; + ++#ifdef CONFIG_MAC80211_LEDS ++ ++static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ char buf[32], *str, *name, *c; ++ ssize_t len; ++ unsigned int gpio; ++ bool active_low = false; ++ ++ len = min(count, sizeof(buf) - 1); ++ if (copy_from_user(buf, ubuf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ name = strchr(buf, ','); ++ if (!name) ++ return -EINVAL; ++ ++ *(name++) = 0; ++ if (!*name) ++ return -EINVAL; ++ ++ c = strchr(name, '\n'); ++ if (c) ++ *c = 0; ++ ++ str = buf; ++ if (*str == '!') { ++ str++; ++ active_low = true; ++ } ++ ++ if (kstrtouint(str, 0, &gpio) < 0) ++ return -EINVAL; ++ ++ if (gpio >= sc->sc_ah->caps.num_gpio_pins) ++ return -EINVAL; ++ ++ if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0) ++ return -EINVAL; ++ ++ return count; ++} ++ ++static const struct file_operations fops_gpio_led = { ++ .write = write_file_gpio_led, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++#endif ++ + + int ath9k_init_debug(struct ath_hw *ah) + { +@@ -1490,6 +1545,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); ++#ifdef CONFIG_MAC80211_LEDS ++ debugfs_create_file("gpio_led", S_IWUSR, ++ sc->debug.debugfs_phy, sc, &fops_gpio_led); ++#endif + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, diff --git a/package/kernel/mac80211/patches/ath/531-ath9k_extra_platform_leds.patch b/package/kernel/mac80211/patches/ath/531-ath9k_extra_platform_leds.patch new file mode 100644 index 0000000000..8ed7ad8a09 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/531-ath9k_extra_platform_leds.patch @@ -0,0 +1,76 @@ +--- a/include/linux/ath9k_platform.h ++++ b/include/linux/ath9k_platform.h +@@ -46,6 +46,9 @@ struct ath9k_platform_data { + int (*external_reset)(void); + + bool use_eeprom; ++ ++ int num_leds; ++ const struct gpio_led *leds; + }; + + #endif /* _LINUX_ATH9K_PLATFORM_H */ +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -15,6 +15,7 @@ + */ + + #include "ath9k.h" ++#include <linux/ath9k_platform.h> + + /********************************/ + /* LED functions */ +@@ -108,6 +109,24 @@ int ath_create_gpio_led(struct ath_softc + return ret; + } + ++static int ath_create_platform_led(struct ath_softc *sc, ++ const struct gpio_led *gpio) ++{ ++ struct ath_led *led; ++ int ret; ++ ++ led = kzalloc(sizeof(*led), GFP_KERNEL); ++ if (!led) ++ return -ENOMEM; ++ ++ led->gpio = gpio; ++ ret = ath_add_led(sc, led); ++ if (ret < 0) ++ kfree(led); ++ ++ return ret; ++} ++ + void ath_deinit_leds(struct ath_softc *sc) + { + struct ath_led *led; +@@ -124,8 +143,10 @@ void ath_deinit_leds(struct ath_softc *s + + void ath_init_leds(struct ath_softc *sc) + { ++ struct ath9k_platform_data *pdata = sc->dev->platform_data; + char led_name[32]; + const char *trigger; ++ int i; + + INIT_LIST_HEAD(&sc->leds); + +@@ -134,6 +155,17 @@ void ath_init_leds(struct ath_softc *sc) + + ath_fill_led_pin(sc); + ++ if (pdata && pdata->leds && pdata->num_leds) ++ for (i = 0; i < pdata->num_leds; i++) { ++ if (pdata->leds[i].gpio == sc->sc_ah->led_pin) ++ sc->sc_ah->led_pin = -1; ++ ++ ath_create_platform_led(sc, &pdata->leds[i]); ++ } ++ ++ if (sc->sc_ah->led_pin < 0) ++ return; ++ + snprintf(led_name, sizeof(led_name), "ath9k-%s", + wiphy_name(sc->hw->wiphy)); + diff --git a/package/kernel/mac80211/patches/ath/540-ath9k_reduce_ani_interval.patch b/package/kernel/mac80211/patches/ath/540-ath9k_reduce_ani_interval.patch new file mode 100644 index 0000000000..e899903478 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/540-ath9k_reduce_ani_interval.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ath/ath9k/ani.h ++++ b/drivers/net/wireless/ath/ath9k/ani.h +@@ -42,7 +42,7 @@ + #define ATH9K_ANI_PERIOD 300 + + /* in ms */ +-#define ATH9K_ANI_POLLINTERVAL 1000 ++#define ATH9K_ANI_POLLINTERVAL 300 + + #define ATH9K_SIG_FIRSTEP_SETTING_MIN 0 + #define ATH9K_SIG_FIRSTEP_SETTING_MAX 20 diff --git a/package/kernel/mac80211/patches/ath/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/ath/542-ath9k_debugfs_diag.patch new file mode 100644 index 0000000000..6dd03fd28a --- /dev/null +++ b/package/kernel/mac80211/patches/ath/542-ath9k_debugfs_diag.patch @@ -0,0 +1,139 @@ +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1522,6 +1522,50 @@ static const struct file_operations fops + #endif + + ++static ssize_t read_file_diag(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ struct ath_hw *ah = sc->sc_ah; ++ char buf[32]; ++ unsigned int len; ++ ++ len = sprintf(buf, "0x%08lx\n", ah->diag); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t write_file_diag(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ struct ath_hw *ah = sc->sc_ah; ++ unsigned long diag; ++ char buf[32]; ++ ssize_t len; ++ ++ len = min(count, sizeof(buf) - 1); ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ if (kstrtoul(buf, 0, &diag)) ++ return -EINVAL; ++ ++ ah->diag = diag; ++ ath9k_hw_update_diag(ah); ++ ++ return count; ++} ++ ++static const struct file_operations fops_diag = { ++ .read = read_file_diag, ++ .write = write_file_diag, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++ + int ath9k_init_debug(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); +@@ -1549,6 +1593,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 ++ debugfs_create_file("diag", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++ sc, &fops_diag); + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -520,6 +520,12 @@ enum { + ATH9K_RESET_COLD, + }; + ++enum { ++ ATH_DIAG_DISABLE_RX, ++ ATH_DIAG_DISABLE_TX, ++ ATH_DIAG_TRIGGER_ERROR, ++}; ++ + struct ath9k_hw_version { + u32 magic; + u16 devid; +@@ -806,6 +812,8 @@ struct ath_hw { + u32 ah_flags; + s16 nf_override; + ++ unsigned long diag; ++ + bool reset_power_on; + bool htc_reset_init; + +@@ -1068,6 +1076,7 @@ void ath9k_hw_check_nav(struct ath_hw *a + bool ath9k_hw_check_alive(struct ath_hw *ah); + + bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); ++void ath9k_hw_update_diag(struct ath_hw *ah); + + /* Generic hw timer primitives */ + 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 +@@ -1842,6 +1842,20 @@ u32 ath9k_hw_get_tsf_offset(struct times + } + EXPORT_SYMBOL(ath9k_hw_get_tsf_offset); + ++void ath9k_hw_update_diag(struct ath_hw *ah) ++{ ++ if (test_bit(ATH_DIAG_DISABLE_RX, &ah->diag)) ++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); ++ else ++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); ++ ++ if (test_bit(ATH_DIAG_DISABLE_TX, &ah->diag)) ++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK); ++ else ++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK); ++} ++EXPORT_SYMBOL(ath9k_hw_update_diag); ++ + int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, + struct ath9k_hw_cal_data *caldata, bool fastcc) + { +@@ -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); ++ ath9k_hw_update_diag(ah); + + if (AR_SREV_9565(ah) && common->bt_ant_diversity) + 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 +@@ -528,6 +528,11 @@ irqreturn_t ath_isr(int irq, void *dev) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) + return IRQ_HANDLED; + ++ if (test_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag)) { ++ status |= ATH9K_INT_FATAL; ++ clear_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag); ++ } ++ + /* + * If there are no status bits set, then this interrupt was not + * for me (should have been caught above). diff --git a/package/kernel/mac80211/patches/ath/543-ath9k_entropy_from_adc.patch b/package/kernel/mac80211/patches/ath/543-ath9k_entropy_from_adc.patch new file mode 100644 index 0000000000..f9d3251c22 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/543-ath9k_entropy_from_adc.patch @@ -0,0 +1,186 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -721,6 +721,7 @@ struct ath_spec_scan { + * @config_pci_powersave: + * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC + * ++ * @get_adc_entropy: get entropy from the raw ADC I/Q output + * @spectral_scan_config: set parameters for spectral scan and enable/disable it + * @spectral_scan_trigger: trigger a spectral scan run + * @spectral_scan_wait: wait for a spectral scan run to finish +@@ -743,6 +744,7 @@ struct ath_hw_ops { + struct ath_hw_antcomb_conf *antconf); + void (*antdiv_comb_conf_set)(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf); ++ void (*get_adc_entropy)(struct ath_hw *ah, u8 *buf, size_t len); + void (*spectral_scan_config)(struct ath_hw *ah, + struct ath_spec_scan *param); + void (*spectral_scan_trigger)(struct ath_hw *ah); +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -1945,6 +1945,26 @@ void ar9003_hw_init_rate_txpower(struct + } + } + ++static void ar9003_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len) ++{ ++ int i, j; ++ ++ REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1); ++ REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); ++ REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0); ++ ++ memset(buf, 0, len); ++ for (i = 0; i < len; i++) { ++ for (j = 0; j < 4; j++) { ++ u32 regval = REG_READ(ah, AR_PHY_TST_ADC); ++ ++ buf[i] <<= 2; ++ buf[i] |= (regval & 1) | ((regval & BIT(10)) >> 9); ++ udelay(1); ++ } ++ } ++} ++ + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) + { + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); +@@ -1981,6 +2001,7 @@ void ar9003_hw_attach_phy_ops(struct ath + priv_ops->set_radar_params = ar9003_hw_set_radar_params; + priv_ops->fast_chan_change = ar9003_hw_fast_chan_change; + ++ ops->get_adc_entropy = ar9003_hw_get_adc_entropy; + ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; + ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; + 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 +@@ -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); + +- ah->curchan = curchan; ++ if (curchan) ++ ah->curchan = curchan; + } + + static const struct ieee80211_iface_limit if_limits[] = { +@@ -960,6 +961,18 @@ static void ath9k_set_hw_capab(struct at + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + } + ++static void ath_get_initial_entropy(struct ath_softc *sc) ++{ ++ struct ath_hw *ah = sc->sc_ah; ++ char buf[256]; ++ ++ /* reuse last channel initialized by the tx power test */ ++ ath9k_hw_reset(ah, ah->curchan, NULL, false); ++ ++ ath9k_hw_get_adc_entropy(ah, buf, sizeof(buf)); ++ add_device_randomness(buf, sizeof(buf)); ++} ++ + int ath9k_init_device(u16 devid, struct ath_softc *sc, + const struct ath_bus_ops *bus_ops) + { +@@ -1005,6 +1018,8 @@ int ath9k_init_device(u16 devid, struct + ARRAY_SIZE(ath9k_tpt_blink)); + #endif + ++ ath_get_initial_entropy(sc); ++ + /* Register with mac80211 */ + error = ieee80211_register_hw(hw); + if (error) +--- a/drivers/net/wireless/ath/ath9k/hw-ops.h ++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h +@@ -100,6 +100,12 @@ static inline void ath9k_hw_tx99_set_txp + ath9k_hw_ops(ah)->tx99_set_txpower(ah, power); + } + ++static inline void ath9k_hw_get_adc_entropy(struct ath_hw *ah, ++ u8 *buf, size_t len) ++{ ++ ath9k_hw_ops(ah)->get_adc_entropy(ah, buf, len); ++} ++ + #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT + + static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) +--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c +@@ -1322,9 +1322,30 @@ void ar5008_hw_init_rate_txpower(struct + } + } + ++static void ar5008_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len) ++{ ++ int i, j; ++ ++ REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1); ++ REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); ++ REG_RMW_FIELD(ah, AR_PHY_TEST2, AR_PHY_TEST2_RX_OBS_SEL, 0); ++ ++ memset(buf, 0, len); ++ for (i = 0; i < len; i++) { ++ for (j = 0; j < 4; j++) { ++ u32 regval = REG_READ(ah, AR_PHY_TST_ADC); ++ ++ buf[i] <<= 2; ++ buf[i] |= (regval & 1) | ((regval & BIT(9)) >> 8); ++ udelay(1); ++ } ++ } ++} ++ + int ar5008_hw_attach_phy_ops(struct ath_hw *ah) + { + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); ++ struct ath_hw_ops *ops = ath9k_hw_ops(ah); + static const u32 ar5416_cca_regs[6] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, +@@ -1339,6 +1360,8 @@ int ar5008_hw_attach_phy_ops(struct ath_ + if (ret) + return ret; + ++ ops->get_adc_entropy = ar5008_hw_get_adc_entropy; ++ + priv_ops->rf_set_freq = ar5008_hw_set_channel; + priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate; + +--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h ++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h +@@ -20,6 +20,12 @@ + #define PHY_AGC_CLR 0x10000000 + #define RFSILENT_BB 0x00002000 + ++#define AR_PHY_TEST_BBB_OBS_SEL 0x780000 ++#define AR_PHY_TEST_BBB_OBS_SEL_S 19 ++ ++#define AR_PHY_TEST_RX_OBS_SEL_BIT5_S 23 ++#define AR_PHY_TEST_RX_OBS_SEL_BIT5 (1 << AR_PHY_TEST_RX_OBS_SEL_BIT5_S) ++ + #define AR_PHY_TURBO 0x9804 + #define AR_PHY_FC_TURBO_MODE 0x00000001 + #define AR_PHY_FC_TURBO_SHORT 0x00000002 +@@ -36,6 +42,9 @@ + + #define AR_PHY_TEST2 0x9808 + ++#define AR_PHY_TEST2_RX_OBS_SEL 0x3C00 ++#define AR_PHY_TEST2_RX_OBS_SEL_S 10 ++ + #define AR_PHY_TIMING2 0x9810 + #define AR_PHY_TIMING3 0x9814 + #define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 +@@ -393,6 +402,8 @@ + #define AR_PHY_RFBUS_GRANT 0x9C20 + #define AR_PHY_RFBUS_GRANT_EN 0x00000001 + ++#define AR_PHY_TST_ADC 0x9C24 ++ + #define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4 + #define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320 + diff --git a/package/kernel/mac80211/patches/ath/544-ath9k-ar933x-usb-hang-workaround.patch b/package/kernel/mac80211/patches/ath/544-ath9k-ar933x-usb-hang-workaround.patch new file mode 100644 index 0000000000..680bb6d590 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/544-ath9k-ar933x-usb-hang-workaround.patch @@ -0,0 +1,79 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -246,6 +246,19 @@ void ath9k_hw_get_channel_centers(struct + centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT); + } + ++static inline void ath9k_hw_disable_pll_lock_detect(struct ath_hw *ah) ++{ ++ /* On AR9330 and AR9340 devices, some PHY registers must be ++ * tuned to gain better stability/performance. These registers ++ * might be changed while doing wlan reset so the registers must ++ * be reprogrammed after each reset. ++ */ ++ REG_CLR_BIT(ah, AR_PHY_USB_CTRL1, BIT(20)); ++ REG_RMW(ah, AR_PHY_USB_CTRL2, ++ (1 << 21) | (0xf << 22), ++ (1 << 21) | (0x3 << 22)); ++} ++ + /******************/ + /* Chip Revisions */ + /******************/ +@@ -1414,6 +1427,9 @@ static bool ath9k_hw_set_reset(struct at + udelay(50); + } + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return true; + } + +@@ -1513,6 +1529,9 @@ static bool ath9k_hw_chip_reset(struct a + ar9003_hw_internal_regulator_apply(ah); + ath9k_hw_init_pll(ah, chan); + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return true; + } + +@@ -1820,8 +1839,14 @@ static int ath9k_hw_do_fastcc(struct ath + if (AR_SREV_9271(ah)) + ar9002_hw_load_ani_reg(ah, chan); + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return 0; + fail: ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return -EINVAL; + } + +@@ -2075,6 +2100,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st + ath9k_hw_set_radar_params(ah); + } + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return 0; + } + EXPORT_SYMBOL(ath9k_hw_reset); +--- a/drivers/net/wireless/ath/ath9k/phy.h ++++ b/drivers/net/wireless/ath/ath9k/phy.h +@@ -48,6 +48,9 @@ + #define AR_PHY_PLL_CONTROL 0x16180 + #define AR_PHY_PLL_MODE 0x16184 + ++#define AR_PHY_USB_CTRL1 0x16c84 ++#define AR_PHY_USB_CTRL2 0x16c88 ++ + enum ath9k_ant_div_comb_lna_conf { + ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2, + ATH_ANT_DIV_COMB_LNA2, diff --git a/package/kernel/mac80211/patches/ath/545-ath9k_ani_ws_detect.patch b/package/kernel/mac80211/patches/ath/545-ath9k_ani_ws_detect.patch new file mode 100644 index 0000000000..22a2308a0b --- /dev/null +++ b/package/kernel/mac80211/patches/ath/545-ath9k_ani_ws_detect.patch @@ -0,0 +1,155 @@ +--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c +@@ -951,55 +951,6 @@ static bool ar5008_hw_ani_control_new(st + * on == 0 means more noise imm + */ + u32 on = param ? 1 : 0; +- /* +- * make register setting for default +- * (weak sig detect ON) come from INI file +- */ +- int m1ThreshLow = on ? +- aniState->iniDef.m1ThreshLow : m1ThreshLow_off; +- int m2ThreshLow = on ? +- aniState->iniDef.m2ThreshLow : m2ThreshLow_off; +- int m1Thresh = on ? +- aniState->iniDef.m1Thresh : m1Thresh_off; +- int m2Thresh = on ? +- aniState->iniDef.m2Thresh : m2Thresh_off; +- int m2CountThr = on ? +- aniState->iniDef.m2CountThr : m2CountThr_off; +- int m2CountThrLow = on ? +- aniState->iniDef.m2CountThrLow : m2CountThrLow_off; +- int m1ThreshLowExt = on ? +- aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off; +- int m2ThreshLowExt = on ? +- aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off; +- int m1ThreshExt = on ? +- aniState->iniDef.m1ThreshExt : m1ThreshExt_off; +- int m2ThreshExt = on ? +- aniState->iniDef.m2ThreshExt : m2ThreshExt_off; +- +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M1_THRESH_LOW, +- m1ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2_THRESH_LOW, +- m2ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M1_THRESH, m1Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2_THRESH, m2Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2COUNT_THR, m2CountThr); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, +- m2CountThrLow); +- +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt); + + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -42,20 +42,6 @@ static const int cycpwrThr1_table[] = + /* level: 0 1 2 3 4 5 6 7 8 */ + { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */ + +-/* +- * register values to turn OFDM weak signal detection OFF +- */ +-static const int m1ThreshLow_off = 127; +-static const int m2ThreshLow_off = 127; +-static const int m1Thresh_off = 127; +-static const int m2Thresh_off = 127; +-static const int m2CountThr_off = 31; +-static const int m2CountThrLow_off = 63; +-static const int m1ThreshLowExt_off = 127; +-static const int m2ThreshLowExt_off = 127; +-static const int m1ThreshExt_off = 127; +-static const int m2ThreshExt_off = 127; +- + static const u8 ofdm2pwr[] = { + ALL_TARGET_LEGACY_6_24, + ALL_TARGET_LEGACY_6_24, +@@ -1095,11 +1081,6 @@ static bool ar9003_hw_ani_control(struct + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_channel *chan = ah->curchan; + struct ar5416AniState *aniState = &ah->ani; +- int m1ThreshLow, m2ThreshLow; +- int m1Thresh, m2Thresh; +- int m2CountThr, m2CountThrLow; +- int m1ThreshLowExt, m2ThreshLowExt; +- int m1ThreshExt, m2ThreshExt; + s32 value, value2; + + switch (cmd & ah->ani_function) { +@@ -1113,61 +1094,6 @@ static bool ar9003_hw_ani_control(struct + */ + u32 on = param ? 1 : 0; + +- if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) +- goto skip_ws_det; +- +- m1ThreshLow = on ? +- aniState->iniDef.m1ThreshLow : m1ThreshLow_off; +- m2ThreshLow = on ? +- aniState->iniDef.m2ThreshLow : m2ThreshLow_off; +- m1Thresh = on ? +- aniState->iniDef.m1Thresh : m1Thresh_off; +- m2Thresh = on ? +- aniState->iniDef.m2Thresh : m2Thresh_off; +- m2CountThr = on ? +- aniState->iniDef.m2CountThr : m2CountThr_off; +- m2CountThrLow = on ? +- aniState->iniDef.m2CountThrLow : m2CountThrLow_off; +- m1ThreshLowExt = on ? +- aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off; +- m2ThreshLowExt = on ? +- aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off; +- m1ThreshExt = on ? +- aniState->iniDef.m1ThreshExt : m1ThreshExt_off; +- m2ThreshExt = on ? +- aniState->iniDef.m2ThreshExt : m2ThreshExt_off; +- +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M1_THRESH_LOW, +- m1ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2_THRESH_LOW, +- m2ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M1_THRESH, +- m1Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2_THRESH, +- m2Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2COUNT_THR, +- m2CountThr); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, +- m2CountThrLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH_LOW, +- m1ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH_LOW, +- m2ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH, +- m1ThreshExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH, +- m2ThreshExt); +-skip_ws_det: + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); diff --git a/package/kernel/mac80211/patches/ath/547-ath9k_led_defstate_fix.patch b/package/kernel/mac80211/patches/ath/547-ath9k_led_defstate_fix.patch new file mode 100644 index 0000000000..5d84cf0c42 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/547-ath9k_led_defstate_fix.patch @@ -0,0 +1,29 @@ +From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl> +Date: Sun, 31 Jan 2016 20:48:49 +0100 +Subject: [PATCH v4 2/8] mac80211: ath9k: set default state for platform LEDs + +Support default state for platform LEDs connected to ath9k device. +Now LEDs are correctly set on or off at ath9k module initialization. +Very useful if power LED is connected to wireless chip. + +Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl> +--- + gpio.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -74,8 +74,11 @@ static int ath_add_led(struct ath_softc + ath9k_hw_gpio_request_out(sc->sc_ah, gpio->gpio, gpio->name, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + +- /* LED off */ +- ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low); ++ /* Set default LED state */ ++ if (gpio->default_state == LEDS_GPIO_DEFSTATE_ON) ++ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, !gpio->active_low); ++ else ++ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low); + + return 0; + } diff --git a/package/kernel/mac80211/patches/ath/548-ath9k_enable_gpio_chip.patch b/package/kernel/mac80211/patches/ath/548-ath9k_enable_gpio_chip.patch new file mode 100644 index 0000000000..0b76d330c6 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/548-ath9k_enable_gpio_chip.patch @@ -0,0 +1,242 @@ +From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl> +Date: Sun, 31 Jan 2016 21:01:31 +0100 +Subject: [PATCH v4 4/8] mac80211: ath9k: enable access to GPIO + +Enable access to GPIO chip and its pins for Atheros AR92xx +wireless devices. For now AR9285 and AR9287 are supported. + +Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl> +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -24,6 +24,7 @@ + #include <linux/completion.h> + #include <linux/time.h> + #include <linux/hw_random.h> ++#include <linux/gpio/driver.h> + + #include "common.h" + #include "debug.h" +@@ -1001,6 +1002,14 @@ struct ath_led { + struct led_classdev cdev; + }; + ++#ifdef CONFIG_GPIOLIB ++struct ath9k_gpio_chip { ++ struct ath_softc *sc; ++ char label[32]; ++ struct gpio_chip gchip; ++}; ++#endif ++ + struct ath_softc { + struct ieee80211_hw *hw; + struct device *dev; +@@ -1058,6 +1067,9 @@ struct ath_softc { + #ifdef CPTCFG_MAC80211_LEDS + const char *led_default_trigger; + struct list_head leds; ++#ifdef CONFIG_GPIOLIB ++ struct ath9k_gpio_chip *gpiochip; ++#endif + #endif + + #ifdef CPTCFG_ATH9K_DEBUGFS +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -16,13 +16,130 @@ + + #include "ath9k.h" + #include <linux/ath9k_platform.h> ++#include <linux/gpio.h> ++ ++#ifdef CPTCFG_MAC80211_LEDS ++ ++#ifdef CONFIG_GPIOLIB ++ ++/***************/ ++/* GPIO Chip */ ++/***************/ ++ ++/* gpio_chip handler : set GPIO to input */ ++static int ath9k_gpio_pin_cfg_input(struct gpio_chip *chip, unsigned offset) ++{ ++ struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip, ++ gchip); ++ ++ ath9k_hw_gpio_request_in(gc->sc->sc_ah, offset, "ath9k-gpio"); ++ ++ return 0; ++} ++ ++/* gpio_chip handler : set GPIO to output */ ++static int ath9k_gpio_pin_cfg_output(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip, ++ gchip); ++ ++ ath9k_hw_gpio_request_out(gc->sc->sc_ah, offset, "ath9k-gpio", ++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value); ++ ++ return 0; ++} ++ ++/* gpio_chip handler : query GPIO direction (0=out, 1=in) */ ++static int ath9k_gpio_pin_get_dir(struct gpio_chip *chip, unsigned offset) ++{ ++ struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip, ++ gchip); ++ struct ath_hw *ah = gc->sc->sc_ah; ++ ++ return !((REG_READ(ah, AR_GPIO_OE_OUT) >> (offset * 2)) & 3); ++} ++ ++/* gpio_chip handler : get GPIO pin value */ ++static int ath9k_gpio_pin_get(struct gpio_chip *chip, unsigned offset) ++{ ++ struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip, ++ gchip); ++ ++ return ath9k_hw_gpio_get(gc->sc->sc_ah, offset); ++} ++ ++/* gpio_chip handler : set GPIO pin to value */ ++static void ath9k_gpio_pin_set(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ struct ath9k_gpio_chip *gc = container_of(chip, struct ath9k_gpio_chip, ++ gchip); ++ ++ ath9k_hw_set_gpio(gc->sc->sc_ah, offset, value); ++} ++ ++/* register GPIO chip */ ++static void ath9k_register_gpio_chip(struct ath_softc *sc) ++{ ++ struct ath9k_gpio_chip *gc; ++ struct ath_hw *ah = sc->sc_ah; ++ ++ gc = kzalloc(sizeof(struct ath9k_gpio_chip), GFP_KERNEL); ++ if (!gc) ++ return; ++ ++ gc->sc = sc; ++ snprintf(gc->label, sizeof(gc->label), "ath9k-%s", ++ wiphy_name(sc->hw->wiphy)); ++ ++ gc->gchip.label = gc->label; ++ gc->gchip.base = -1; /* determine base automatically */ ++ gc->gchip.ngpio = ah->caps.num_gpio_pins; ++ gc->gchip.direction_input = ath9k_gpio_pin_cfg_input; ++ gc->gchip.direction_output = ath9k_gpio_pin_cfg_output; ++ gc->gchip.get_direction = ath9k_gpio_pin_get_dir; ++ gc->gchip.get = ath9k_gpio_pin_get; ++ gc->gchip.set = ath9k_gpio_pin_set; ++ ++ if (gpiochip_add(&gc->gchip)) { ++ kfree(gc); ++ return; ++ } ++ ++ sc->gpiochip = gc; ++} ++ ++/* remove GPIO chip */ ++static void ath9k_unregister_gpio_chip(struct ath_softc *sc) ++{ ++ struct ath9k_gpio_chip *gc = sc->gpiochip; ++ ++ if (!gc) ++ return; ++ ++ gpiochip_remove(&gc->gchip); ++ kfree(gc); ++ sc->gpiochip = NULL; ++} ++ ++#else /* CONFIG_GPIOLIB */ ++ ++static inline void ath9k_register_gpio_chip(struct ath_softc *sc) ++{ ++} ++ ++static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc) ++{ ++} ++ ++#endif /* CONFIG_GPIOLIB */ + + /********************************/ + /* LED functions */ + /********************************/ + +-#ifdef CPTCFG_MAC80211_LEDS +- + static void ath_fill_led_pin(struct ath_softc *sc) + { + struct ath_hw *ah = sc->sc_ah; +@@ -80,6 +197,12 @@ static int ath_add_led(struct ath_softc + else + ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low); + ++#ifdef CONFIG_GPIOLIB ++ /* If there is GPIO chip configured, reserve LED pin */ ++ if (sc->gpiochip) ++ gpio_request(sc->gpiochip->gchip.base + gpio->gpio, gpio->name); ++#endif ++ + return 0; + } + +@@ -136,17 +259,24 @@ void ath_deinit_leds(struct ath_softc *s + + while (!list_empty(&sc->leds)) { + led = list_first_entry(&sc->leds, struct ath_led, list); ++#ifdef CONFIG_GPIOLIB ++ /* If there is GPIO chip configured, free LED pin */ ++ if (sc->gpiochip) ++ gpio_free(sc->gpiochip->gchip.base + led->gpio->gpio); ++#endif + list_del(&led->list); + ath_led_brightness(&led->cdev, LED_OFF); + led_classdev_unregister(&led->cdev); + ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio); + kfree(led); + } ++ ath9k_unregister_gpio_chip(sc); + } + + void ath_init_leds(struct ath_softc *sc) + { + struct ath9k_platform_data *pdata = sc->dev->platform_data; ++ struct device_node *np = sc->dev->of_node; + char led_name[32]; + const char *trigger; + int i; +@@ -156,6 +286,15 @@ void ath_init_leds(struct ath_softc *sc) + if (AR_SREV_9100(sc->sc_ah)) + return; + ++ if (!np) ++ ath9k_register_gpio_chip(sc); ++ ++ /* setup gpio controller only if requested and skip the led_pin setup */ ++ if (of_property_read_bool(np, "gpio-controller")) { ++ ath9k_register_gpio_chip(sc); ++ return; ++ } ++ + ath_fill_led_pin(sc); + + if (pdata && pdata->leds && pdata->num_leds) +@@ -180,6 +319,7 @@ void ath_init_leds(struct ath_softc *sc) + ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, + !sc->sc_ah->config.led_active_high); + } ++ + #endif + + /*******************/ diff --git a/package/kernel/mac80211/patches/ath/549-ath9k_enable_gpio_buttons.patch b/package/kernel/mac80211/patches/ath/549-ath9k_enable_gpio_buttons.patch new file mode 100644 index 0000000000..e7282ab6b1 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/549-ath9k_enable_gpio_buttons.patch @@ -0,0 +1,143 @@ +From: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl> +Subject: [PATCH v5 5/8] mac80211: ath9k: enable GPIO buttons + +Enable platform-defined GPIO button support for ath9k device. +Key poller is activated for attached platform buttons. +Requires ath9k GPIO chip access. + +Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl> +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -1069,6 +1069,7 @@ struct ath_softc { + struct list_head leds; + #ifdef CONFIG_GPIOLIB + struct ath9k_gpio_chip *gpiochip; ++ struct platform_device *btnpdev; /* gpio-keys-polled */ + #endif + #endif + +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -17,6 +17,8 @@ + #include "ath9k.h" + #include <linux/ath9k_platform.h> + #include <linux/gpio.h> ++#include <linux/platform_device.h> ++#include <linux/gpio_keys.h> + + #ifdef CPTCFG_MAC80211_LEDS + +@@ -124,6 +126,67 @@ static void ath9k_unregister_gpio_chip(s + sc->gpiochip = NULL; + } + ++/******************/ ++/* GPIO Buttons */ ++/******************/ ++ ++/* add GPIO buttons */ ++static void ath9k_init_buttons(struct ath_softc *sc) ++{ ++ struct ath9k_platform_data *pdata = sc->dev->platform_data; ++ struct platform_device *pdev; ++ struct gpio_keys_platform_data gkpdata; ++ struct gpio_keys_button *bt; ++ int i; ++ ++ if (!sc->gpiochip) ++ return; ++ ++ if (!pdata || !pdata->btns || !pdata->num_btns) ++ return; ++ ++ bt = devm_kmemdup(sc->dev, pdata->btns, ++ pdata->num_btns * sizeof(struct gpio_keys_button), ++ GFP_KERNEL); ++ if (!bt) ++ return; ++ ++ for (i = 0; i < pdata->num_btns; i++) { ++ if (pdata->btns[i].gpio == sc->sc_ah->led_pin) ++ sc->sc_ah->led_pin = -1; ++ ++ ath9k_hw_gpio_request_in(sc->sc_ah, pdata->btns[i].gpio, ++ "ath9k-gpio"); ++ bt[i].gpio = sc->gpiochip->gchip.base + pdata->btns[i].gpio; ++ } ++ ++ memset(&gkpdata, 0, sizeof(struct gpio_keys_platform_data)); ++ gkpdata.buttons = bt; ++ gkpdata.nbuttons = pdata->num_btns; ++ gkpdata.poll_interval = pdata->btn_poll_interval; ++ ++ pdev = platform_device_register_data(sc->dev, "gpio-keys-polled", ++ PLATFORM_DEVID_AUTO, &gkpdata, ++ sizeof(gkpdata)); ++ if (!IS_ERR_OR_NULL(pdev)) ++ sc->btnpdev = pdev; ++ else { ++ sc->btnpdev = NULL; ++ devm_kfree(sc->dev, bt); ++ } ++} ++ ++/* remove GPIO buttons */ ++static void ath9k_deinit_buttons(struct ath_softc *sc) ++{ ++ if (!sc->gpiochip || !sc->btnpdev) ++ return; ++ ++ platform_device_unregister(sc->btnpdev); ++ ++ sc->btnpdev = NULL; ++} ++ + #else /* CONFIG_GPIOLIB */ + + static inline void ath9k_register_gpio_chip(struct ath_softc *sc) +@@ -134,6 +197,14 @@ static inline void ath9k_unregister_gpio + { + } + ++static inline void ath9k_init_buttons(struct ath_softc *sc) ++{ ++} ++ ++static inline void ath9k_deinit_buttons(struct ath_softc *sc) ++{ ++} ++ + #endif /* CONFIG_GPIOLIB */ + + /********************************/ +@@ -257,6 +328,7 @@ void ath_deinit_leds(struct ath_softc *s + { + struct ath_led *led; + ++ ath9k_deinit_buttons(sc); + while (!list_empty(&sc->leds)) { + led = list_first_entry(&sc->leds, struct ath_led, list); + #ifdef CONFIG_GPIOLIB +@@ -296,6 +368,7 @@ void ath_init_leds(struct ath_softc *sc) + } + + ath_fill_led_pin(sc); ++ ath9k_init_buttons(sc); + + if (pdata && pdata->leds && pdata->num_leds) + for (i = 0; i < pdata->num_leds; i++) { +--- a/include/linux/ath9k_platform.h ++++ b/include/linux/ath9k_platform.h +@@ -49,6 +49,10 @@ struct ath9k_platform_data { + + int num_leds; + const struct gpio_led *leds; ++ ++ unsigned num_btns; ++ const struct gpio_keys_button *btns; ++ unsigned btn_poll_interval; + }; + + #endif /* _LINUX_ATH9K_PLATFORM_H */ diff --git a/package/kernel/mac80211/patches/ath/550-ath9k-disable-bands-via-dt.patch b/package/kernel/mac80211/patches/ath/550-ath9k-disable-bands-via-dt.patch new file mode 100644 index 0000000000..55f040f170 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/550-ath9k-disable-bands-via-dt.patch @@ -0,0 +1,15 @@ +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -571,6 +571,12 @@ static int ath9k_of_init(struct ath_soft + + ath_dbg(common, CONFIG, "parsing configuration from OF node\n"); + ++ if (of_property_read_bool(np, "qca,disable-2ghz")) ++ ah->disable_2ghz = true; ++ ++ if (of_property_read_bool(np, "qca,disable-5ghz")) ++ ah->disable_5ghz = true; ++ + if (of_property_read_bool(np, "qca,no-eeprom")) { + /* ath9k-eeprom-<bus>-<id>.bin */ + scnprintf(eeprom_name, sizeof(eeprom_name), diff --git a/package/kernel/mac80211/patches/ath/551-ath9k_ubnt_uap_plus_hsr.patch b/package/kernel/mac80211/patches/ath/551-ath9k_ubnt_uap_plus_hsr.patch new file mode 100644 index 0000000000..82b8109e06 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/551-ath9k_ubnt_uap_plus_hsr.patch @@ -0,0 +1,418 @@ +--- a/drivers/net/wireless/ath/ath9k/channel.c ++++ b/drivers/net/wireless/ath/ath9k/channel.c +@@ -15,6 +15,8 @@ + */ + + #include "ath9k.h" ++#include <linux/ath9k_platform.h> ++#include "hsr.h" + + /* Set/change channels. If the channel is really being changed, it's done + * by reseting the chip. To accomplish this we must first cleanup any pending +@@ -22,6 +24,7 @@ + */ + static int ath_set_channel(struct ath_softc *sc) + { ++ struct ath9k_platform_data *pdata = sc->dev->platform_data; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hw *hw = sc->hw; +@@ -42,6 +45,11 @@ static int ath_set_channel(struct ath_so + ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", + chan->center_freq, chandef->width); + ++ if (pdata && pdata->ubnt_hsr) { ++ ath9k_hsr_enable(ah, chandef->width, chan->center_freq); ++ ath9k_hsr_status(ah); ++ } ++ + /* update survey stats for the old channel before switching */ + spin_lock_irqsave(&common->cc_lock, flags); + ath_update_survey_stats(sc); +--- /dev/null ++++ b/drivers/net/wireless/ath/ath9k/hsr.c +@@ -0,0 +1,247 @@ ++/* ++ * ++ * The MIT License (MIT) ++ * ++ * Copyright (c) 2015 Kirill Berezin ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ * ++ */ ++ ++#include <linux/io.h> ++#include <linux/slab.h> ++#include <linux/module.h> ++#include <linux/time.h> ++#include <linux/bitops.h> ++#include <linux/etherdevice.h> ++#include <linux/rtnetlink.h> ++#include <asm/unaligned.h> ++ ++#include "hw.h" ++#include "ath9k.h" ++ ++#define HSR_GPIO_CSN 8 ++#define HSR_GPIO_CLK 6 ++#define HSR_GPIO_DOUT 7 ++#define HSR_GPIO_DIN 5 ++ ++/* delays are in useconds */ ++#define HSR_DELAY_HALF_TICK 100 ++#define HSR_DELAY_PRE_WRITE 75 ++#define HSR_DELAY_FINAL 20000 ++#define HSR_DELAY_TRAILING 200 ++ ++void ath9k_hsr_init(struct ath_hw *ah) ++{ ++ ath9k_hw_gpio_request_in(ah, HSR_GPIO_DIN, NULL); ++ ath9k_hw_gpio_request_out(ah, HSR_GPIO_CSN, NULL, ++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ath9k_hw_gpio_request_out(ah, HSR_GPIO_CLK, NULL, ++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ath9k_hw_gpio_request_out(ah, HSR_GPIO_DOUT, NULL, ++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); ++ ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0); ++ ++ udelay(HSR_DELAY_TRAILING); ++} ++ ++static u32 ath9k_hsr_write_byte(struct ath_hw *ah, int delay, u32 value) ++{ ++ struct ath_common *common = ath9k_hw_common(ah); ++ int i; ++ u32 rval = 0; ++ ++ udelay(delay); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ for (i = 0; i < 8; ++i) { ++ rval = rval << 1; ++ ++ /* pattern is left to right, that is 7-th bit runs first */ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); ++ udelay(HSR_DELAY_HALF_TICK); ++ } ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ ath_dbg(common, CONFIG, "ath9k_hsr_write_byte: write byte %d return value is %d %c\n", ++ value, rval, rval > 32 ? rval : '-'); ++ ++ return rval & 0xff; ++} ++ ++static int ath9k_hsr_write_a_chain(struct ath_hw *ah, char *chain, int items) ++{ ++ int status = 0; ++ int i = 0; ++ int err; ++ ++ /* a preamble */ ++ ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ ++ /* clear HSR's reply buffer */ ++ if (status) { ++ int loop = 0; ++ ++ for (loop = 0; (loop < 42) && status; ++loop) ++ status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, ++ 0); ++ ++ if (loop >= 42) { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_write_a_chain: can't clear an output buffer after a 42 cycles.\n"); ++ return -1; ++ } ++ } ++ ++ for (i = 0; (i < items) && (chain[i] != 0); ++i) ++ ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]); ++ ++ ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ mdelay(HSR_DELAY_FINAL / 1000); ++ ++ /* reply */ ++ memset(chain, 0, items); ++ ++ ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ udelay(HSR_DELAY_TRAILING); ++ ++ for (i = 0; i < (items - 1); ++i) { ++ u32 ret; ++ ++ ret = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ if (ret != 0) ++ chain[i] = (char)ret; ++ else ++ break; ++ ++ udelay(HSR_DELAY_TRAILING); ++ } ++ ++ if (i <= 1) ++ return 0; ++ ++ err = kstrtoint(chain + 1, 10, &i); ++ if (err) ++ return err; ++ ++ return i; ++} ++ ++int ath9k_hsr_disable(struct ath_hw *ah) ++{ ++ char cmd[10] = {'b', '4', '0', 0, 0, 0, 0, 0, 0, 0}; ++ int ret; ++ ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ((ret > 0) && (*cmd == 'B')) ++ return 0; ++ ++ return -1; ++} ++ ++int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq) ++{ ++ char cmd[10]; ++ int ret; ++ ++ /* Bandwidth argument is 0 sometimes. Assume default 802.11bgn ++ * 20MHz on invalid values ++ */ ++ if ((bw != 5) && (bw != 10) && (bw != 20) && (bw != 40)) ++ bw = 20; ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'b'; ++ snprintf(cmd + 1, 3, "%02d", bw); ++ ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ((*cmd != 'B') || (ret != bw)) { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_enable: failed changing bandwidth -> set (%d,%d) reply (%d, %d)\n", ++ 'b', bw, *cmd, ret); ++ return -1; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'x'; ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if (*cmd != 'X') { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_enable: failed 'x' command -> reply (%d, %d)\n", ++ *cmd, ret); ++ return -1; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'm'; ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if (*cmd != 'M') { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_enable: failed 'm' command -> reply (%d, %d)\n", ++ *cmd, ret); ++ return -1; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'f'; ++ snprintf(cmd + 1, 6, "%05d", fq); ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ((*cmd != 'F') && (ret != fq)) { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_enable: failed set frequency -> reply (%d, %d)\n", ++ *cmd, ret); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int ath9k_hsr_status(struct ath_hw *ah) ++{ ++ char cmd[10] = {'s', 0, 0, 0, 0, 0, 0, 0, 0, 0}; ++ int ret; ++ ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if (*cmd != 'S') { ++ ATH_DBG_WARN(1, "ath9k_hsr_status: returned %d,%d\n", *cmd, ++ ret); ++ return -1; ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/net/wireless/ath/ath9k/hsr.h +@@ -0,0 +1,48 @@ ++/* ++ * The MIT License (MIT) ++ * ++ * Copyright (c) 2015 Kirill Berezin ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef HSR_H ++#define HSR_H ++ ++#ifdef CPTCFG_ATH9K_UBNTHSR ++ ++void ath9k_hsr_init(struct ath_hw *ah); ++int ath9k_hsr_disable(struct ath_hw *ah); ++int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq); ++int ath9k_hsr_status(struct ath_hw *ah); ++ ++#else ++static inline void ath9k_hsr_init(struct ath_hw *ah) {} ++ ++static inline int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq) ++{ ++ return 0; ++} ++ ++static inline int ath9k_hsr_disable(struct ath_hw *ah) { return 0; } ++static inline int ath9k_hsr_status(struct ath_hw *ah) { return 0; } ++ ++#endif ++ ++#endif /* HSR_H */ +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -16,8 +16,10 @@ + + #include <linux/nl80211.h> + #include <linux/delay.h> ++#include <linux/ath9k_platform.h> + #include "ath9k.h" + #include "btcoex.h" ++#include "hsr.h" + + u8 ath9k_parse_mpdudensity(u8 mpdudensity) + { +@@ -649,6 +651,7 @@ void ath_reset_work(struct work_struct * + static int ath9k_start(struct ieee80211_hw *hw) + { + struct ath_softc *sc = hw->priv; ++ struct ath9k_platform_data *pdata = sc->dev->platform_data; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan; +@@ -727,6 +730,11 @@ static int ath9k_start(struct ieee80211_ + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + } + ++ if (pdata && pdata->ubnt_hsr) { ++ ath9k_hsr_init(ah); ++ ath9k_hsr_disable(ah); ++ } ++ + /* + * Reset key cache to sane defaults (all entries cleared) instead of + * semi-random values after suspend/resume. +--- a/drivers/net/wireless/ath/ath9k/Makefile ++++ b/drivers/net/wireless/ath/ath9k/Makefile +@@ -16,6 +16,7 @@ ath9k-$(CPTCFG_ATH9K_DFS_CERTIFIED) += d + ath9k-$(CPTCFG_ATH9K_TX99) += tx99.o + ath9k-$(CPTCFG_ATH9K_WOW) += wow.o + ath9k-$(CPTCFG_ATH9K_HWRNG) += rng.o ++ath9k-$(CPTCFG_ATH9K_UBNTHSR) += hsr.o + + ath9k-$(CPTCFG_ATH9K_DEBUGFS) += debug.o + +--- a/include/linux/ath9k_platform.h ++++ b/include/linux/ath9k_platform.h +@@ -53,6 +53,8 @@ struct ath9k_platform_data { + unsigned num_btns; + const struct gpio_keys_button *btns; + unsigned btn_poll_interval; ++ ++ bool ubnt_hsr; + }; + + #endif /* _LINUX_ATH9K_PLATFORM_H */ +--- a/local-symbols ++++ b/local-symbols +@@ -114,6 +114,7 @@ ATH9K_WOW= + ATH9K_RFKILL= + ATH9K_CHANNEL_CONTEXT= + ATH9K_PCOEM= ++ATH9K_UBNTHSR= + ATH9K_HTC= + ATH9K_HTC_DEBUGFS= + ATH9K_HWRNG= +--- a/drivers/net/wireless/ath/ath9k/Kconfig ++++ b/drivers/net/wireless/ath/ath9k/Kconfig +@@ -59,6 +59,19 @@ config ATH9K_AHB + Say Y, if you have a SoC with a compatible built-in + wireless MAC. Say N if unsure. + ++config ATH9K_UBNTHSR ++ bool "Ubiquiti UniFi Outdoor Plus HSR support" ++ depends on ATH9K ++ ---help--- ++ This options enables code to control the HSR RF ++ filter in the receive path of the Ubiquiti UniFi ++ Outdoor Plus access point. ++ ++ Say Y if you want to use the access point. The ++ code will only be used if the device is detected, ++ so it does not harm other setup other than occupying ++ a bit of memory. ++ + config ATH9K_DEBUGFS + bool "Atheros ath9k debugging" + depends on ATH9K && DEBUG_FS diff --git a/package/kernel/mac80211/patches/ath/552-ahb_of.patch b/package/kernel/mac80211/patches/ath/552-ahb_of.patch new file mode 100644 index 0000000000..8c20b00dd4 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/552-ahb_of.patch @@ -0,0 +1,330 @@ +--- a/drivers/net/wireless/ath/ath9k/ahb.c ++++ b/drivers/net/wireless/ath/ath9k/ahb.c +@@ -19,7 +19,15 @@ + #include <linux/nl80211.h> + #include <linux/platform_device.h> + #include <linux/module.h> ++#include <linux/of_device.h> + #include "ath9k.h" ++#include <linux/ath9k_platform.h> ++ ++#ifdef CONFIG_OF ++#include <asm/mach-ath79/ath79.h> ++#include <asm/mach-ath79/ar71xx_regs.h> ++#include <linux/mtd/mtd.h> ++#endif + + static const struct platform_device_id ath9k_platform_id_table[] = { + { +@@ -68,6 +76,235 @@ static const struct ath_bus_ops ath_ahb_ + .eeprom_read = ath_ahb_eeprom_read, + }; + ++#ifdef CONFIG_OF ++ ++#define QCA955X_DDR_CTL_CONFIG 0x108 ++#define QCA955X_DDR_CTL_CONFIG_ACT_WMAC BIT(23) ++ ++static int of_get_wifi_cal(struct device_node *np, struct ath9k_platform_data *pdata) ++{ ++#ifdef CONFIG_MTD ++ struct device_node *mtd_np = NULL; ++ size_t retlen; ++ int size, ret; ++ struct mtd_info *mtd; ++ const char *part; ++ const __be32 *list; ++ phandle phandle; ++ ++ list = of_get_property(np, "mtd-cal-data", &size); ++ if (!list) ++ return 0; ++ ++ if (size != (2 * sizeof(*list))) ++ return 1; ++ ++ phandle = be32_to_cpup(list++); ++ if (phandle) ++ mtd_np = of_find_node_by_phandle(phandle); ++ ++ if (!mtd_np) ++ return 1; ++ ++ part = of_get_property(mtd_np, "label", NULL); ++ if (!part) ++ part = mtd_np->name; ++ ++ mtd = get_mtd_device_nm(part); ++ if (IS_ERR(mtd)) ++ return 1; ++ ++ ret = mtd_read(mtd, be32_to_cpup(list), sizeof(pdata->eeprom_data), ++ &retlen, (u8*)pdata->eeprom_data); ++ put_mtd_device(mtd); ++ ++#endif ++ return 0; ++} ++ ++static int ar913x_wmac_reset(void) ++{ ++ ath79_device_reset_set(AR913X_RESET_AMBA2WMAC); ++ mdelay(10); ++ ++ ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC); ++ mdelay(10); ++ ++ return 0; ++} ++ ++static int ar933x_wmac_reset(void) ++{ ++ int retries = 20; ++ ++ ath79_device_reset_set(AR933X_RESET_WMAC); ++ ath79_device_reset_clear(AR933X_RESET_WMAC); ++ ++ while (1) { ++ u32 bootstrap; ++ ++ bootstrap = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); ++ if ((bootstrap & AR933X_BOOTSTRAP_EEPBUSY) == 0) ++ return 0; ++ ++ if (retries-- == 0) ++ break; ++ ++ udelay(10000); ++ } ++ ++ pr_err("ar933x: WMAC reset timed out"); ++ return -ETIMEDOUT; ++} ++ ++static int qca955x_wmac_reset(void) ++{ ++ int i; ++ ++ /* Try to wait for WMAC DDR activity to stop */ ++ for (i = 0; i < 10; i++) { ++ if (!(__raw_readl(ath79_ddr_base + QCA955X_DDR_CTL_CONFIG) & ++ QCA955X_DDR_CTL_CONFIG_ACT_WMAC)) ++ break; ++ ++ udelay(10); ++ } ++ ++ ath79_device_reset_set(QCA955X_RESET_RTC); ++ udelay(10); ++ ath79_device_reset_clear(QCA955X_RESET_RTC); ++ udelay(10); ++ ++ return 0; ++} ++ ++enum { ++ AR913X_WMAC = 0, ++ AR933X_WMAC, ++ AR934X_WMAC, ++ QCA953X_WMAC, ++ QCA955X_WMAC, ++ QCA956X_WMAC, ++}; ++ ++static int ar9330_get_soc_revision(void) ++{ ++ if (ath79_soc_rev == 1) ++ return ath79_soc_rev; ++ ++ return 0; ++} ++ ++static int ath79_get_soc_revision(void) ++{ ++ return ath79_soc_rev; ++} ++ ++static const struct of_ath_ahb_data { ++ u16 dev_id; ++ u32 bootstrap_reg; ++ u32 bootstrap_ref; ++ ++ int (*soc_revision)(void); ++ int (*wmac_reset)(void); ++} of_ath_ahb_data[] = { ++ [AR913X_WMAC] = { ++ .dev_id = AR5416_AR9100_DEVID, ++ .wmac_reset = ar913x_wmac_reset, ++ ++ }, ++ [AR933X_WMAC] = { ++ .dev_id = AR9300_DEVID_AR9330, ++ .bootstrap_reg = AR933X_RESET_REG_BOOTSTRAP, ++ .bootstrap_ref = AR933X_BOOTSTRAP_REF_CLK_40, ++ .soc_revision = ar9330_get_soc_revision, ++ .wmac_reset = ar933x_wmac_reset, ++ }, ++ [AR934X_WMAC] = { ++ .dev_id = AR9300_DEVID_AR9340, ++ .bootstrap_reg = AR934X_RESET_REG_BOOTSTRAP, ++ .bootstrap_ref = AR934X_BOOTSTRAP_REF_CLK_40, ++ .soc_revision = ath79_get_soc_revision, ++ }, ++ [QCA953X_WMAC] = { ++ .dev_id = AR9300_DEVID_AR953X, ++ .bootstrap_reg = QCA953X_RESET_REG_BOOTSTRAP, ++ .bootstrap_ref = QCA953X_BOOTSTRAP_REF_CLK_40, ++ .soc_revision = ath79_get_soc_revision, ++ }, ++ [QCA955X_WMAC] = { ++ .dev_id = AR9300_DEVID_QCA955X, ++ .bootstrap_reg = QCA955X_RESET_REG_BOOTSTRAP, ++ .bootstrap_ref = QCA955X_BOOTSTRAP_REF_CLK_40, ++ .wmac_reset = qca955x_wmac_reset, ++ }, ++ [QCA956X_WMAC] = { ++ .dev_id = AR9300_DEVID_QCA956X, ++ .bootstrap_reg = QCA956X_RESET_REG_BOOTSTRAP, ++ .bootstrap_ref = QCA956X_BOOTSTRAP_REF_CLK_40, ++ .soc_revision = ath79_get_soc_revision, ++ }, ++}; ++ ++const struct of_device_id of_ath_ahb_match[] = { ++ { .compatible = "qca,ar9130-wmac", .data = &of_ath_ahb_data[AR913X_WMAC] }, ++ { .compatible = "qca,ar9330-wmac", .data = &of_ath_ahb_data[AR933X_WMAC] }, ++ { .compatible = "qca,ar9340-wmac", .data = &of_ath_ahb_data[AR934X_WMAC] }, ++ { .compatible = "qca,qca9530-wmac", .data = &of_ath_ahb_data[QCA953X_WMAC] }, ++ { .compatible = "qca,qca9550-wmac", .data = &of_ath_ahb_data[QCA955X_WMAC] }, ++ { .compatible = "qca,qca9560-wmac", .data = &of_ath_ahb_data[QCA956X_WMAC] }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, of_ath_ahb_match); ++ ++static int of_ath_ahb_probe(struct platform_device *pdev) ++{ ++ struct ath9k_platform_data *pdata; ++ const struct of_device_id *match; ++ const struct of_ath_ahb_data *data; ++ u8 led_pin; ++ ++ match = of_match_device(of_ath_ahb_match, &pdev->dev); ++ data = (const struct of_ath_ahb_data *)match->data; ++ ++ pdata = dev_get_platdata(&pdev->dev); ++ ++ if (!of_property_read_u8(pdev->dev.of_node, "qca,led-pin", &led_pin)) ++ pdata->led_pin = led_pin; ++ else ++ pdata->led_pin = -1; ++ ++ if (of_property_read_bool(pdev->dev.of_node, "qca,disable-2ghz")) ++ pdata->disable_2ghz = true; ++ ++ if (of_property_read_bool(pdev->dev.of_node, "qca,disable-5ghz")) ++ pdata->disable_5ghz = true; ++ ++ if (of_property_read_bool(pdev->dev.of_node, "qca,tx-gain-buffalo")) ++ pdata->tx_gain_buffalo = true; ++ ++ if (data->wmac_reset) { ++ data->wmac_reset(); ++ pdata->external_reset = data->wmac_reset; ++ } ++ ++ if (data->bootstrap_reg && data->bootstrap_ref) { ++ u32 t = ath79_reset_rr(data->bootstrap_reg); ++ if (t & data->bootstrap_ref) ++ pdata->is_clk_25mhz = false; ++ else ++ pdata->is_clk_25mhz = true; ++ } ++ ++ pdata->get_mac_revision = data->soc_revision; ++ ++ if (of_get_wifi_cal(pdev->dev.of_node, pdata)) ++ dev_err(&pdev->dev, "failed to load calibration data from mtd device\n"); ++ ++ return data->dev_id; ++} ++#endif ++ + static int ath_ahb_probe(struct platform_device *pdev) + { + void __iomem *mem; +@@ -79,6 +316,17 @@ static int ath_ahb_probe(struct platform + int ret = 0; + struct ath_hw *ah; + char hw_name[64]; ++ u16 dev_id; ++ ++ if (id) ++ dev_id = id->driver_data; ++ ++#ifdef CONFIG_OF ++ if (pdev->dev.of_node) ++ pdev->dev.platform_data = devm_kzalloc(&pdev->dev, ++ sizeof(struct ath9k_platform_data), ++ GFP_KERNEL); ++#endif + + if (!dev_get_platdata(&pdev->dev)) { + dev_err(&pdev->dev, "no platform data specified\n"); +@@ -121,13 +369,16 @@ static int ath_ahb_probe(struct platform + sc->mem = mem; + sc->irq = irq; + ++#ifdef CONFIG_OF ++ dev_id = of_ath_ahb_probe(pdev); ++#endif + ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); + if (ret) { + dev_err(&pdev->dev, "request_irq failed\n"); + goto err_free_hw; + } + +- ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops); ++ ret = ath9k_init_device(dev_id, sc, &ath_ahb_bus_ops); + if (ret) { + dev_err(&pdev->dev, "failed to initialize device\n"); + goto err_irq; +@@ -158,6 +409,9 @@ static int ath_ahb_remove(struct platfor + free_irq(sc->irq, sc); + ieee80211_free_hw(sc->hw); + } ++#ifdef CONFIG_OF ++ pdev->dev.platform_data = NULL; ++#endif + + return 0; + } +@@ -167,6 +421,9 @@ static struct platform_driver ath_ahb_dr + .remove = ath_ahb_remove, + .driver = { + .name = "ath9k", ++#ifdef CONFIG_OF ++ .of_match_table = of_ath_ahb_match, ++#endif + }, + .id_table = ath9k_platform_id_table, + }; +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -25,6 +25,7 @@ + #include <linux/time.h> + #include <linux/hw_random.h> + #include <linux/gpio/driver.h> ++#include <linux/reset.h> + + #include "common.h" + #include "debug.h" +@@ -1023,6 +1024,9 @@ struct ath_softc { + struct ath_hw *sc_ah; + void __iomem *mem; + int irq; ++#ifdef CONFIG_OF ++ struct reset_control *reset; ++#endif + spinlock_t sc_serial_rw; + spinlock_t sc_pm_lock; + spinlock_t sc_pcu_lock; diff --git a/package/kernel/mac80211/patches/ath/921-ath10k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/ath/921-ath10k_init_devices_synchronously.patch new file mode 100644 index 0000000000..fbf33a213c --- /dev/null +++ b/package/kernel/mac80211/patches/ath/921-ath10k_init_devices_synchronously.patch @@ -0,0 +1,33 @@ +From: Sven Eckelmann <sven@open-mesh.com> +Date: Tue, 18 Nov 2014 12:29:28 +0100 +Subject: [PATCH] ath10k: Don't initialize devices asynchronously + +OpenWrt requires all PHYs to be initialized to create the configuration files +during bootup. ath10k violates this because it delays the creation of the PHY +to a not well defined point in the future. + +Forcing the work to be done immediately works around this problem but may also +delay the boot when firmware images cannot be found. + +Signed-off-by: Sven Eckelmann <sven@open-mesh.com> +--- + +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -2507,6 +2507,16 @@ int ath10k_core_register(struct ath10k * + ar->chip_id = chip_id; + queue_work(ar->workqueue, &ar->register_work); + ++ /* OpenWrt requires all PHYs to be initialized to create the ++ * configuration files during bootup. ath10k violates this ++ * because it delays the creation of the PHY to a not well defined ++ * point in the future. ++ * ++ * Forcing the work to be done immediately works around this problem ++ * but may also delay the boot when firmware images cannot be found. ++ */ ++ flush_workqueue(ar->workqueue); ++ + return 0; + } + EXPORT_SYMBOL(ath10k_core_register); diff --git a/package/kernel/mac80211/patches/ath/930-ath10k_add_tpt_led_trigger.patch b/package/kernel/mac80211/patches/ath/930-ath10k_add_tpt_led_trigger.patch new file mode 100644 index 0000000000..9df4696913 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/930-ath10k_add_tpt_led_trigger.patch @@ -0,0 +1,37 @@ +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -8122,6 +8122,21 @@ static int ath10k_mac_init_rd(struct ath + return 0; + } + ++#ifdef CPTCFG_MAC80211_LEDS ++static const struct ieee80211_tpt_blink ath10k_tpt_blink[] = { ++ { .throughput = 0 * 1024, .blink_time = 334 }, ++ { .throughput = 1 * 1024, .blink_time = 260 }, ++ { .throughput = 2 * 1024, .blink_time = 220 }, ++ { .throughput = 5 * 1024, .blink_time = 190 }, ++ { .throughput = 10 * 1024, .blink_time = 170 }, ++ { .throughput = 25 * 1024, .blink_time = 150 }, ++ { .throughput = 54 * 1024, .blink_time = 130 }, ++ { .throughput = 120 * 1024, .blink_time = 110 }, ++ { .throughput = 265 * 1024, .blink_time = 80 }, ++ { .throughput = 586 * 1024, .blink_time = 50 }, ++}; ++#endif ++ + int ath10k_mac_register(struct ath10k *ar) + { + static const u32 cipher_suites[] = { +@@ -8397,6 +8412,12 @@ int ath10k_mac_register(struct ath10k *a + + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + ++#ifdef CPTCFG_MAC80211_LEDS ++ ieee80211_create_tpt_led_trigger(ar->hw, ++ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath10k_tpt_blink, ++ ARRAY_SIZE(ath10k_tpt_blink)); ++#endif ++ + ret = ieee80211_register_hw(ar->hw); + if (ret) { + ath10k_err(ar, "failed to register ieee80211: %d\n", ret); diff --git a/package/kernel/mac80211/patches/ath/936-ath10k-fix-otp-failure-result.patch b/package/kernel/mac80211/patches/ath/936-ath10k-fix-otp-failure-result.patch new file mode 100644 index 0000000000..e1aaefd035 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/936-ath10k-fix-otp-failure-result.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -783,7 +783,7 @@ static int ath10k_core_get_board_id_from + if (ret) { + ath10k_err(ar, "could not execute otp for board id check: %d\n", + ret); +- return ret; ++ return -EOPNOTSUPP; + } + + board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP); diff --git a/package/kernel/mac80211/patches/ath/960-0010-ath10k-limit-htt-rx-ring-size.patch b/package/kernel/mac80211/patches/ath/960-0010-ath10k-limit-htt-rx-ring-size.patch new file mode 100644 index 0000000000..5f4d34896d --- /dev/null +++ b/package/kernel/mac80211/patches/ath/960-0010-ath10k-limit-htt-rx-ring-size.patch @@ -0,0 +1,13 @@ +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/htt.h +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/htt.h ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/htt.h +@@ -238,7 +238,7 @@ enum htt_rx_ring_flags { + }; + + #define HTT_RX_RING_SIZE_MIN 128 +-#define HTT_RX_RING_SIZE_MAX 2048 ++#define HTT_RX_RING_SIZE_MAX 512 + #define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX + #define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1) + #define HTT_RX_RING_FILL_LEVEL_DUAL_MAC (HTT_RX_RING_SIZE - 1) diff --git a/package/kernel/mac80211/patches/ath/960-0011-ath10k-limit-pci-buffer-size.patch b/package/kernel/mac80211/patches/ath/960-0011-ath10k-limit-pci-buffer-size.patch new file mode 100644 index 0000000000..a101282d07 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/960-0011-ath10k-limit-pci-buffer-size.patch @@ -0,0 +1,38 @@ +--- a/drivers/net/wireless/ath/ath10k/pci.c ++++ b/drivers/net/wireless/ath/ath10k/pci.c +@@ -128,7 +128,7 @@ static struct ce_attr host_ce_config_wla + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, +- .dest_nentries = 512, ++ .dest_nentries = 128, + .recv_cb = ath10k_pci_htt_htc_rx_cb, + }, + +@@ -137,7 +137,7 @@ static struct ce_attr host_ce_config_wla + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, +- .dest_nentries = 128, ++ .dest_nentries = 64, + .recv_cb = ath10k_pci_htc_rx_cb, + }, + +@@ -164,7 +164,7 @@ static struct ce_attr host_ce_config_wla + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 512, +- .dest_nentries = 512, ++ .dest_nentries = 128, + .recv_cb = ath10k_pci_htt_rx_cb, + }, + +@@ -189,7 +189,7 @@ static struct ce_attr host_ce_config_wla + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, +- .dest_nentries = 128, ++ .dest_nentries = 96, + .recv_cb = ath10k_pci_pktlog_rx_cb, + }, + diff --git a/package/kernel/mac80211/patches/ath/972-ath10k_fix-crash-due-to-wrong-handling-of-peer_bw_rxnss_override-parameter.patch b/package/kernel/mac80211/patches/ath/972-ath10k_fix-crash-due-to-wrong-handling-of-peer_bw_rxnss_override-parameter.patch new file mode 100644 index 0000000000..a7eb0a0d84 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/972-ath10k_fix-crash-due-to-wrong-handling-of-peer_bw_rxnss_override-parameter.patch @@ -0,0 +1,144 @@ +From: Sebastian Gottschall <s.gottschall@dd-wrt.com> + +current handling of peer_bw_rxnss_override parameter is based on guessing the VHT160/8080 capability by rx rate. this is wrong and may lead +to a non initialized peer_bw_rxnss_override parameter which is required since VHT160 operation mode only supports 2x2 chainmasks in addition the original code +initialized the parameter with wrong masked values. +This patch uses the peer phymode and peer nss information for correct initialisation of the peer_bw_rxnss_override parameter. +if this peer information is not available, we initialize the parameter by minimum nss which is suggested by QCA as temporary workaround according +to the QCA sourcecodes. + +Signed-off-by: Sebastian Gottschall <s.gottschall@dd-wrt.com> + +v2: remove debug messages +v3: apply some cosmetics, update documentation +v4: fix compile warning and truncate nss to maximum of 2x2 since current chipsets only support 2x2 at vht160 +v5: handle maximum nss for chipsets supportig vht160 with 1x1 only +v7: use more simple code variant and take care about hw/sw chainmask configuration +v8: fix some code style issues +v9: use SM/MS macros from code.h to simplify shift/mask handling +--- + drivers/net/wireless/ath/ath10k/mac.c | 54 +++++++++++++++++++-------- + drivers/net/wireless/ath/ath10k/wmi.c | 7 +--- + drivers/net/wireless/ath/ath10k/wmi.h | 14 ++++++- + 3 files changed, 52 insertions(+), 23 deletions(-) +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -2466,7 +2466,7 @@ static void ath10k_peer_assoc_h_vht(stru + const u16 *vht_mcs_mask; + u8 ampdu_factor; + u8 max_nss, vht_mcs; +- int i; ++ int i, nss160; + + if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) + return; +@@ -2526,23 +2526,45 @@ static void ath10k_peer_assoc_h_vht(stru + __le16_to_cpu(vht_cap->vht_mcs.tx_highest); + arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit( + __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask); ++ arg->peer_bw_rxnss_override = 0; ++ nss160 = 1; /* 1x1 default config for VHT160 */ + +- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", +- sta->addr, arg->peer_max_mpdu, arg->peer_flags); ++ /* only local 4x4 configuration do support 2x2 for VHT160, ++ * everything else must use 1x1 ++ */ + +- if (arg->peer_vht_rates.rx_max_rate && +- (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) { +- switch (arg->peer_vht_rates.rx_max_rate) { +- case 1560: +- /* Must be 2x2 at 160Mhz is all it can do. */ +- arg->peer_bw_rxnss_override = 2; +- break; +- case 780: +- /* Can only do 1x1 at 160Mhz (Long Guard Interval) */ +- arg->peer_bw_rxnss_override = 1; +- break; +- } ++ if (ar->cfg_rx_chainmask == 15) ++ nss160 = arg->peer_num_spatial_streams <= 2 ? 1 : 2; ++ ++ /* if peer provides 1x1 nss160 information using max rate ++ * vht information, we reduce local nss160 to 1x1. ++ * consider that it has been observed that some client ++ * devices provide zero here, no matter which transmission ++ * rate is possible. in that case the local nss configuration ++ * will be used at maxmimum configuration possible. (see above) ++ */ ++ ++ if (arg->peer_vht_rates.rx_max_rate == 780) ++ nss160 = 1; ++ ++ /* in case if peer is connected with vht160 or vht80+80, ++ * we need to properly adjust rxnss parameters otherwise ++ * firmware will raise a assert ++ */ ++ switch (arg->peer_phymode) { ++ case MODE_11AC_VHT80_80: ++ arg->peer_bw_rxnss_override = BW_NSS_FWCONF_80_80(nss160); ++ /* fall through */ ++ case MODE_11AC_VHT160: ++ arg->peer_bw_rxnss_override |= BW_NSS_FWCONF_160(nss160); ++ break; ++ default: ++ break; + } ++ ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x peer_bw_rxnss_override 0x%x\n", ++ sta->addr, arg->peer_max_mpdu, arg->peer_flags, ++ arg->peer_bw_rxnss_override); + } + + static void ath10k_peer_assoc_h_qos(struct ath10k *ar, +@@ -2694,9 +2716,9 @@ static int ath10k_peer_assoc_prepare(str + ath10k_peer_assoc_h_crypto(ar, vif, sta, arg); + ath10k_peer_assoc_h_rates(ar, vif, sta, arg); + ath10k_peer_assoc_h_ht(ar, vif, sta, arg); ++ ath10k_peer_assoc_h_phymode(ar, vif, sta, arg); + ath10k_peer_assoc_h_vht(ar, vif, sta, arg); + ath10k_peer_assoc_h_qos(ar, vif, sta, arg); +- ath10k_peer_assoc_h_phymode(ar, vif, sta, arg); + + return 0; + } +--- a/drivers/net/wireless/ath/ath10k/wmi.c ++++ b/drivers/net/wireless/ath/ath10k/wmi.c +@@ -7231,12 +7231,7 @@ ath10k_wmi_peer_assoc_fill_10_4(struct a + struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf; + + ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg); +- if (arg->peer_bw_rxnss_override) +- cmd->peer_bw_rxnss_override = +- __cpu_to_le32((arg->peer_bw_rxnss_override - 1) | +- BIT(PEER_BW_RXNSS_OVERRIDE_OFFSET)); +- else +- cmd->peer_bw_rxnss_override = 0; ++ cmd->peer_bw_rxnss_override = __cpu_to_le32(arg->peer_bw_rxnss_override); + } + + static int +--- a/drivers/net/wireless/ath/ath10k/wmi.h ++++ b/drivers/net/wireless/ath/ath10k/wmi.h +@@ -6306,7 +6306,19 @@ struct wmi_10_2_peer_assoc_complete_cmd + __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */ + } __packed; + +-#define PEER_BW_RXNSS_OVERRIDE_OFFSET 31 ++#define BW_NSS_FWCONF_MAP_ENABLE BIT(31) ++#define BW_NSS_FWCONF_MAP_160MHZ_LSB (0) ++#define BW_NSS_FWCONF_MAP_160MHZ_MASK (0x00000007) ++#define BW_NSS_FWCONF_MAP_80_80MHZ_LSB (3) ++#define BW_NSS_FWCONF_MAP_80_80MHZ_MASK (0x00000038) ++#define BW_NSS_FWCONF_MAP_MASK (0x0000003F) ++ ++#define GET_BW_NSS_FWCONF_160(x) (MS(x, BW_NSS_FWCONF_MAP_160MHZ) + 1) ++#define GET_BW_NSS_FWCONF_80_80(x) (MS(x, BW_NSS_FWCONF_MAP_80_80MHZ) + 1) ++ ++/* Values defined to set 160 MHz Bandwidth NSS Mapping into FW*/ ++#define BW_NSS_FWCONF_160(x) (BW_NSS_FWCONF_MAP_ENABLE | SM(x - 1, BW_NSS_FWCONF_MAP_160MHZ)) ++#define BW_NSS_FWCONF_80_80(x) (BW_NSS_FWCONF_MAP_ENABLE | SM(x - 1, BW_NSS_FWCONF_MAP_80_80MHZ)) + + struct wmi_10_4_peer_assoc_complete_cmd { + struct wmi_10_2_peer_assoc_complete_cmd cmd; diff --git a/package/kernel/mac80211/patches/ath/973-ath10k_fix-band_center_freq-handling-for-VHT160-in-recent-firmwares.patch b/package/kernel/mac80211/patches/ath/973-ath10k_fix-band_center_freq-handling-for-VHT160-in-recent-firmwares.patch new file mode 100644 index 0000000000..c5c8b1063a --- /dev/null +++ b/package/kernel/mac80211/patches/ath/973-ath10k_fix-band_center_freq-handling-for-VHT160-in-recent-firmwares.patch @@ -0,0 +1,53 @@ +From: Sebastian Gottschall <s.gottschall@dd-wrt.com> + +starting with firmware 10.4.3.4.x series QCA changed the handling of the channel property band_center_freq1 and band_center_freq2 in vht160 operation mode +likelly for backward compatiblity with vht80 only capable clients. +this patch adjusts the handling to get vht160 to work again with official qca firmwares newer than 3.3 +consider that this patch will not work with older firmwares anymore. to avoid undefined behaviour this we disable vht160 capability for outdated firmwares +Signed-off-by: Sebastian Gottschall <s.gottschall@dd-wrt.com> + +v2: fix trailing whitespace issue and fix some typos within the commit note +--- + drivers/net/wireless/ath/ath10k/mac.c | 7 ------- + drivers/net/wireless/ath/ath10k/wmi.c | 11 ++++++++--- + 2 files changed, 8 insertions(+), 10 deletions(-) +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -4445,13 +4445,6 @@ static struct ieee80211_sta_vht_cap ath1 + vht_cap.cap |= val; + } + +- /* Currently the firmware seems to be buggy, don't enable 80+80 +- * mode until that's resolved. +- */ +- if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) && +- (ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == 0) +- vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; +- + mcs_map = 0; + for (i = 0; i < 8; i++) { + if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i))) +--- a/drivers/net/wireless/ath/ath10k/wmi.c ++++ b/drivers/net/wireless/ath/ath10k/wmi.c +@@ -1672,13 +1672,18 @@ void ath10k_wmi_put_wmi_channel(struct w + flags |= WMI_CHAN_FLAG_HT40_PLUS; + if (arg->chan_radar) + flags |= WMI_CHAN_FLAG_DFS; +- ++ ch->band_center_freq2 = 0; + ch->mhz = __cpu_to_le32(arg->freq); + ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1); + if (arg->mode == MODE_11AC_VHT80_80) + ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq2); +- else +- ch->band_center_freq2 = 0; ++ if (arg->mode == MODE_11AC_VHT160) { ++ if (arg->freq < arg->band_center_freq1) ++ ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1 - 40); ++ else ++ ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1 + 40); ++ ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq1); ++ } + ch->min_power = arg->min_power; + ch->max_power = arg->max_power; + ch->reg_power = arg->max_reg_power; diff --git a/package/kernel/mac80211/patches/ath/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch b/package/kernel/mac80211/patches/ath/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch new file mode 100644 index 0000000000..e59d45d508 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch @@ -0,0 +1,643 @@ +From: Sebastian Gottschall <s.gottschall@newmedia-net.de> + +Adds LED and GPIO Control support for 988x, 9887, 9888, 99x0, 9984 based +chipsets with on chipset connected led's using WMI Firmware API. The LED +device will get available named as "ath10k-phyX" at sysfs and can be controlled +with various triggers. adds also debugfs interface for gpio control. + +This patch is specific for OpenWRt base, as is use old backported package +with old wireless source. Support for QCA9984 is removed and a simbol +is added to local-simbol file to export the actually compile the code +with the ATH10K_LEDS simbol. + + +Signed-off-by: Sebastian Gottschall <s.gottschall@dd-wrt.com> +Reviewed-by: Steve deRosier <derosier@cal-sierra.com> +[kvalo: major reorg and cleanup] +Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> +--- + +v13: + +* only compile tested! + +* fix all checkpatch warnings + +* fix commit log + +* sizeof(struct ath10k_gpiocontrol) -> sizeof(*gpio) + +* unsigned -> unsigned int + +* remove GPIOLIB code, that should be added in a separate patch + +* rename gpio.c to leds.c + +* add leds.h + +* rename some functions: + + ath10k_attach_led() -> ath10k_leds_register() + ath10k_unregister_led() -> ath10k_leds_unregister() + ath10k_reset_led_pin() -> ath10k_leds_start() + +* call ath10k_leds_unregister() before ath10k_thermal_unregister() to preserve ordering + +* call ath10k_leds_start() only from ath10k_core_start() and not from mac.c + +* rename struct ath10k_gpiocontrol as anonymous function under struct + ath10k::leds, no need for memory allocation + +* merge ath10k_add_led() to ath10k_attach_led(), which is it's only caller + +* remove #if IS_ENABLED() checks from most of places, memory savings from those were not worth it + +* Kconfig help text improvement and move it lower in the menu, also don't enable it by default + +* switch to set_brightness_blocking() so that the callback can sleep, + then no need to use ath10k_wmi_cmd_send_nowait() and can take mutex + to access ar->state + +* don't touch ath10k_wmi_pdev_get_temperature() + +* as QCA6174/QCA9377 are not (yet) supported don't add the command to WMI-TLV interface + +* remove debugfs interface, that should be added in another patch + +* cleanup includes + + + drivers/net/wireless/ath/ath10k/Kconfig | 10 +++ + drivers/net/wireless/ath/ath10k/Makefile | 1 + + drivers/net/wireless/ath/ath10k/core.c | 22 +++++++ + drivers/net/wireless/ath/ath10k/core.h | 9 ++- + drivers/net/wireless/ath/ath10k/hw.h | 1 + + drivers/net/wireless/ath/ath10k/leds.c | 103 ++++++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath10k/leds.h | 45 +++++++++++++ + drivers/net/wireless/ath/ath10k/mac.c | 1 + + drivers/net/wireless/ath/ath10k/wmi-ops.h | 32 ++++++++++ + drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 + + drivers/net/wireless/ath/ath10k/wmi.c | 54 ++++++++++++++++ + drivers/net/wireless/ath/ath10k/wmi.h | 35 ++++++++++ + 12 files changed, 314 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/wireless/ath/ath10k/leds.c + create mode 100644 drivers/net/wireless/ath/ath10k/leds.h +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/Kconfig +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/Kconfig ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/Kconfig +@@ -69,6 +69,16 @@ config ATH10K_DEBUGFS + + If unsure, say Y to make it easier to debug problems. + ++config ATH10K_LEDS ++ bool "Atheros ath10k LED support" ++ depends on ATH10K ++ select MAC80211_LEDS ++ select LEDS_CLASS ++ select NEW_LEDS ++ default y ++ ---help--- ++ This option is necessary, if you want LED support for chipset connected led pins. If unsure, say N. ++ + config ATH10K_SPECTRAL + bool "Atheros ath10k spectral scan support" + depends on ATH10K_DEBUGFS +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/Makefile +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/Makefile ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/Makefile +@@ -19,6 +19,7 @@ ath10k_core-$(CPTCFG_ATH10K_SPECTRAL) += + ath10k_core-$(CPTCFG_NL80211_TESTMODE) += testmode.o + ath10k_core-$(CPTCFG_ATH10K_TRACING) += trace.o + ath10k_core-$(CPTCFG_ATH10K_THERMAL) += thermal.o ++ath10k_core-$(CPTCFG_ATH10K_LEDS) += leds.o + ath10k_core-$(CPTCFG_MAC80211_DEBUGFS) += debugfs_sta.o + ath10k_core-$(CONFIG_PM) += wow.o + ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o +Index: backports-v4.18-rc7/local-symbols +=================================================================== +--- backports-v4.18-rc7.orig/local-symbols ++++ backports-v4.18-rc7/local-symbols +@@ -147,6 +147,7 @@ ATH10K_DEBUG= + ATH10K_DEBUGFS= + ATH10K_SPECTRAL= + ATH10K_THERMAL= ++ATH10K_LEDS= + ATH10K_TRACING= + ATH10K_DFS_CERTIFIED= + WCN36XX= +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/core.c +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/core.c ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/core.c +@@ -34,6 +34,7 @@ + #include "testmode.h" + #include "wmi-ops.h" + #include "coredump.h" ++#include "leds.h" + + unsigned int ath10k_debug_mask; + static unsigned int ath10k_cryptmode_param; +@@ -66,6 +67,7 @@ static const struct ath10k_hw_params ath + .id = QCA988X_HW_2_0_VERSION, + .dev_id = QCA988X_2_0_DEVICE_ID, + .name = "qca988x hw2.0", ++ .led_pin = 1, + .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, +@@ -129,6 +131,7 @@ static const struct ath10k_hw_params ath + .id = QCA9887_HW_1_0_VERSION, + .dev_id = QCA9887_1_0_DEVICE_ID, + .name = "qca9887 hw1.0", ++ .led_pin = 1, + .patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, +@@ -288,6 +291,7 @@ static const struct ath10k_hw_params ath + .id = QCA99X0_HW_2_0_DEV_VERSION, + .dev_id = QCA99X0_2_0_DEVICE_ID, + .name = "qca99x0 hw2.0", ++ .led_pin = 17, + .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .otp_exe_param = 0x00000700, +@@ -325,6 +329,7 @@ static const struct ath10k_hw_params ath + .id = QCA9984_HW_1_0_DEV_VERSION, + .dev_id = QCA9984_1_0_DEVICE_ID, + .name = "qca9984/qca9994 hw1.0", ++ .led_pin = 17, + .patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, +@@ -367,6 +372,7 @@ static const struct ath10k_hw_params ath + .id = QCA9888_HW_2_0_DEV_VERSION, + .dev_id = QCA9888_2_0_DEVICE_ID, + .name = "qca9888 hw2.0", ++ .led_pin = 17, + .patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, +@@ -2428,6 +2434,10 @@ int ath10k_core_start(struct ath10k *ar, + if (status) + goto err_hif_stop; + ++ status = ath10k_leds_start(ar); ++ if (status) ++ goto err_hif_stop; ++ + return 0; + + err_hif_stop: +@@ -2682,9 +2692,18 @@ static void ath10k_core_register_work(st + goto err_spectral_destroy; + } + ++ status = ath10k_leds_register(ar); ++ if (status) { ++ ath10k_err(ar, "could not register leds: %d\n", ++ status); ++ goto err_thermal_unregister; ++ } ++ + set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); + return; + ++err_thermal_unregister: ++ ath10k_thermal_unregister(ar); + err_spectral_destroy: + ath10k_spectral_destroy(ar); + err_debug_destroy: +@@ -2728,6 +2747,8 @@ void ath10k_core_unregister(struct ath10 + if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) + return; + ++ ath10k_leds_unregister(ar); ++ + ath10k_thermal_unregister(ar); + /* Stop spectral before unregistering from mac80211 to remove the + * relayfs debugfs file cleanly. Otherwise the parent debugfs tree +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/core.h +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/core.h ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/core.h +@@ -25,6 +25,7 @@ + #include <linux/pci.h> + #include <linux/uuid.h> + #include <linux/time.h> ++#include <linux/leds.h> + + #include "htt.h" + #include "htc.h" +@@ -902,7 +903,6 @@ struct ath10k { + u32 low_5ghz_chan; + u32 high_5ghz_chan; + bool ani_enabled; +- + bool p2p; + + struct { +@@ -1093,6 +1093,13 @@ struct ath10k { + } testmode; + + struct { ++ struct gpio_led wifi_led; ++ struct led_classdev cdev; ++ char label[48]; ++ u32 gpio_state_pin; ++ } leds; ++ ++ struct { + /* protected by data_lock */ + u32 fw_crash_counter; + u32 fw_warm_reset_counter; +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/hw.h +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/hw.h ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/hw.h +@@ -504,6 +504,7 @@ struct ath10k_hw_params { + const char *name; + u32 patch_load_addr; + int uart_pin; ++ int led_pin; + u32 otp_exe_param; + + /* Type of hw cycle counter wraparound logic, for more info +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/leds.c +=================================================================== +--- /dev/null ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/leds.c +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (c) 2005-2011 Atheros Communications Inc. ++ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. ++ * Copyright (c) 2018 Sebastian Gottschall <s.gottschall@dd-wrt.com> ++ * Copyright (c) 2018, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include <linux/leds.h> ++ ++#include "core.h" ++#include "wmi.h" ++#include "wmi-ops.h" ++ ++#include "leds.h" ++ ++static int ath10k_leds_set_brightness_blocking(struct led_classdev *led_cdev, ++ enum led_brightness brightness) ++{ ++ struct ath10k *ar = container_of(led_cdev, struct ath10k, ++ leds.cdev); ++ struct gpio_led *led = &ar->leds.wifi_led; ++ ++ mutex_lock(&ar->conf_mutex); ++ ++ if (ar->state != ATH10K_STATE_ON) ++ goto out; ++ ++ ar->leds.gpio_state_pin = (brightness != LED_OFF) ^ led->active_low; ++ ath10k_wmi_gpio_output(ar, led->gpio, ar->leds.gpio_state_pin); ++ ++out: ++ mutex_unlock(&ar->conf_mutex); ++ ++ return 0; ++} ++ ++int ath10k_leds_start(struct ath10k *ar) ++{ ++ if (ar->hw_params.led_pin == 0) ++ /* leds not supported */ ++ return 0; ++ ++ /* under some circumstances, the gpio pin gets reconfigured ++ * to default state by the firmware, so we need to ++ * reconfigure it this behaviour has only ben seen on ++ * QCA9984 and QCA99XX devices so far ++ */ ++ ath10k_wmi_gpio_config(ar, ar->hw_params.led_pin, 0, ++ WMI_GPIO_PULL_NONE, WMI_GPIO_INTTYPE_DISABLE); ++ ath10k_wmi_gpio_output(ar, ar->hw_params.led_pin, 1); ++ ++ return 0; ++} ++ ++int ath10k_leds_register(struct ath10k *ar) ++{ ++ int ret; ++ ++ if (ar->hw_params.led_pin == 0) ++ /* leds not supported */ ++ return 0; ++ ++ snprintf(ar->leds.label, sizeof(ar->leds.label), "ath10k-%s", ++ wiphy_name(ar->hw->wiphy)); ++ ar->leds.wifi_led.active_low = 1; ++ ar->leds.wifi_led.gpio = ar->hw_params.led_pin; ++ ar->leds.wifi_led.name = ar->leds.label; ++ ar->leds.wifi_led.default_state = LEDS_GPIO_DEFSTATE_KEEP; ++ ++ ar->leds.cdev.name = ar->leds.label; ++ ar->leds.cdev.brightness_set_blocking = ath10k_leds_set_brightness_blocking; ++ ++ /* FIXME: this assignment doesn't make sense as it's NULL, remove it? */ ++ ar->leds.cdev.default_trigger = ar->leds.wifi_led.default_trigger; ++ ++ ret = led_classdev_register(wiphy_dev(ar->hw->wiphy), &ar->leds.cdev); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++void ath10k_leds_unregister(struct ath10k *ar) ++{ ++ if (ar->hw_params.led_pin == 0) ++ /* leds not supported */ ++ return; ++ ++ led_classdev_unregister(&ar->leds.cdev); ++} ++ +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/leds.h +=================================================================== +--- /dev/null ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/leds.h +@@ -0,0 +1,41 @@ ++/* ++ * Copyright (c) 2018, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#ifndef _LEDS_H_ ++#define _LEDS_H_ ++ ++#include "core.h" ++ ++#ifdef CPTCFG_ATH10K_LEDS ++void ath10k_leds_unregister(struct ath10k *ar); ++int ath10k_leds_start(struct ath10k *ar); ++int ath10k_leds_register(struct ath10k *ar); ++#else ++static inline void ath10k_leds_unregister(struct ath10k *ar) ++{ ++} ++ ++static inline int ath10k_leds_start(struct ath10k *ar) ++{ ++ return 0; ++} ++ ++static inline int ath10k_leds_register(struct ath10k *ar) ++{ ++ return 0; ++} ++ ++#endif ++#endif /* _LEDS_H_ */ +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/mac.c +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/mac.c ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/mac.c +@@ -33,6 +33,7 @@ + #include "wmi-tlv.h" + #include "wmi-ops.h" + #include "wow.h" ++#include "leds.h" + + /*********/ + /* Rates */ +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/wmi-ops.h +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/wmi-ops.h ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/wmi-ops.h +@@ -214,7 +214,10 @@ struct wmi_ops { + struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value); + struct sk_buff *(*gen_pdev_get_tpc_table_cmdid)(struct ath10k *ar, + u32 param); ++ struct sk_buff *(*gen_gpio_config)(struct ath10k *ar, u32 gpio_num, ++ u32 input, u32 pull_type, u32 intr_mode); + ++ struct sk_buff *(*gen_gpio_output)(struct ath10k *ar, u32 gpio_num, u32 set); + }; + + int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); +@@ -1042,6 +1045,35 @@ ath10k_wmi_force_fw_hang(struct ath10k * + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); + } + ++static inline int ath10k_wmi_gpio_config(struct ath10k *ar, u32 gpio_num, ++ u32 input, u32 pull_type, u32 intr_mode) ++{ ++ struct sk_buff *skb; ++ ++ if (!ar->wmi.ops->gen_gpio_config) ++ return -EOPNOTSUPP; ++ ++ skb = ar->wmi.ops->gen_gpio_config(ar, gpio_num, input, pull_type, intr_mode); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); ++ ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->gpio_config_cmdid); ++} ++ ++static inline int ath10k_wmi_gpio_output(struct ath10k *ar, u32 gpio_num, u32 set) ++{ ++ struct sk_buff *skb; ++ ++ if (!ar->wmi.ops->gen_gpio_config) ++ return -EOPNOTSUPP; ++ ++ skb = ar->wmi.ops->gen_gpio_output(ar, gpio_num, set); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); ++ ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->gpio_output_cmdid); ++} ++ + static inline int + ath10k_wmi_dbglog_cfg(struct ath10k *ar, u64 module_enable, u32 log_level) + { +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/wmi-tlv.c +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/wmi-tlv.c ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/wmi-tlv.c +@@ -3909,6 +3909,8 @@ static const struct wmi_ops wmi_tlv_ops + .gen_echo = ath10k_wmi_tlv_op_gen_echo, + .gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable, ++ /* .gen_gpio_config not implemented */ ++ /* .gen_gpio_output not implemented */ + }; + + static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = { +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/wmi.c +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/wmi.c ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/wmi.c +@@ -7115,6 +7115,49 @@ ath10k_wmi_op_gen_peer_set_param(struct + return skb; + } + ++static struct sk_buff *ath10k_wmi_op_gen_gpio_config(struct ath10k *ar, ++ u32 gpio_num, u32 input, ++ u32 pull_type, u32 intr_mode) ++{ ++ struct wmi_gpio_config_cmd *cmd; ++ struct sk_buff *skb; ++ ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_gpio_config_cmd *)skb->data; ++ cmd->pull_type = __cpu_to_le32(pull_type); ++ cmd->gpio_num = __cpu_to_le32(gpio_num); ++ cmd->input = __cpu_to_le32(input); ++ cmd->intr_mode = __cpu_to_le32(intr_mode); ++ ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi gpio_config gpio_num 0x%08x input 0x%08x pull_type 0x%08x intr_mode 0x%08x\n", ++ gpio_num, input, pull_type, intr_mode); ++ ++ return skb; ++} ++ ++static struct sk_buff *ath10k_wmi_op_gen_gpio_output(struct ath10k *ar, ++ u32 gpio_num, u32 set) ++{ ++ struct wmi_gpio_output_cmd *cmd; ++ struct sk_buff *skb; ++ ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); ++ if (!skb) ++ return ERR_PTR(-ENOMEM); ++ ++ cmd = (struct wmi_gpio_output_cmd *)skb->data; ++ cmd->gpio_num = __cpu_to_le32(gpio_num); ++ cmd->set = __cpu_to_le32(set); ++ ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi gpio_output gpio_num 0x%08x set 0x%08x\n", ++ gpio_num, set); ++ ++ return skb; ++} ++ + static struct sk_buff * + ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id, + enum wmi_sta_ps_mode psmode) +@@ -8726,6 +8769,9 @@ static const struct wmi_ops wmi_ops = { + .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, + .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, + .gen_echo = ath10k_wmi_op_gen_echo, ++ .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, ++ .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, ++ + /* .gen_bcn_tmpl not implemented */ + /* .gen_prb_tmpl not implemented */ + /* .gen_p2p_go_bcn_ie not implemented */ +@@ -8796,6 +8842,8 @@ static const struct wmi_ops wmi_10_1_ops + .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, + .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, + .gen_echo = ath10k_wmi_op_gen_echo, ++ .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, ++ .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, + /* .gen_bcn_tmpl not implemented */ + /* .gen_prb_tmpl not implemented */ + /* .gen_p2p_go_bcn_ie not implemented */ +@@ -8867,6 +8915,8 @@ static const struct wmi_ops wmi_10_2_ops + .gen_delba_send = ath10k_wmi_op_gen_delba_send, + .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, + .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, ++ .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, ++ .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, + /* .gen_pdev_enable_adaptive_cca not implemented */ + }; + +@@ -8937,6 +8987,8 @@ static const struct wmi_ops wmi_10_2_4_o + .gen_pdev_enable_adaptive_cca = + ath10k_wmi_op_gen_pdev_enable_adaptive_cca, + .get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype, ++ .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, ++ .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, + /* .gen_bcn_tmpl not implemented */ + /* .gen_prb_tmpl not implemented */ + /* .gen_p2p_go_bcn_ie not implemented */ +@@ -9016,6 +9068,8 @@ static const struct wmi_ops wmi_10_4_ops + .gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info, + .gen_echo = ath10k_wmi_op_gen_echo, + .gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config, ++ .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, ++ .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, + }; + + int ath10k_wmi_attach(struct ath10k *ar) +Index: backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/wmi.h +=================================================================== +--- backports-v4.18-rc7.orig/drivers/net/wireless/ath/ath10k/wmi.h ++++ backports-v4.18-rc7/drivers/net/wireless/ath/ath10k/wmi.h +@@ -2941,6 +2941,41 @@ enum wmi_10_4_feature_mask { + + }; + ++/* WMI_GPIO_CONFIG_CMDID */ ++enum { ++ WMI_GPIO_PULL_NONE, ++ WMI_GPIO_PULL_UP, ++ WMI_GPIO_PULL_DOWN, ++}; ++ ++enum { ++ WMI_GPIO_INTTYPE_DISABLE, ++ WMI_GPIO_INTTYPE_RISING_EDGE, ++ WMI_GPIO_INTTYPE_FALLING_EDGE, ++ WMI_GPIO_INTTYPE_BOTH_EDGE, ++ WMI_GPIO_INTTYPE_LEVEL_LOW, ++ WMI_GPIO_INTTYPE_LEVEL_HIGH ++}; ++ ++/* WMI_GPIO_CONFIG_CMDID */ ++struct wmi_gpio_config_cmd { ++ __le32 gpio_num; /* GPIO number to be setup */ ++ __le32 input; /* 0 - Output/ 1 - Input */ ++ __le32 pull_type; /* Pull type defined above */ ++ __le32 intr_mode; /* Interrupt mode defined above (Input) */ ++} __packed; ++ ++/* WMI_GPIO_OUTPUT_CMDID */ ++struct wmi_gpio_output_cmd { ++ __le32 gpio_num; /* GPIO number to be setup */ ++ __le32 set; /* Set the GPIO pin*/ ++} __packed; ++ ++/* WMI_GPIO_INPUT_EVENTID */ ++struct wmi_gpio_input_event { ++ __le32 gpio_num; /* GPIO number which changed state */ ++} __packed; ++ + struct wmi_ext_resource_config_10_4_cmd { + /* contains enum wmi_host_platform_type */ + __le32 host_platform_config; diff --git a/package/kernel/mac80211/patches/ath/975-ath10k-use-tpt-trigger-by-default.patch b/package/kernel/mac80211/patches/ath/975-ath10k-use-tpt-trigger-by-default.patch new file mode 100644 index 0000000000..80db9ec437 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/975-ath10k-use-tpt-trigger-by-default.patch @@ -0,0 +1,53 @@ +From 79c9d7aabae1d1da9eea97d83b61e1517a8a2221 Mon Sep 17 00:00:00 2001 +From: Mathias Kresin <dev@kresin.me> +Date: Fri, 22 Jun 2018 18:59:44 +0200 +Subject: [PATCH] ath10k: use tpt LED trigger by default + +Use the tpt LED trigger for each created phy led. Ths way LEDs attached +to the ath10k GPIO pins are indicating the phy status and blink on +traffic. + +Signed-off-by: Mathias Kresin <dev@kresin.me> +--- + drivers/net/wireless/ath/ath10k/core.h | 4 ++++ + drivers/net/wireless/ath/ath10k/leds.c | 4 +--- + drivers/net/wireless/ath/ath10k/mac.c | 2 +- + 3 files changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath10k/core.h ++++ b/drivers/net/wireless/ath/ath10k/core.h +@@ -1055,6 +1055,10 @@ struct ath10k { + struct ath10k_radar_found_info last_radar_info; + struct work_struct radar_confirmation_work; + ++#ifdef CPTCFG_MAC80211_LEDS ++ const char *led_default_trigger; ++#endif ++ + /* must be last */ + u8 drv_priv[0] __aligned(sizeof(void *)); + }; +--- a/drivers/net/wireless/ath/ath10k/leds.c ++++ b/drivers/net/wireless/ath/ath10k/leds.c +@@ -81,9 +81,7 @@ int ath10k_leds_register(struct ath10k * + + ar->leds.cdev.name = ar->leds.label; + ar->leds.cdev.brightness_set_blocking = ath10k_leds_set_brightness_blocking; +- +- /* FIXME: this assignment doesn't make sense as it's NULL, remove it? */ +- ar->leds.cdev.default_trigger = ar->leds.wifi_led.default_trigger; ++ ar->leds.cdev.default_trigger = ar->led_default_trigger; + + ret = led_classdev_register(wiphy_dev(ar->hw->wiphy), &ar->leds.cdev); + if (ret) +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -8429,7 +8429,7 @@ int ath10k_mac_register(struct ath10k *a + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + + #ifdef CPTCFG_MAC80211_LEDS +- ieee80211_create_tpt_led_trigger(ar->hw, ++ ar->led_default_trigger = ieee80211_create_tpt_led_trigger(ar->hw, + IEEE80211_TPT_LEDTRIG_FL_RADIO, ath10k_tpt_blink, + ARRAY_SIZE(ath10k_tpt_blink)); + #endif diff --git a/package/kernel/mac80211/patches/ath/976-ath10k-Limit-available-channels-via-DT-ieee80211-fre.patch b/package/kernel/mac80211/patches/ath/976-ath10k-Limit-available-channels-via-DT-ieee80211-fre.patch new file mode 100644 index 0000000000..ea57d11144 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/976-ath10k-Limit-available-channels-via-DT-ieee80211-fre.patch @@ -0,0 +1,39 @@ +From bbf0a8af2261bc7ae39b227ff6a1e9f45a008c27 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann <sven.eckelmann@openmesh.com> +Date: Mon, 30 Jul 2018 17:31:41 +0200 +Subject: [PATCH] ath10k: Limit available channels via DT ieee80211-freq-limit + +Tri-band devices (1x 2.4GHz + 2x 5GHz) often incorporate special filters in +the RX and TX path. These filtered channel can in theory still be used by +the hardware but the signal strength is reduced so much that it makes no +sense. + +There is already a DT property to limit the available channels but ath10k +has to manually call this functionality to limit the currrently set wiphy +channels further. + +Signed-off-by: Sven Eckelmann <sven.eckelmann@openmesh.com> + +Forwarded: https://patchwork.kernel.org/patch/10549245/ +--- + drivers/net/wireless/ath/ath10k/mac.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -17,6 +17,7 @@ + + #include "mac.h" + ++#include <net/cfg80211.h> + #include <net/mac80211.h> + #include <linux/etherdevice.h> + #include <linux/acpi.h> +@@ -8230,6 +8231,7 @@ int ath10k_mac_register(struct ath10k *a + ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; + } + ++ wiphy_read_of_freq_limits(ar->hw->wiphy); + ath10k_mac_setup_ht_vht_cap(ar); + + ar->hw->wiphy->interface_modes = |