diff mbox series

[OpenWrt-Devel,RFC/RFT] ath9k: implement kthread entropy collection for AR5008 and AR9002 PHYs.

Message ID 20200130200345.31741-1-rsalvaterra@gmail.com
State Rejected
Delegated to: Petr Štetiar
Headers show
Series [OpenWrt-Devel,RFC/RFT] ath9k: implement kthread entropy collection for AR5008 and AR9002 PHYs. | expand

Commit Message

Rui Salvaterra Jan. 30, 2020, 8:03 p.m. UTC
The mainline ath9k driver is able to provide a hardware random number
generator by collecting radio noise from the PHY ADC (using a kthread
to fill up the entropy pool as needed). Nevertheless, this feature has
only been implemented for the more recent AR9003 PHYs.

Meanwhile, OpenWrt has been carrying a patch to provide entropy from the
ADC for the three supported PHYs for a long time, but this patch only
collects entropy once per existing PHY, at the driver initialisation
time.

This patch enables kconfig support for this feature and updates the
OpenWrt patch, in order to add ADC entropy collection support to both
AR5008 and AR9002 PHYs.

Signed-off-by: Rui Salvaterra <rsalvaterra@gmail.com>
---
 package/kernel/mac80211/ath.mk                |   7 +
 .../ath/543-ath9k_entropy_from_adc.patch      | 216 ++++++++++--------
 2 files changed, 134 insertions(+), 89 deletions(-)

Comments

Felix Fietkau Jan. 31, 2020, 8:12 a.m. UTC | #1
On 2020-01-30 21:03, Rui Salvaterra wrote:
> The mainline ath9k driver is able to provide a hardware random number
> generator by collecting radio noise from the PHY ADC (using a kthread
> to fill up the entropy pool as needed). Nevertheless, this feature has
> only been implemented for the more recent AR9003 PHYs.
> 
> Meanwhile, OpenWrt has been carrying a patch to provide entropy from the
> ADC for the three supported PHYs for a long time, but this patch only
> collects entropy once per existing PHY, at the driver initialisation
> time.
> 
> This patch enables kconfig support for this feature and updates the
> OpenWrt patch, in order to add ADC entropy collection support to both
> AR5008 and AR9002 PHYs.
> 
> Signed-off-by: Rui Salvaterra <rsalvaterra@gmail.com>
For at least AR5008 and AR9002, but probably also for AR9003 I would
like to keep the behavior of collecting entropy only once at driver
initialization.
Last time I worked on this I noticed that on several chips, sampling
entropy during normal operation caused stability issues that were hard
to pin down but quite noticeable.
I think the benefit of continuous entropy collection is simply not worth
the extra cost of potential stability issues and debugging time.

- Felix
Rui Salvaterra Jan. 31, 2020, 9:06 a.m. UTC | #2
Hi, Felix,

On Fri, 31 Jan 2020 at 08:12, Felix Fietkau <nbd@nbd.name> wrote:
> For at least AR5008 and AR9002, but probably also for AR9003 I would
> like to keep the behavior of collecting entropy only once at driver
> initialization.

Well, you could have told me this before I started working on it, but
I guess you
don't read the developer section of the forum, even when you're mentioned. ;)
(What's the best communication channel for OpenWrt development? There are
far too many options, I think.)

FWIW, my Archer C6 v2 has been running OpenWrt 19.07 with my entropy
patch for days without any problems (1 x AR9003, though). I'll be testing soon
on a TL-WDR3600 (2 x AR9003) and a WNDR3700 v1 (2 x AR9002). Like
I wrote in the forum, I don't have (yet) AR5008 hardware to test.

> Last time I worked on this I noticed that on several chips, sampling
> entropy during normal operation caused stability issues that were hard
> to pin down but quite noticeable.

Maybe it's not a good idea to sample from a low power state? :) The old code
didn't call ath9k_ps_wakeup before collecting (and ath9k_ps_restore afterwards),
it's possible that the stability problems are related to the power
state at collection
time.

The current mainline code is from 2015, and it's nothing like the one in the
OpenWrt patch (from 2013). The entropy collection is not continuous at all,
it's done on a kthread which only wakes up when the available entropy drops
below a certain threshold. I only extended the mainline code to support the
previous PHYs.
Rui Salvaterra Jan. 31, 2020, 9:54 a.m. UTC | #3
On Fri, 31 Jan 2020 at 09:06, Rui Salvaterra <rsalvaterra@gmail.com> wrote:
>
> Like I wrote in the forum, I don't have (yet) AR5008 hardware to test.

