Commit 56771e50 authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

carl9170: remove fast channel change feature

Marco Fonseca reported a issue with his carl9170 device:
"I'm seeing a problem with the carl driver. If I change channels
repeatedly on the 2.4ghz band, monitoring (e.g. tcpdump) will
eventually halt.  I've seen this on various versions of the carl
driver/firmware (both from 1.9.4 to 1.9.7)"
<http://marc.info/?l=linux-wireless&m=136381302428113>

The culprit was identified as "fast channel change feature" which
according to Adrian Chadd is: "... notoriously unreliable and
really only fully debugged on some very later chips."
<http://marc.info/?l=linux-wireless&m=136416984531380>

Therefore, this patch removes the fast channel change feature.
The phy will now always have to go through a cold reset when
changing channels, but it should no longer become deaf.

Cc: Marco Fonseca <marco@tampabay.rr.com>
Signed-off-by: default avatarChristian Lamparter <chunkeey@googlemail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent fe21bb02
...@@ -70,12 +70,6 @@ ...@@ -70,12 +70,6 @@
static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 3, 2, 1, 0 }; static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 3, 2, 1, 0 };
enum carl9170_rf_init_mode {
CARL9170_RFI_NONE,
CARL9170_RFI_WARM,
CARL9170_RFI_COLD,
};
#define CARL9170_MAX_RX_BUFFER_SIZE 8192 #define CARL9170_MAX_RX_BUFFER_SIZE 8192
enum carl9170_device_state { enum carl9170_device_state {
...@@ -599,7 +593,7 @@ int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state); ...@@ -599,7 +593,7 @@ int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state);
/* PHY / RF */ /* PHY / RF */
int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
enum nl80211_channel_type bw, enum carl9170_rf_init_mode rfi); enum nl80211_channel_type bw);
int carl9170_get_noisefloor(struct ar9170 *ar); int carl9170_get_noisefloor(struct ar9170 *ar);
/* FW */ /* FW */
......
...@@ -655,7 +655,7 @@ static ssize_t carl9170_debugfs_bug_write(struct ar9170 *ar, const char *buf, ...@@ -655,7 +655,7 @@ static ssize_t carl9170_debugfs_bug_write(struct ar9170 *ar, const char *buf,
case 'P': case 'P':
err = carl9170_set_channel(ar, ar->hw->conf.channel, err = carl9170_set_channel(ar, ar->hw->conf.channel,
ar->hw->conf.channel_type, CARL9170_RFI_COLD); ar->hw->conf.channel_type);
if (err < 0) if (err < 0)
count = err; count = err;
......
...@@ -939,7 +939,7 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed) ...@@ -939,7 +939,7 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
goto out; goto out;
err = carl9170_set_channel(ar, hw->conf.channel, err = carl9170_set_channel(ar, hw->conf.channel,
hw->conf.channel_type, CARL9170_RFI_NONE); hw->conf.channel_type);
if (err) if (err)
goto out; goto out;
......
...@@ -1569,16 +1569,14 @@ static enum carl9170_bw nl80211_to_carl(enum nl80211_channel_type type) ...@@ -1569,16 +1569,14 @@ static enum carl9170_bw nl80211_to_carl(enum nl80211_channel_type type)
} }
int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
enum nl80211_channel_type _bw, enum nl80211_channel_type _bw)
enum carl9170_rf_init_mode rfi)
{ {
const struct carl9170_phy_freq_params *freqpar; const struct carl9170_phy_freq_params *freqpar;
struct carl9170_rf_init_result rf_res; struct carl9170_rf_init_result rf_res;
struct carl9170_rf_init rf; struct carl9170_rf_init rf;
u32 cmd, tmp, offs = 0, new_ht = 0; u32 tmp, offs = 0, new_ht = 0;
int err; int err;
enum carl9170_bw bw; enum carl9170_bw bw;
bool warm_reset;
struct ieee80211_channel *old_channel = NULL; struct ieee80211_channel *old_channel = NULL;
bw = nl80211_to_carl(_bw); bw = nl80211_to_carl(_bw);
...@@ -1592,51 +1590,27 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, ...@@ -1592,51 +1590,27 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
/* may be NULL at first setup */ /* may be NULL at first setup */
if (ar->channel) { if (ar->channel) {
old_channel = ar->channel; old_channel = ar->channel;
warm_reset = (old_channel->band != channel->band) ||
(old_channel->center_freq ==
channel->center_freq) ||
(ar->ht_settings != new_ht);
ar->channel = NULL; ar->channel = NULL;
} else {
warm_reset = true;
} }
/* HW workaround */ /* cold reset BB/ADDA */
if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] && err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET,
channel->center_freq <= 2417) AR9170_PWR_RESET_BB_COLD_RESET);
warm_reset = true; if (err)
return err;
if (rfi != CARL9170_RFI_NONE || warm_reset) {
u32 val;
if (rfi == CARL9170_RFI_COLD)
val = AR9170_PWR_RESET_BB_COLD_RESET;
else
val = AR9170_PWR_RESET_BB_WARM_RESET;
/* warm/cold reset BB/ADDA */
err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, val);
if (err)
return err;
err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, 0x0);
if (err)
return err;
err = carl9170_init_phy(ar, channel->band); err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, 0x0);
if (err) if (err)
return err; return err;
err = carl9170_init_rf_banks_0_7(ar, err = carl9170_init_phy(ar, channel->band);
channel->band == IEEE80211_BAND_5GHZ); if (err)
if (err) return err;
return err;
cmd = CARL9170_CMD_RF_INIT; err = carl9170_init_rf_banks_0_7(ar,
} else { channel->band == IEEE80211_BAND_5GHZ);
cmd = CARL9170_CMD_FREQUENCY; if (err)
} return err;
err = carl9170_exec_cmd(ar, CARL9170_CMD_FREQ_START, 0, NULL, 0, NULL); err = carl9170_exec_cmd(ar, CARL9170_CMD_FREQ_START, 0, NULL, 0, NULL);
if (err) if (err)
...@@ -1648,8 +1622,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, ...@@ -1648,8 +1622,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
return err; return err;
err = carl9170_init_rf_bank4_pwr(ar, err = carl9170_init_rf_bank4_pwr(ar,
channel->band == IEEE80211_BAND_5GHZ, channel->band == IEEE80211_BAND_5GHZ,
channel->center_freq, bw); channel->center_freq, bw);
if (err) if (err)
return err; return err;
...@@ -1703,13 +1677,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, ...@@ -1703,13 +1677,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
rf.delta_slope_coeff_man = cpu_to_le32(freqpar->coeff_man); rf.delta_slope_coeff_man = cpu_to_le32(freqpar->coeff_man);
rf.delta_slope_coeff_exp_shgi = cpu_to_le32(freqpar->coeff_exp_shgi); rf.delta_slope_coeff_exp_shgi = cpu_to_le32(freqpar->coeff_exp_shgi);
rf.delta_slope_coeff_man_shgi = cpu_to_le32(freqpar->coeff_man_shgi); rf.delta_slope_coeff_man_shgi = cpu_to_le32(freqpar->coeff_man_shgi);
rf.finiteLoopCount = cpu_to_le32(2000);
if (rfi != CARL9170_RFI_NONE) err = carl9170_exec_cmd(ar, CARL9170_CMD_RF_INIT, sizeof(rf), &rf,
rf.finiteLoopCount = cpu_to_le32(2000);
else
rf.finiteLoopCount = cpu_to_le32(1000);
err = carl9170_exec_cmd(ar, cmd, sizeof(rf), &rf,
sizeof(rf_res), &rf_res); sizeof(rf_res), &rf_res);
if (err) if (err)
return err; return err;
...@@ -1724,9 +1693,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, ...@@ -1724,9 +1693,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
old_channel->center_freq : -1, channel->center_freq, old_channel->center_freq : -1, channel->center_freq,
err); err);
if ((rfi == CARL9170_RFI_COLD) || (ar->chan_fail > 3)) { if (ar->chan_fail > 3) {
/* /* We have tried very hard to change to _another_
* We have tried very hard to change to _another_
* channel and we've failed to do so! * channel and we've failed to do so!
* Chances are that the PHY/RF is no longer * Chances are that the PHY/RF is no longer
* operable (due to corruptions/fatal events/bugs?) * operable (due to corruptions/fatal events/bugs?)
...@@ -1736,8 +1704,7 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, ...@@ -1736,8 +1704,7 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
return 0; return 0;
} }
err = carl9170_set_channel(ar, channel, _bw, err = carl9170_set_channel(ar, channel, _bw);
CARL9170_RFI_COLD);
if (err) if (err)
return err; return err;
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment