Skip to contentSkip to conversation

carl9170: PHY updates + hang fix

PATCH New Christian Lamparter 1 participant 8 messages Sep 17, 2010 CARL9170 Linux community wireless driver

lore
Share & tools
lore

Christian Lamparter

author maintainer
#0 lore raw

cover 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(-)
author maintainer
#1 lore raw

PATCH 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
index 71dea97..fe265e3 100644
@@ -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
author maintainer
#2 lore raw

PATCH 2/7 carl9170: fix noise dBm conversion

In reply to Christian Lamparter

Ever 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
index fe265e3..7df8f71 100644
@@ -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
author maintainer
#3 lore raw

PATCH 3/7 carl9170: don't load bogus nf of chain 1

In reply to Christian Lamparter

According 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
index 9f1d603..d43675a 100644
@@ -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
index 6559381..dbb35c3 100644
@@ -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
index 7df8f71..fa349b8 100644
@@ -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
author maintainer
#4 lore raw

PATCH 4/7 carl9170: abort tasklet during usb reset

In reply to Christian Lamparter

This 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
index fde918d..1e7c274 100644
@@ -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
author maintainer
#5 lore raw

PATCH 5/7 carl9170: fix state downgrade during reset

In reply to Christian Lamparter

Don'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
index 1e7c274..eb789a9 100644
@@ -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
author maintainer
#6 lore raw

PATCH 6/7 carl9170: reinit phy after HT settings have changed

In reply to Christian Lamparter

The 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
index d43675a..d7c5482 100644
@@ -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
index fa349b8..89deca3 100644
@@ -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
author maintainer
#7 lore raw

PATCH 7/7 carl9170: fix hang in AP mode when HT STA does PSM

In reply to Christian Lamparter

This 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
index ea49d54..43de9df 100644
@@ -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