And I just ordered an AR5BXB72* for testing purposes. I can configure it as AP
on my Turris Omnia.

* https://www.aliexpress.com/item/32356022951.html
Rui Salvaterra Feb. 10, 2020, 9:44 a.m. UTC | #4
On Fri, 31 Jan 2020 at 08:12, Felix Fietkau <nbd@nbd.name> wrote:
>
> For at least AR5008 and AR9002, but probably also for AR9003 I would
> like to keep the behavior of collecting entropy only once at driver
> initialization.
> Last time I worked on this I noticed that on several chips, sampling
> entropy during normal operation caused stability issues that were hard
> to pin down but quite noticeable.
> I think the benefit of continuous entropy collection is simply not worth
> the extra cost of potential stability issues and debugging time.
>
> - Felix

Hi again, Felix,

FWIW, this patch has just survived a whole weekend of rngtest <
/dev/random on a Buffalo WZR-HP-AG300H (dual AR9002). Output follows:

root@AP157427:~# rngtest < /dev/random
rngtest 6.6
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There
is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
^Crngtest: bits received from input: 224241980032
rngtest: FIPS 140-2 successes: 11203058
rngtest: FIPS 140-2 failures: 9041
rngtest: FIPS 140-2(2001-10-10) Monobit: 1165
rngtest: FIPS 140-2(2001-10-10) Poker: 1175
rngtest: FIPS 140-2(2001-10-10) Runs: 3340
rngtest: FIPS 140-2(2001-10-10) Long run: 3405
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=165.459; avg=1025.932; max=1093.147)Kibits/s
rngtest: FIPS tests speed: (min=503.707; avg=14584.165; max=14920.741)Kibits/s
rngtest: Program run time: 228508694816 microseconds

Best regards,
Rui
Felix Fietkau Feb. 10, 2020, 1:37 p.m. UTC | #5
On 2020-02-10 10:44, Rui Salvaterra wrote:
> On Fri, 31 Jan 2020 at 08:12, Felix Fietkau <nbd@nbd.name> wrote:
>>
>> For at least AR5008 and AR9002, but probably also for AR9003 I would
>> like to keep the behavior of collecting entropy only once at driver
>> initialization.
>> Last time I worked on this I noticed that on several chips, sampling
>> entropy during normal operation caused stability issues that were hard
>> to pin down but quite noticeable.
>> I think the benefit of continuous entropy collection is simply not worth
>> the extra cost of potential stability issues and debugging time.
>>
>> - Felix
> 
> Hi again, Felix,
> 
> FWIW, this patch has just survived a whole weekend of rngtest <
> /dev/random on a Buffalo WZR-HP-AG300H (dual AR9002). Output follows:
> 
> root@AP157427:~# rngtest < /dev/random
> rngtest 6.6
> Copyright (c) 2004 by Henrique de Moraes Holschuh
> This is free software; see the source for copying conditions.  There
> is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
> PARTICULAR PURPOSE.
> 
> rngtest: starting FIPS tests...
> ^Crngtest: bits received from input: 224241980032
> rngtest: FIPS 140-2 successes: 11203058
> rngtest: FIPS 140-2 failures: 9041
> rngtest: FIPS 140-2(2001-10-10) Monobit: 1165
> rngtest: FIPS 140-2(2001-10-10) Poker: 1175
> rngtest: FIPS 140-2(2001-10-10) Runs: 3340
> rngtest: FIPS 140-2(2001-10-10) Long run: 3405
> rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
> rngtest: input channel speed: (min=165.459; avg=1025.932; max=1093.147)Kibits/s
> rngtest: FIPS tests speed: (min=503.707; avg=14584.165; max=14920.741)Kibits/s
> rngtest: Program run time: 228508694816 microseconds
The issues that were reported years ago were mainly stuck beacons,
increase in hardware resets, connection stability issues.

- Felix
Rui Salvaterra Feb. 10, 2020, 3:46 p.m. UTC | #6
Hi again, Felix,

On Mon, 10 Feb 2020 at 13:37, Felix Fietkau <nbd@nbd.name> wrote:
> The issues that were reported years ago were mainly stuck beacons,
> increase in hardware resets, connection stability issues.

Thanks for the info, I'll keep an eye out for those. The dmesg is
clean, I haven't enabled any debugging, but I'll do so for further
testing.
As an aside, this WZR-HP-AG300H is running as an AP, at a public
institution, with 12 STAs connected, at the moment (8 at 2,4 GHz, 4 at
5 GHz), without any reported issues.

