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 <t...@able.be> -- 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 openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel