carl9170: PHY updates + hang fix
Christian Lamparter
maintainercover carl9170: PHY updates + hang fix
Christian Lamparter (7):
carl9170: use rx chainmask from eeprom
carl9170: fix noise dBm conversion
carl9170: don't load bogus nf of chain 1
carl9170: abort tasklet during usb reset
carl9170: fix state downgrade during reset
carl9170: reinit phy after HT settings have changed
carl9170: fix hang in AP mode when HT STA does PSM
drivers/net/wireless/ath/carl9170/carl9170.h | 3 +- drivers/net/wireless/ath/carl9170/debug.c | 8 ++--- drivers/net/wireless/ath/carl9170/main.c | 4 +- drivers/net/wireless/ath/carl9170/phy.c | 45 ++++++++++++++------------ drivers/net/wireless/ath/carl9170/usb.c | 5 ++- 5 files changed, 34 insertions(+), 31 deletions(-)
Christian Lamparter
maintainerPATCH 1/7 carl9170: use rx chainmask from eeprom
The eeprom provides a mask for all present rx chains. Why not use it instead of the generic initval default?
--- drivers/net/wireless/ath/carl9170/phy.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-)
drivers/net/wireless/ath/carl9170/phy.c +4 -1
@@ -532,8 +532,11 @@ static int carl9170_init_phy_from_eeprom(struct ar9170 *ar,SET_VAL (AR9170_PHY_TPCRG1_PD_GAIN_2 , val, xpd2pd[m->xpdGain &0xf ] >>2 );carl9170_regwrite (AR9170_PHY_REG_TPCRG1 , val); -carl9170_regwrite_finish (); +carl9170_regwrite (AR9170_PHY_REG_RX_CHAINMASK , ar->eeprom.rx_mask); +carl9170_regwrite (AR9170_PHY_REG_CAL_CHAINMASK , ar->eeprom.rx_mask); + +carl9170_regwrite_finish ();return carl9170_regwrite_result (); }
Signature · 1 line
1.7.1
Christian Lamparter
maintainerPATCH 2/7 carl9170: fix noise dBm conversion
In reply to Christian LamparterEver since carl9170 gained support to read the noisefloor, the reported noisefloor level was pretty poor.
Initially I assumed that something was wrong in the PHY setup and it would be impossible to fix without any guidances. But this was not the case. In fact the nf readings were correct and the thing that was broken was the "simple" sign extension code!
--- drivers/net/wireless/ath/carl9170/phy.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/carl9170/phy.c +2 -2
@@ -1558,9 +1558,9 @@ static int carl9170_set_power_cal(struct ar9170 *ar, u32 freq,static int carl9170_calc_noise_dbm (u32 raw_noise) {if (raw_noise &0x100 ) -return ~((raw_noise &0x0ff ) >>1 ); +return ~0x1ff | raw_noise;else -return (raw_noise &0xff ) >>1 ; +return raw_noise; }int carl9170_get_noisefloor (struct ar9170 *ar)
Signature · 1 line
1.7.1
Christian Lamparter
maintainerPATCH 3/7 carl9170: don't load bogus nf of chain 1
In reply to Christian LamparterAccording to Atheros, chain 1 is not connected.
--- drivers/net/wireless/ath/carl9170/carl9170.h | 2 +- drivers/net/wireless/ath/carl9170/debug.c | 8 +++----- drivers/net/wireless/ath/carl9170/phy.c | 11 +++++------ 3 files changed, 9 insertions(+), 12 deletions(-)
drivers/net/wireless/ath/carl9170/carl9170.h +1 -1
@@ -321,7 +321,7 @@ struct ar9170 {/* PHY */ struct ieee80211_channel *channel; -int noise[6 ]; +int noise[4 ];unsigned int chan_fail;unsigned int total_chan_fail;u8 heavy_clip;
drivers/net/wireless/ath/carl9170/debug.c +3 -5
@@ -437,12 +437,10 @@ static char *carl9170_debugfs_phy_noise_read(struct ar9170 *ar, char *buf,return buf; } -ADD (buf, *len, bufsize,"Chain 1: %10d dBm, ext. chan.:%10d dBm\n" , - ar->noise[1 ], ar->noise[4 ]); +ADD (buf, *len, bufsize,"Chain 0: %10d dBm, ext. chan.:%10d dBm\n" , + ar->noise[0 ], ar->noise[2 ]);ADD (buf, *len, bufsize,"Chain 2: %10d dBm, ext. chan.:%10d dBm\n" , - ar->noise[2 ], ar->noise[5 ]); -ADD (buf, *len, bufsize,"Combined %10d dBm, ext. chan.:%10d dBm\n" , - ar->noise[0 ], ar->noise[3 ]); + ar->noise[1 ], ar->noise[3 ]);return buf; }
drivers/net/wireless/ath/carl9170/phy.c +5 -6
@@ -1566,9 +1566,8 @@ static int carl9170_calc_noise_dbm(u32 raw_noise)int carl9170_get_noisefloor (struct ar9170 *ar) {static const u32 phy_regs[] = { -AR9170_PHY_REG_CCA ,AR9170_PHY_REG_CH1_CCA , -AR9170_PHY_REG_CH2_CCA ,AR9170_PHY_REG_EXT_CCA , -AR9170_PHY_REG_CH1_EXT_CCA ,AR9170_PHY_REG_CH2_EXT_CCA }; +AR9170_PHY_REG_CCA ,AR9170_PHY_REG_CH2_CCA , +AR9170_PHY_REG_EXT_CCA ,AR9170_PHY_REG_CH2_EXT_CCA };u32 phy_res[ARRAY_SIZE (phy_regs)];int err, i;
@@ -1578,12 +1577,12 @@ int carl9170_get_noisefloor(struct ar9170 *ar)if (err)return err; -for (i =0 ; i <3 ; i++) { +for (i =0 ; i <2 ; i++) { ar->noise[i] =carl9170_calc_noise_dbm ( (phy_res[i] >>19 ) &0x1ff ); - ar->noise[i +3 ] =carl9170_calc_noise_dbm ( - (phy_res[i +3 ] >>23 ) &0x1ff ); + ar->noise[i +2 ] =carl9170_calc_noise_dbm ( + (phy_res[i +2 ] >>23 ) &0x1ff ); }return 0 ;
Signature · 1 line
1.7.1
Christian Lamparter
maintainerPATCH 4/7 carl9170: abort tasklet during usb reset
In reply to Christian LamparterThis patch prevents the tasklet code from
interfering while the firmware is down for
an unscheduled maintenance.
--- drivers/net/wireless/ath/carl9170/usb.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/carl9170/usb.c +3 -0
@@ -367,6 +367,9 @@ static void carl9170_usb_tasklet(unsigned long data) {struct ar9170 *ar = (struct ar9170 *) data; +if (!IS_INITIALIZED (ar)) +return ; +carl9170_usb_rx_work (ar);/*
Signature · 1 line
1.7.1
Christian Lamparter
maintainerPATCH 5/7 carl9170: fix state downgrade during reset
In reply to Christian LamparterDon't mark the device as completely dead just yet. If all goes to plan and carl9170_reboot succeeds then we can skip the expensive userspace-driven reinitialization anyway.
And if it doesn't and carl9170_reboot fails, then carl9170_usb_cancel_urbs will do the necessary steps.
--- drivers/net/wireless/ath/carl9170/usb.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/carl9170/usb.c +0 -2
@@ -846,8 +846,6 @@ int carl9170_usb_restart(struct ar9170 *ar)carl9170_usb_stop (ar); -carl9170_set_state (ar,CARL9170_UNKNOWN_STATE ); -if (err) goto err_out;
Signature · 1 line
1.7.1
Christian Lamparter
maintainerPATCH 6/7 carl9170: reinit phy after HT settings have changed
In reply to Christian LamparterThe driver has a set of different initvals for 20 MHz vs dynamic HT2040 operation. Because we can't change some of the registers "in-flight", the driver needs to perform a warm reset.
--- drivers/net/wireless/ath/carl9170/carl9170.h | 1 + drivers/net/wireless/ath/carl9170/phy.c | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-)
drivers/net/wireless/ath/carl9170/carl9170.h +1 -0
@@ -325,6 +325,7 @@ struct ar9170 {unsigned int chan_fail;unsigned int total_chan_fail;u8 heavy_clip; +u8 ht_settings;/* power calibration data */ u8 power_5G_leg[4 ];
drivers/net/wireless/ath/carl9170/phy.c +13 -12
@@ -1610,7 +1610,7 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,const struct carl9170_phy_freq_params *freqpar;struct carl9170_rf_init_result rf_res;struct carl9170_rf_init rf; -u32 cmd, tmp, offs =0 ; +u32 cmd, tmp, offs =0 , new_ht =0 ;int err;enum carl9170_bw bw;bool warm_reset;
@@ -1618,12 +1618,19 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, bw =nl80211_to_carl (_bw); +if (conf_is_ht (&ar->hw->conf)) + new_ht |=CARL9170FW_PHY_HT_ENABLE ; + +if (conf_is_ht40 (&ar->hw->conf)) + new_ht |=CARL9170FW_PHY_HT_DYN2040 ; +/* may be NULL at first setup */ if (ar->channel) { old_channel = ar->channel; warm_reset = (old_channel->band != channel->band) || (old_channel->center_freq == - channel->center_freq); + channel->center_freq) || + (ar->ht_settings != new_ht); ar->channel =NULL ; }else {
@@ -1724,16 +1731,9 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, freqpar =carl9170_get_hw_dyn_params (channel, bw); - rf.ht_settings =0 ; -if (conf_is_ht (&ar->hw->conf)) { - rf.ht_settings |=CARL9170FW_PHY_HT_ENABLE ; - -if (conf_is_ht40 (&ar->hw->conf)) { - rf.ht_settings |=CARL9170FW_PHY_HT_DYN2040 ; -SET_VAL (CARL9170FW_PHY_HT_EXT_CHAN_OFF , - rf.ht_settings, offs); - } - } + rf.ht_settings = new_ht; +if (conf_is_ht40 (&ar->hw->conf)) +SET_VAL (CARL9170FW_PHY_HT_EXT_CHAN_OFF , rf.ht_settings, offs); rf.freq =cpu_to_le32 (channel->center_freq *1000 ); rf.delta_slope_coeff_exp =cpu_to_le32 (freqpar->coeff_exp);
@@ -1805,5 +1805,6 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, ar->ps.off_override &= ~PS_OFF_5GHZ ; ar->channel = channel; + ar->ht_settings = new_ht;return 0 ; }
Signature · 1 line
1.7.1
Christian Lamparter
maintainerPATCH 7/7 carl9170: fix hang in AP mode when HT STA does PSM
In reply to Christian LamparterThis is a obvious bug, skb_queue_walk does not
work if the iterator gets removed from the queue.
--- drivers/net/wireless/ath/carl9170/main.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/carl9170/main.c +2 -2
@@ -1412,7 +1412,7 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, {struct ar9170 *ar = hw->priv;struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; -struct sk_buff *skb; +struct sk_buff *skb, *tmp;struct sk_buff_head free;int i;
@@ -1462,7 +1462,7 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw,for (i =0 ; i < ar->hw->queues; i++) {spin_lock_bh (&ar->tx_pending[i].lock); - skb_queue_walk(&ar->tx_pending[i], skb) { + skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) {struct _carl9170_tx_superframe *super;struct ieee80211_hdr *hdr;
Signature · 1 line
1.7.1