Thanks,
Rui
Rui Salvaterra Feb. 13, 2020, 9:28 a.m. UTC | #7
Hi again, Felix,

On Mon, 10 Feb 2020 at 15:46, Rui Salvaterra <rsalvaterra@gmail.com> wrote:
>
> As an aside, this WZR-HP-AG300H is running as an AP, at a public
> institution, with 12 STAs connected, at the moment (8 at 2,4 GHz, 4 at
> 5 GHz), without any reported issues.

So, since Tuesday, I've been running cat /dev/random > /dev/null on
this router to stress the ADC entropy collection as much as possible.
Everything's working just fine, though I'm seeing this in
/sys/kernel/debug/ieee80211/phy?/ath9k/reset:

phy0 (2.4 GHz):
    Baseband Hang:  0
Baseband Watchdog:  0
   Fatal HW Error:  0
      TX HW error:  0
 Transmit timeout:  0
     TX Path Hang:  0
      PLL RX Hang:  0
         MAC Hang:  1
     Stuck Beacon: 76
        MCI Reset:  0
Calibration error:  0
Tx DMA stop error: 69
Rx DMA stop error:  0

phy1 (5 GHz):
    Baseband Hang:  0
Baseband Watchdog:  0
   Fatal HW Error:  0
      TX HW error:  0
 Transmit timeout:  0
     TX Path Hang:  0
      PLL RX Hang:  0
         MAC Hang:  1
     Stuck Beacon:  1
        MCI Reset:  0
Calibration error:  0
Tx DMA stop error:  0
Rx DMA stop error:  0

I suspect these errors might be related to the DMA stop sequence
(which you actually fixed/mitigated [1], as I seem to recall having
this issue on my TL-WDR3600), not the entropy collection. In any case,
I'm going to test an image which reverses the stop sequence also on
AR9002, to see if this has any effect. Note that
/sys/kernel/debug/ieee80211/phy?/ath9k/queues are completely clean on
both PHYs:

phy0 (2.4 GHz):
(VO):  qnum: 3 qdepth:  0 ampdu-depth:  0 pending:   0
(VI):  qnum: 2 qdepth:  0 ampdu-depth:  0 pending:   0
(BE):  qnum: 1 qdepth:  0 ampdu-depth:  0 pending:   0
(BK):  qnum: 0 qdepth:  0 ampdu-depth:  0 pending:   0
(CAB): qnum: 8 qdepth:  0 ampdu-depth:  0 pending:   0

phy1 (5 GHz):
(VO):  qnum: 3 qdepth:  0 ampdu-depth:  0 pending:   0
(VI):  qnum: 2 qdepth:  0 ampdu-depth:  0 pending:   0
(BE):  qnum: 1 qdepth:  0 ampdu-depth:  0 pending:   0
(BK):  qnum: 0 qdepth:  0 ampdu-depth:  0 pending:   0
(CAB): qnum: 8 qdepth:  0 ampdu-depth:  0 pending:   0

Thanks,
Rui

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/net/wireless/ath/ath9k?id=300f77c08ded96d33f492aaa02549103852f0c12
diff mbox series

Patch

diff --git a/package/kernel/mac80211/ath.mk b/package/kernel/mac80211/ath.mk
index 788131b751..fb6e893494 100644
--- a/package/kernel/mac80211/ath.mk
+++ b/package/kernel/mac80211/ath.mk
@@ -8,6 +8,7 @@  PKG_CONFIG_DEPENDS += \
 	CONFIG_PACKAGE_ATH_SPECTRAL \
 	CONFIG_PACKAGE_ATH_DYNACK \
 	CONFIG_ATH9K_SUPPORT_PCOEM \
+	CONFIG_ATH9K_HWRNG \
 	CONFIG_ATH9K_TX99 \
 	CONFIG_ATH10K_LEDS \
 	CONFIG_ATH10K_THERMAL \
@@ -45,6 +46,7 @@  config-$(CONFIG_TARGET_ipq40xx) += ATH10K_AHB
 config-$(CONFIG_PCI) += ATH9K_PCI
 config-$(CONFIG_ATH_USER_REGD) += ATH_USER_REGD
 config-$(CONFIG_ATH9K_SUPPORT_PCOEM) += ATH9K_PCOEM
+config-$(CONFIG_ATH9K_HWRNG) += ATH9K_HWRNG
 config-$(CONFIG_ATH9K_TX99) += ATH9K_TX99
 config-$(CONFIG_ATH9K_UBNTHSR) += ATH9K_UBNTHSR
 config-$(CONFIG_ATH10K_LEDS) += ATH10K_LEDS
