Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −7
Original line number Original line Diff line number Diff line
@@ -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);


/* 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 */
+1 −1
Original line number Original line Diff line number Diff line
@@ -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;


+1 −1
Original line number Original line Diff line number Diff line
@@ -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;


+24 −57
Original line number Original line Diff line number Diff line
@@ -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,31 +1590,12 @@ 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 (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)
	if (err)
		return err;
		return err;


@@ -1633,11 +1612,6 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
	if (err)
	if (err)
		return err;
		return err;


		cmd = CARL9170_CMD_RF_INIT;
	} else {
		cmd = CARL9170_CMD_FREQUENCY;
	}

	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)
		return err;
		return err;
@@ -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);

	if (rfi != CARL9170_RFI_NONE)
	rf.finiteLoopCount = cpu_to_le32(2000);
	rf.finiteLoopCount = cpu_to_le32(2000);
	else
	err = carl9170_exec_cmd(ar, CARL9170_CMD_RF_INIT, sizeof(rf), &rf,
		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,
			  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,
			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 {