forked from openwrt/openwrt
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ath9k: implement ADC entropy gathering for older chips
Testing is required on AR5008. No detected issues on AR900{1,2}. Signed-off-by: Rui Salvaterra <[email protected]>
- Loading branch information
1 parent
5a075c8
commit 4ad670e
Showing
1 changed file
with
177 additions
and
124 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,158 +1,78 @@ | ||
--- a/drivers/net/wireless/ath/ath9k/hw.h | ||
+++ b/drivers/net/wireless/ath/ath9k/hw.h | ||
@@ -723,6 +723,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 | ||
@@ -745,6 +746,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 | ||
@@ -1918,6 +1918,26 @@ void ar9003_hw_init_rate_txpower(struct | ||
From 82880c4a6224f9e537d106b3bfe079c792bd9f09 Mon Sep 17 00:00:00 2001 | ||
From: Rui Salvaterra <[email protected]> | ||
Date: Wed, 28 Oct 2020 14:02:43 +0000 | ||
Subject: [PATCH] ath9k: implement ADC entropy collection for older generations | ||
|
||
Signed-off-by: Rui Salvaterra <[email protected]> | ||
--- | ||
drivers/net/wireless/ath/ath9k/ar5008_phy.c | 34 +++++++++++++++++++++ | ||
drivers/net/wireless/ath/ath9k/ar9002_phy.h | 13 +++++++- | ||
drivers/net/wireless/ath/ath9k/ar9003_phy.c | 32 +++++++++++++++++++ | ||
drivers/net/wireless/ath/ath9k/hw.h | 5 +++ | ||
drivers/net/wireless/ath/ath9k/rng.c | 34 ++++++--------------- | ||
5 files changed, 92 insertions(+), 26 deletions(-) | ||
|
||
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c | ||
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c | ||
@@ -1340,9 +1340,38 @@ void ar5008_hw_init_rate_txpower(struct | ||
} | ||
} | ||
|
||
+static void ar9003_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len) | ||
+static int __maybe_unused | ||
+ar5008_hw_get_adc_entropy(struct ath_hw *ah, u32 *buf, const u32 buf_size, u32 *rng_last) | ||
+{ | ||
+ int i, j; | ||
+ u32 v1, v2, last = *rng_last; | ||
+ | ||
+ REG_RMW_FIELD(ah, AR_PHY_TEST(ah), AR_PHY_TEST_BBB_OBS_SEL, 1); | ||
+ REG_CLR_BIT(ah, AR_PHY_TEST(ah), AR_PHY_TEST_RX_OBS_SEL_BIT5); | ||
+ REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS(ah), 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); | ||
@@ -1954,6 +1974,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 | ||
@@ -871,7 +871,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[] = { | ||
@@ -1049,6 +1050,18 @@ static void ath9k_set_hw_capab(struct at | ||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); | ||
} | ||
|
||
+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) | ||
{ | ||
@@ -1096,6 +1109,8 @@ int ath9k_init_device(u16 devid, struct | ||
|
||
wiphy_read_of_freq_limits(hw->wiphy); | ||
|
||
+ ath_get_initial_entropy(sc); | ||
+ REG_RMW_FIELD(ah, AR_PHY_TEST2, AR_PHY_TEST2_RX_OBS_SEL, 0); | ||
+ | ||
/* 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); | ||
+} | ||
+ for (i = 0, j = 0; i < buf_size; i++) { | ||
+ v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; | ||
+ v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; | ||
+ | ||
#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 | ||
@@ -1340,9 +1340,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; | ||
+ /* wait for data ready */ | ||
+ if (v1 && v2 && last != v1 && v1 != v2 && v1 != 0xffff && | ||
+ v2 != 0xffff) | ||
+ buf[j++] = (v1 << 16) | v2; | ||
+ | ||
+ 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); | ||
+ last = v2; | ||
+ } | ||
+ | ||
+ 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); | ||
+ *rng_last = last; | ||
+ | ||
+ buf[i] <<= 2; | ||
+ buf[i] |= (regval & 1) | ((regval & BIT(9)) >> 8); | ||
+ udelay(1); | ||
+ } | ||
+ } | ||
+ return j << 2; | ||
+} | ||
+ | ||
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); | ||
+ struct ath_hw_ops *ops __maybe_unused; | ||
+ | ||
static const u32 ar5416_cca_regs[6] = { | ||
AR_PHY_CCA, | ||
AR_PHY_CH1_CCA, | ||
@@ -1357,6 +1378,8 @@ int ar5008_hw_attach_phy_ops(struct ath_ | ||
@@ -1357,6 +1386,11 @@ int ar5008_hw_attach_phy_ops(struct ath_ | ||
if (ret) | ||
return ret; | ||
|
||
+#ifdef CONFIG_ATH9K_HWRNG | ||
+ ops = ath9k_hw_ops(ah); | ||
+ ops->get_adc_entropy = ar5008_hw_get_adc_entropy; | ||
+#endif | ||
+ | ||
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 @@ | ||
@@ -16,10 +16,16 @@ | ||
#ifndef AR9002_PHY_H | ||
#define AR9002_PHY_H | ||
|
||
-#define AR_PHY_TEST 0x9800 | ||
+#define AR_PHY_TEST(_ah) 0x9800 | ||
#define PHY_AGC_CLR 0x10000000 | ||
#define RFSILENT_BB 0x00002000 | ||
|
||
|
@@ -184,3 +104,136 @@ | |
#define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4 | ||
#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320 | ||
|
||
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c | ||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | ||
@@ -1918,6 +1918,33 @@ void ar9003_hw_init_rate_txpower(struct | ||
} | ||
} | ||
|
||
+static int __maybe_unused | ||
+ar9003_hw_get_adc_entropy(struct ath_hw *ah, u32 *buf, const u32 buf_size, u32 *rng_last) | ||
+{ | ||
+ int i, j; | ||
+ u32 v1, v2, last = *rng_last; | ||
+ | ||
+ REG_RMW_FIELD(ah, AR_PHY_TEST(ah), AR_PHY_TEST_BBB_OBS_SEL, 1); | ||
+ REG_CLR_BIT(ah, AR_PHY_TEST(ah), AR_PHY_TEST_RX_OBS_SEL_BIT5); | ||
+ REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS(ah), AR_PHY_TEST_CTL_RX_OBS_SEL, 0); | ||
+ | ||
+ for (i = 0, j = 0; i < buf_size; i++) { | ||
+ v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; | ||
+ v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; | ||
+ | ||
+ /* wait for data ready */ | ||
+ if (v1 && v2 && last != v1 && v1 != v2 && v1 != 0xffff && | ||
+ v2 != 0xffff) | ||
+ buf[j++] = (v1 << 16) | v2; | ||
+ | ||
+ last = v2; | ||
+ } | ||
+ | ||
+ *rng_last = last; | ||
+ | ||
+ return j << 2; | ||
+} | ||
+ | ||
void ar9003_hw_attach_phy_ops(struct ath_hw *ah) | ||
{ | ||
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); | ||
@@ -1963,6 +1990,11 @@ void ar9003_hw_attach_phy_ops(struct ath | ||
#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT | ||
ops->set_bt_ant_diversity = ar9003_hw_set_bt_ant_diversity; | ||
#endif | ||
+ | ||
+#ifdef CONFIG_ATH9K_HWRNG | ||
+ ops->get_adc_entropy = ar9003_hw_get_adc_entropy; | ||
+#endif | ||
+ | ||
ops->tx99_start = ar9003_hw_tx99_start; | ||
ops->tx99_stop = ar9003_hw_tx99_stop; | ||
ops->tx99_set_txpower = ar9003_hw_tx99_set_txpower; | ||
--- a/drivers/net/wireless/ath/ath9k/hw.h | ||
+++ b/drivers/net/wireless/ath/ath9k/hw.h | ||
@@ -726,6 +726,7 @@ struct ath_spec_scan { | ||
* @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 | ||
+ * @get_adc_entropy: get entropy from the raw ADC I/Q output | ||
*/ | ||
struct ath_hw_ops { | ||
void (*config_pci_powersave)(struct ath_hw *ah, | ||
@@ -757,6 +758,10 @@ struct ath_hw_ops { | ||
#ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT | ||
void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable); | ||
#endif | ||
+ | ||
+#ifdef CONFIG_ATH9K_HWRNG | ||
+ int (*get_adc_entropy)(struct ath_hw *ah, u32 *buf, const u32 buf_size, u32 *rng_last); | ||
+#endif | ||
}; | ||
|
||
struct ath_nf_limits { | ||
--- a/drivers/net/wireless/ath/ath9k/rng.c | ||
+++ b/drivers/net/wireless/ath/ath9k/rng.c | ||
@@ -19,37 +19,25 @@ | ||
|
||
#include "ath9k.h" | ||
#include "hw.h" | ||
-#include "ar9003_phy.h" | ||
+ | ||
+static inline int ath9k_hw_get_adc_entropy(struct ath_hw *ah, | ||
+ u32 *buf, const u32 buf_size, u32 *rng_last) | ||
+{ | ||
+ return ath9k_hw_ops(ah)->get_adc_entropy(ah, buf, buf_size, rng_last); | ||
+} | ||
|
||
static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size) | ||
{ | ||
- int i, j; | ||
- u32 v1, v2, rng_last = sc->rng_last; | ||
struct ath_hw *ah = sc->sc_ah; | ||
+ int bytes_read; | ||
|
||
ath9k_ps_wakeup(sc); | ||
|
||
- REG_RMW_FIELD(ah, AR_PHY_TEST(ah), AR_PHY_TEST_BBB_OBS_SEL, 1); | ||
- REG_CLR_BIT(ah, AR_PHY_TEST(ah), AR_PHY_TEST_RX_OBS_SEL_BIT5); | ||
- REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS(ah), AR_PHY_TEST_CTL_RX_OBS_SEL, 0); | ||
- | ||
- for (i = 0, j = 0; i < buf_size; i++) { | ||
- v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; | ||
- v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; | ||
- | ||
- /* wait for data ready */ | ||
- if (v1 && v2 && rng_last != v1 && v1 != v2 && v1 != 0xffff && | ||
- v2 != 0xffff) | ||
- buf[j++] = (v1 << 16) | v2; | ||
- | ||
- rng_last = v2; | ||
- } | ||
+ bytes_read = ath9k_hw_get_adc_entropy(ah, buf, buf_size, &sc->rng_last); | ||
|
||
ath9k_ps_restore(sc); | ||
|
||
- sc->rng_last = rng_last; | ||
- | ||
- return j << 2; | ||
+ return bytes_read; | ||
} | ||
|
||
static u32 ath9k_rng_delay_get(u32 fail_stats) | ||
@@ -95,14 +83,10 @@ static int ath9k_rng_read(struct hwrng * | ||
void ath9k_rng_start(struct ath_softc *sc) | ||
{ | ||
static atomic_t serial = ATOMIC_INIT(0); | ||
- struct ath_hw *ah = sc->sc_ah; | ||
|
||
if (sc->rng_ops.read) | ||
return; | ||
|
||
- if (!AR_SREV_9300_20_OR_LATER(ah)) | ||
- return; | ||
- | ||
snprintf(sc->rng_name, sizeof(sc->rng_name), "ath9k_%u", | ||
(atomic_inc_return(&serial) - 1) & U16_MAX); | ||
sc->rng_ops.name = sc->rng_name; |