@@ -211,6 +213,11 @@  define KernelPackage/ath9k/config
 		bool "Support chips used in PC OEM cards"
 		depends on PACKAGE_kmod-ath9k
 
+	config ATH9K_HWRNG
+		bool "Use the PHY ADC as a hardware random number generator"
+		depends on PACKAGE_kmod-ath9k
+		select PACKAGE_kmod-random-core
+
        config ATH9K_TX99
                bool "Enable TX99 support (WARNING: testing only, breaks normal operation!)"
                depends on PACKAGE_kmod-ath9k
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
index 64bd6cacfd..8b92fbcb0b 100644
--- a/package/kernel/mac80211/patches/ath/543-ath9k_entropy_from_adc.patch
+++ b/package/kernel/mac80211/patches/ath/543-ath9k_entropy_from_adc.patch
@@ -8,145 +8,113 @@ 
   * @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
-@@ -744,6 +745,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);
+@@ -756,6 +757,10 @@ struct ath_hw_ops {
+ #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
+ 	void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable);
+ #endif
++
++#ifdef CPTCFG_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/ar9003_phy.c
 +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -1927,6 +1927,26 @@ void ar9003_hw_init_rate_txpower(struct
+@@ -1927,6 +1927,33 @@ void ar9003_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
++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, 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);
++	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;
 +
-+			buf[i] <<= 2;
-+			buf[i] |= (regval & 1) | ((regval & BIT(10)) >> 9);
-+			udelay(1);
-+		}
++		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 +1983,7 @@ void ar9003_hw_attach_phy_ops(struct ath
+@@ -1962,7 +1989,9 @@ void ar9003_hw_attach_phy_ops(struct ath
+ 	priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
  	priv_ops->set_radar_params = ar9003_hw_set_radar_params;
  	priv_ops->fast_chan_change = ar9003_hw_fast_chan_change;
- 
+-
++#ifdef CPTCFG_ATH9K_HWRNG
 +	ops->get_adc_entropy = ar9003_hw_get_adc_entropy;
++#endif
  	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
-@@ -819,7 +819,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[] = {
-@@ -1015,6 +1016,18 @@ static void ath9k_set_hw_capab(struct at
- 	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
- }
- 
-+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)
- {
-@@ -1060,6 +1073,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
-@@ -1320,9 +1320,30 @@ void ar5008_hw_init_rate_txpower(struct
+@@ -1320,9 +1320,37 @@ void ar5008_hw_init_rate_txpower(struct
  	}
  }
  
-+static void ar5008_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, 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);
++	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;
 +
-+			buf[i] <<= 2;
-+			buf[i] |= (regval & 1) | ((regval & BIT(9)) >> 8);
-+			udelay(1);
-+		}
++		last = v2;
 +	}
++
++	*rng_last = last;
++
++	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,
-@@ -1337,6 +1358,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
+@@ -1336,7 +1364,10 @@ int ar5008_hw_attach_phy_ops(struct ath_
+ 	ret = ar5008_hw_rf_alloc_ext_banks(ah);
  	if (ret)
  	    return ret;
- 
+-
++#ifdef CPTCFG_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;
  
@@ -184,3 +152,73 @@ 
  #define AR_PHY_CHAN_INFO_GAIN_DIFF             0x9CF4
  #define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320
  
+--- a/drivers/net/wireless/ath/ath9k/rng.c
++++ b/drivers/net/wireless/ath/ath9k/rng.c
+@@ -19,42 +19,30 @@
+ 
+ #include "ath9k.h"
+ #include "hw.h"
+-#include "ar9003_phy.h"
+ 
+ #define ATH9K_RNG_BUF_SIZE	320
+ #define ATH9K_RNG_ENTROPY(x)	(((x) * 8 * 10) >> 5) /* quality: 10/32 */
+ 
+ static DECLARE_WAIT_QUEUE_HEAD(rng_queue);
+ 
+-static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size)
++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, const 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, 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);
+-
+-	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)
+@@ -109,14 +97,9 @@ out:
+ 
+ void ath9k_rng_start(struct ath_softc *sc)
+ {
+-	struct ath_hw *ah = sc->sc_ah;
+-
+ 	if (sc->rng_task)
+ 		return;
+ 
+-	if (!AR_SREV_9300_20_OR_LATER(ah))
+-		return;
+-
+ 	sc->rng_task = kthread_run(ath9k_rng_kthread, sc, "ath9k-hwrng");
+ 	if (IS_ERR(sc->rng_task))
+ 		sc->rng_task = NULL;