Hi Felix,
I have a question about https://dev.openwrt.org/changeset/38486. While
backporting the aforementioned patch from trunk to attitude adjustment, I
noticed that the patch does not include a gettor function for the adc entropy
of the ar9002 chip, only those of ar5008 and ar9003.
static void ar9003_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len)
static void ar5008_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len)
but no
static void ar9002_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len)
Furthermore, when the phy_ops are constructed in ar9002_hw_attach_phy_ops, the
get_adc_entropy function pointer is never assigned.
I can be wrong ofcourse, but am under the impression this will create a
problem when the driver is probed for an ar9002 chip and possibly result in a
kernel oops, because "ath9k_hw_get_adc_entropy" expects the ath_hw struct to
have a valid (non-NULL) function pointer for get_adc_entropy. See below:
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);
}
Did changes in ar9002_phy.c somehow miss inclusion in the patch?
When testing the backported patch for my ar9003 chip, I was confronted with a
kernel oops at initialisation, which I narrowed down to ath9k_hw_reset
function, called from ath_get_initial_entropy, where the channels in
ieee80211_conf data field in common hardware config are not yet initialised it
seems. I changed the condition to verify for a valid pointer before
dereferencing it, which seems to solve the problem.
This is different in the mac82011 version from trunk (compat-
wireless-2013-11-05), where channelFlags from channel are used in the
condition, which is an u32, and thus can not result in a null pointer
dereference. My question now is, although the fix seems sufficient, is it also
correct/expected behaviour?
This is the backport of the patch thus far. I included the changes for the
ar9002 chip. I would expect the implementation for get_adc_entropy for ar9002
to be close(r) to ar9003, but since ar5008 depends on defines from
ar9002_phy.h and the latter are missing those from ar9003_phy.h, I copied the
implementation for ar5008 to ar9002, which may be very wrong ofcourse
(untested, as I have no ar9002 chip). The patch/driver does work for me now
(char buf being filled with entropy).
Signed-off-by: Tijs Van Buggenhout <[email protected]>
--
diff -u -Naur a/drivers/net/wireless/ath/ath9k/hw.h
b/drivers/net/wireless/ath/ath9k/hw.h
--- a/drivers/net/wireless/ath/ath9k/hw.h 2013-10-28 18:00:58.000000000
+0100
+++ b/drivers/net/wireless/ath/ath9k/hw.h 2013-11-19 13:32:56.000000000
+0100
@@ -700,6 +700,7 @@
* @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
@@ -722,6 +723,7 @@
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 (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable);
void (*spectral_scan_config)(struct ath_hw *ah,
struct ath_spec_scan *param);
diff -u -Naur a/drivers/net/wireless/ath/ath9k/hw.c
b/drivers/net/wireless/ath/ath9k/hw.c
--- a/drivers/net/wireless/ath/ath9k/hw.c 2013-10-28 18:00:58.000000000
+0100
+++ b/drivers/net/wireless/ath/ath9k/hw.c 2013-12-05 21:05:25.000000000
+0100
@@ -131,8 +131,8 @@
static void ath9k_hw_set_clockrate(struct ath_hw *ah)
{
- struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
unsigned int clockrate;
/* AR9287 v1.3+ uses async FIFO and runs the MAC at 117 MHz */
@@ -140,7 +140,7 @@
clockrate = 117;
else if (!ah->curchan) /* should really check for CCK instead */
clockrate = ATH9K_CLOCK_RATE_CCK;
- else if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ)
+ else if (conf->chandef.chan && conf->chandef.chan->band ==
IEEE80211_BAND_2GHZ)
clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
else if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)
clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
diff -u -Naur a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c 2013-10-28
18:00:58.000000000 +0100
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c 2013-12-05
19:09:34.000000000 +0100
@@ -1603,6 +1603,26 @@
}
}
+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);
@@ -1633,6 +1653,7 @@
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->antctrl_shared_chain_lnadiv =
ar9003_hw_antctrl_shared_chain_lnadiv;
diff -u -Naur a/drivers/net/wireless/ath/ath9k/init.c
b/drivers/net/wireless/ath/ath9k/init.c
--- a/drivers/net/wireless/ath/ath9k/init.c 2013-10-28 18:00:58.000000000
+0100
+++ b/drivers/net/wireless/ath/ath9k/init.c 2013-12-05 21:09:13.000000000
+0100
@@ -735,7 +735,8 @@
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ);
- ah->curchan = curchan;
+ if (curchan)
+ ah->curchan = curchan;
}
void ath9k_reload_chainmask_settings(struct ath_softc *sc)
@@ -880,6 +881,18 @@
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
+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)
{
@@ -925,6 +938,8 @@
ARRAY_SIZE(ath9k_tpt_blink));
#endif
+ ath_get_initial_entropy(sc);
+
/* Register with mac80211 */
error = ieee80211_register_hw(hw);
if (error)
diff -u -Naur a/drivers/net/wireless/ath/ath9k/hw-ops.h
b/drivers/net/wireless/ath/ath9k/hw-ops.h
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h 2013-06-30 16:34:53.000000000
+0200
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h 2013-11-19 13:34:39.000000000
+0100
@@ -78,6 +78,12 @@
ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
}
+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);
+}
+
static inline void ath9k_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah,
bool enable)
{
diff -u -Naur a/drivers/net/wireless/ath/ath9k/link.c
b/drivers/net/wireless/ath/ath9k/link.c
--- a/drivers/net/wireless/ath/ath9k/link.c 2013-06-30 16:34:53.000000000
+0200
+++ b/drivers/net/wireless/ath/ath9k/link.c 2013-12-05 21:09:34.000000000
+0100
@@ -342,6 +342,11 @@
unsigned int timestamp = jiffies_to_msecs(jiffies);
u32 cal_interval, short_cal_interval, long_cal_interval;
unsigned long flags;
+ char buf[256];
+
+ /* gather entropy */
+ ath9k_hw_get_adc_entropy(ah, buf, sizeof(buf));
+ add_device_randomness(buf, sizeof(buf));
if (ah->caldata && ah->caldata->nfcal_interference)
long_cal_interval = ATH_LONG_CALINTERVAL_INT;diff -u -Naur
a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c 2013-06-30
16:34:53.000000000 +0200
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c 2013-12-05
19:08:38.000000000 +0100
@@ -1310,9 +1310,30 @@
conf->radar_inband = 8;
}
+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,
@@ -1327,6 +1348,8 @@
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;
diff -u -Naur a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h 2013-06-30
16:34:53.000000000 +0200
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h 2013-11-19
13:32:00.000000000 +0100
@@ -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
@@ -388,6 +397,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 -u -Naur a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c 2013-06-30
16:34:53.000000000 +0200
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c 2013-12-05
19:18:44.000000000 +0100
@@ -616,6 +616,26 @@
}
}
+static void ar9002_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);
+ }
+ }
+}
+
void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -628,6 +648,7 @@
priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
priv_ops->do_getnf = ar9002_hw_do_getnf;
+ ops->get_adc_entropy = ar9002_hw_get_adc_entropy;
ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
ops->spectral_scan_config = ar9002_hw_spectral_scan_config;
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel