linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] ath9k: prevent calibration during off-channel activity
@ 2010-07-28 17:45 Felix Fietkau
  2010-07-28 17:45 ` [PATCH 2/3] ath9k_hw: clean up per-channel calibration data Felix Fietkau
  2010-07-28 20:43 ` [PATCH 1/3] ath9k: prevent calibration during off-channel activity Luis R. Rodriguez
  0 siblings, 2 replies; 16+ messages in thread
From: Felix Fietkau @ 2010-07-28 17:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

Previously the software scan callback was used to indicate to the hardware,
when it was safe to calibrate. This didn't really work properly, because it
depends on a specific order of software scan callbacks vs. channel changes.
Also, software scans are not the only thing that triggers off-channel
activity, so it's better to use the newly added indication from mac80211 for
this and not use the software scan callback for anything calibration related.

This fixes at least some of the invalid noise floor readings that I've seen
in AP mode on AR9160

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    3 +-
 drivers/net/wireless/ath/ath9k/main.c  |   75 ++++++++++++++++---------------
 drivers/net/wireless/ath/ath9k/recv.c  |    4 +-
 3 files changed, 42 insertions(+), 40 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 998ae2c..9e967b1 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -510,13 +510,12 @@ void ath_deinit_leds(struct ath_softc *sc);
 #define SC_OP_BEACONS                BIT(1)
 #define SC_OP_RXAGGR                 BIT(2)
 #define SC_OP_TXAGGR                 BIT(3)
-#define SC_OP_FULL_RESET             BIT(4)
 #define SC_OP_PREAMBLE_SHORT         BIT(5)
 #define SC_OP_PROTECT_ENABLE         BIT(6)
 #define SC_OP_RXFLUSH                BIT(7)
 #define SC_OP_LED_ASSOCIATED         BIT(8)
 #define SC_OP_LED_ON                 BIT(9)
-#define SC_OP_SCANNING               BIT(10)
+#define SC_OP_OFFCHANNEL             BIT(10)
 #define SC_OP_TSF_RESET              BIT(11)
 #define SC_OP_BT_PRIORITY_DETECTED   BIT(12)
 #define SC_OP_BT_SCAN		     BIT(13)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 0429dda..c82d8c4 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -154,6 +154,27 @@ void ath9k_ps_restore(struct ath_softc *sc)
 	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 }
 
+static void ath_start_ani(struct ath_common *common)
+{
+	struct ath_hw *ah = common->ah;
+	unsigned long timestamp = jiffies_to_msecs(jiffies);
+	struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+	if (!(sc->sc_flags & SC_OP_ANI_RUN))
+		return;
+
+	if (sc->sc_flags & SC_OP_OFFCHANNEL)
+		return;
+
+	common->ani.longcal_timer = timestamp;
+	common->ani.shortcal_timer = timestamp;
+	common->ani.checkani_timer = timestamp;
+
+	mod_timer(&common->ani.timer,
+		  jiffies +
+			msecs_to_jiffies((u32)ah->config.ani_poll_interval));
+}
+
 /*
  * Set/change channels.  If the channel is really being changed, it's done
  * by reseting the chip.  To accomplish this we must first cleanup any pending
@@ -172,6 +193,11 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	if (sc->sc_flags & SC_OP_INVALID)
 		return -EIO;
 
+	del_timer_sync(&common->ani.timer);
+	cancel_work_sync(&sc->paprd_work);
+	cancel_work_sync(&sc->hw_check_work);
+	cancel_delayed_work_sync(&sc->tx_complete_work);
+
 	ath9k_ps_wakeup(sc);
 
 	/*
@@ -191,7 +217,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	 * to flush data frames already in queue because of
 	 * changing channel. */
 
-	if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET))
+	if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL))
 		fastcc = false;
 
 	ath_print(common, ATH_DBG_CONFIG,
@@ -212,8 +238,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	}
 	spin_unlock_bh(&sc->sc_resetlock);
 
-	sc->sc_flags &= ~SC_OP_FULL_RESET;
-
 	if (ath_startrecv(sc) != 0) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to restart recv logic\n");
@@ -225,6 +249,12 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	ath_update_txpow(sc);
 	ath9k_hw_set_interrupts(ah, ah->imask);
 
+	if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) {
+		ath_start_ani(common);
+		ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+		ath_beacon_config(sc, NULL);
+	}
+
  ps_restore:
 	ath9k_ps_restore(sc);
 	return r;
@@ -439,8 +469,7 @@ set_timer:
 		cal_interval = min(cal_interval, (u32)short_cal_interval);
 
 	mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) &&
-	    !(sc->sc_flags & SC_OP_SCANNING)) {
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) {
 		if (!sc->sc_ah->curchan->paprd_done)
 			ieee80211_queue_work(sc->hw, &sc->paprd_work);
 		else
@@ -448,24 +477,6 @@ set_timer:
 	}
 }
 
-static void ath_start_ani(struct ath_common *common)
-{
-	struct ath_hw *ah = common->ah;
-	unsigned long timestamp = jiffies_to_msecs(jiffies);
-	struct ath_softc *sc = (struct ath_softc *) common->priv;
-
-	if (!(sc->sc_flags & SC_OP_ANI_RUN))
-		return;
-
-	common->ani.longcal_timer = timestamp;
-	common->ani.shortcal_timer = timestamp;
-	common->ani.checkani_timer = timestamp;
-
-	mod_timer(&common->ani.timer,
-		  jiffies +
-			msecs_to_jiffies((u32)ah->config.ani_poll_interval));
-}
-
 /*
  * Update tx/rx chainmask. For legacy association,
  * hard code chainmask to 1x1, for 11n association, use
@@ -477,7 +488,7 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht)
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 
-	if ((sc->sc_flags & SC_OP_SCANNING) || is_ht ||
+	if ((sc->sc_flags & SC_OP_OFFCHANNEL) || is_ht ||
 	    (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE)) {
 		common->tx_chainmask = ah->caps.tx_chainmask;
 		common->rx_chainmask = ah->caps.rx_chainmask;
@@ -1579,6 +1590,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 
 		aphy->chan_idx = pos;
 		aphy->chan_is_ht = conf_is_ht(conf);
+		if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+			sc->sc_flags |= SC_OP_OFFCHANNEL;
+		else
+			sc->sc_flags &= ~SC_OP_OFFCHANNEL;
 
 		if (aphy->state == ATH_WIPHY_SCAN ||
 		    aphy->state == ATH_WIPHY_ACTIVE)
@@ -1990,7 +2005,6 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
 	mutex_lock(&sc->mutex);
 	if (ath9k_wiphy_scanning(sc)) {
@@ -2007,11 +2021,6 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 
 	aphy->state = ATH_WIPHY_SCAN;
 	ath9k_wiphy_pause_all_forced(sc, aphy);
-	sc->sc_flags |= SC_OP_SCANNING;
-	del_timer_sync(&common->ani.timer);
-	cancel_work_sync(&sc->paprd_work);
-	cancel_work_sync(&sc->hw_check_work);
-	cancel_delayed_work_sync(&sc->tx_complete_work);
 	mutex_unlock(&sc->mutex);
 }
 
@@ -2023,15 +2032,9 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
-	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
 	mutex_lock(&sc->mutex);
 	aphy->state = ATH_WIPHY_ACTIVE;
-	sc->sc_flags &= ~SC_OP_SCANNING;
-	sc->sc_flags |= SC_OP_FULL_RESET;
-	ath_start_ani(common);
-	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
-	ath_beacon_config(sc, NULL);
 	mutex_unlock(&sc->mutex);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index da0cfe9..4125ca2 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -292,7 +292,7 @@ static void ath_edma_start_recv(struct ath_softc *sc)
 
 	ath_opmode_init(sc);
 
-	ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_SCANNING));
+	ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
 }
 
 static void ath_edma_stop_recv(struct ath_softc *sc)
@@ -498,7 +498,7 @@ int ath_startrecv(struct ath_softc *sc)
 start_recv:
 	spin_unlock_bh(&sc->rx.rxbuflock);
 	ath_opmode_init(sc);
-	ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_SCANNING));
+	ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
 
 	return 0;
 }
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/3] ath9k_hw: clean up per-channel calibration data
  2010-07-28 17:45 [PATCH 1/3] ath9k: prevent calibration during off-channel activity Felix Fietkau
@ 2010-07-28 17:45 ` Felix Fietkau
  2010-07-28 17:45   ` [PATCH 3/3] ath9k_hw: fix a noise floor calibration related race condition Felix Fietkau
  2010-07-28 20:52   ` [PATCH 2/3] ath9k_hw: clean up per-channel calibration data Luis R. Rodriguez
  2010-07-28 20:43 ` [PATCH 1/3] ath9k: prevent calibration during off-channel activity Luis R. Rodriguez
  1 sibling, 2 replies; 16+ messages in thread
From: Felix Fietkau @ 2010-07-28 17:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

The noise floor history buffer is currently not kept per channel, which
can lead to problems when changing channels from a clean channel to a
noisy one. Also when switching from HT20 to HT40, the noise floor
history buffer is full of measurements, but none of them contain data
for the extension channel, which it needs quite a bit of time to recover
from.

This patch puts all the per-channel calibration data into a single data
structure, and gives the the driver control over whether that is used
per-channel or even not used for some channels.

For ath9k_htc, I decided to keep this per-channel in order to avoid
creating regressions.

For ath9k, the data is kept only for the operating channel, which saves
some space. ath9k_hw takes care of wiping old data when the operating
channel or its channel flags change.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ar9002_calib.c |    8 +-
 drivers/net/wireless/ath/ath9k/ar9003_calib.c |    8 +-
 drivers/net/wireless/ath/ath9k/ar9003_paprd.c |   17 ++--
 drivers/net/wireless/ath/ath9k/ath9k.h        |    1 +
 drivers/net/wireless/ath/ath9k/calib.c        |   99 +++++++++++++------------
 drivers/net/wireless/ath/ath9k/calib.h        |    3 +-
 drivers/net/wireless/ath/ath9k/htc.h          |    2 +
 drivers/net/wireless/ath/ath9k/htc_drv_main.c |   10 ++-
 drivers/net/wireless/ath/ath9k/hw.c           |   18 +++--
 drivers/net/wireless/ath/ath9k/hw.h           |   24 ++++--
 drivers/net/wireless/ath/ath9k/main.c         |   32 +++++---
 drivers/net/wireless/ath/ath9k/xmit.c         |    2 +-
 12 files changed, 130 insertions(+), 94 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index dabafb8..4a7bcfa 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -63,6 +63,7 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
 				      u8 rxchainmask,
 				      struct ath9k_cal_list *currCal)
 {
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
 	bool iscaldone = false;
 
 	if (currCal->calState == CAL_RUNNING) {
@@ -81,14 +82,14 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
 				}
 
 				currCal->calData->calPostProc(ah, numChains);
-				ichan->CalValid |= currCal->calData->calType;
+				caldata->CalValid |= currCal->calData->calType;
 				currCal->calState = CAL_DONE;
 				iscaldone = true;
 			} else {
 				ar9002_hw_setup_calibration(ah, currCal);
 			}
 		}
-	} else if (!(ichan->CalValid & currCal->calData->calType)) {
+	} else if (!(caldata->CalValid & currCal->calData->calType)) {
 		ath9k_hw_reset_calibration(ah, currCal);
 	}
 
@@ -901,7 +902,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
 	}
 
-	chan->CalValid = 0;
+	if (ah->caldata)
+		ah->caldata->CalValid = 0;
 
 	return true;
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 5a06503..1c5dadc 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -68,6 +68,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
 				      u8 rxchainmask,
 				      struct ath9k_cal_list *currCal)
 {
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
 	/* Cal is assumed not done until explicitly set below */
 	bool iscaldone = false;
 
@@ -95,7 +96,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
 				currCal->calData->calPostProc(ah, numChains);
 
 				/* Calibration has finished. */
-				ichan->CalValid |= currCal->calData->calType;
+				caldata->CalValid |= currCal->calData->calType;
 				currCal->calState = CAL_DONE;
 				iscaldone = true;
 			} else {
@@ -106,7 +107,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
 			ar9003_hw_setup_calibration(ah, currCal);
 			}
 		}
-	} else if (!(ichan->CalValid & currCal->calData->calType)) {
+	} else if (!(caldata->CalValid & currCal->calData->calType)) {
 		/* If current cal is marked invalid in channel, kick it off */
 		ath9k_hw_reset_calibration(ah, currCal);
 	}
@@ -785,7 +786,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
 	if (ah->cal_list_curr)
 		ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
 
-	chan->CalValid = 0;
+	if (ah->caldata)
+		ah->caldata->CalValid = 0;
 
 	return true;
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index 49e0c86..7c38229 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -577,10 +577,11 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
 }
 
 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
-					struct ath9k_channel *chan, int chain)
+					struct ath9k_hw_cal_data *caldata,
+					int chain)
 {
-	u32 *paprd_table_val = chan->pa_table[chain];
-	u32 small_signal_gain = chan->small_signal_gain[chain];
+	u32 *paprd_table_val = caldata->pa_table[chain];
+	u32 small_signal_gain = caldata->small_signal_gain[chain];
 	u32 training_power;
 	u32 reg = 0;
 	int i;
@@ -654,17 +655,17 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
 }
 EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
 
-int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
-			      int chain)
+int ar9003_paprd_create_curve(struct ath_hw *ah,
+			      struct ath9k_hw_cal_data *caldata, int chain)
 {
-	u16 *small_signal_gain = &chan->small_signal_gain[chain];
-	u32 *pa_table = chan->pa_table[chain];
+	u16 *small_signal_gain = &caldata->small_signal_gain[chain];
+	u32 *pa_table = caldata->pa_table[chain];
 	u32 *data_L, *data_U;
 	int i, status = 0;
 	u32 *buf;
 	u32 reg;
 
-	memset(chan->pa_table[chain], 0, sizeof(chan->pa_table[chain]));
+	memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain]));
 
 	buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC);
 	if (!buf)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9e967b1..20f9002 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -608,6 +608,7 @@ struct ath_softc {
 struct ath_wiphy {
 	struct ath_softc *sc; /* shared for all virtual wiphys */
 	struct ieee80211_hw *hw;
+	struct ath9k_hw_cal_data caldata;
 	enum ath_wiphy_state {
 		ATH_WIPHY_INACTIVE,
 		ATH_WIPHY_ACTIVE,
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 139289e..52460bc 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -22,23 +22,6 @@
 /* We can tune this as we go by monitoring really low values */
 #define ATH9K_NF_TOO_LOW	-60
 
-/* AR5416 may return very high value (like -31 dBm), in those cases the nf
- * is incorrect and we should use the static NF value. Later we can try to
- * find out why they are reporting these values */
-
-static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
-{
-	if (nf > ATH9K_NF_TOO_LOW) {
-		ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
-			  "noise floor value detected (%d) is "
-			  "lower than what we think is a "
-			  "reasonable value (%d)\n",
-			  nf, ATH9K_NF_TOO_LOW);
-		return false;
-	}
-	return true;
-}
-
 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
 {
 	int16_t nfval;
@@ -121,6 +104,19 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
 	ah->cal_samples = 0;
 }
 
+static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
+				   struct ath9k_channel *chan)
+{
+	struct ath_nf_limits *limit;
+
+	if (!chan || IS_CHAN_2GHZ(chan))
+		limit = &ah->nf_2g;
+	else
+		limit = &ah->nf_5g;
+
+	return limit->nominal;
+}
+
 /* This is done for the currently configured channel */
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 {
@@ -128,7 +124,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 	struct ieee80211_conf *conf = &common->hw->conf;
 	struct ath9k_cal_list *currCal = ah->cal_list_curr;
 
-	if (!ah->curchan)
+	if (!ah->caldata)
 		return true;
 
 	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
@@ -151,7 +147,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 		  "Resetting Cal %d state for channel %u\n",
 		  currCal->calData->calType, conf->channel->center_freq);
 
-	ah->curchan->CalValid &= ~currCal->calData->calType;
+	ah->caldata->CalValid &= ~currCal->calData->calType;
 	currCal->calState = CAL_WAITING;
 
 	return false;
@@ -169,19 +165,28 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah)
 
 void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
 {
-	struct ath9k_nfcal_hist *h;
+	struct ath9k_nfcal_hist *h = NULL;
 	unsigned i, j;
 	int32_t val;
 	u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
 	struct ath_common *common = ath9k_hw_common(ah);
+	s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
 
-	h = ah->nfCalHist;
+	if (ah->caldata)
+		h = ah->caldata->nfCalHist;
 
 	for (i = 0; i < NUM_NF_READINGS; i++) {
 		if (chainmask & (1 << i)) {
+			s16 nfval;
+
+			if (h)
+				nfval = h[i].privNF;
+			else
+				nfval = default_nf;
+
 			val = REG_READ(ah, ah->nf_regs[i]);
 			val &= 0xFFFFFE00;
-			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+			val |= (((u32) nfval << 1) & 0x1ff);
 			REG_WRITE(ah, ah->nf_regs[i], val);
 		}
 	}
@@ -285,14 +290,18 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
 	int16_t nfarray[NUM_NF_READINGS] = { 0 };
 	struct ath9k_nfcal_hist *h;
 	struct ieee80211_channel *c = chan->chan;
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
+
+	if (!caldata)
+		return ath9k_hw_get_default_nf(ah, chan);
 
 	chan->channelFlags &= (~CHANNEL_CW_INT);
 	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
 		ath_print(common, ATH_DBG_CALIBRATE,
 			  "NF did not complete in calibration window\n");
 		nf = 0;
-		chan->rawNoiseFloor = nf;
-		return chan->rawNoiseFloor;
+		caldata->rawNoiseFloor = nf;
+		return caldata->rawNoiseFloor;
 	} else {
 		ath9k_hw_do_getnf(ah, nfarray);
 		ath9k_hw_nf_sanitize(ah, nfarray);
@@ -307,47 +316,41 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
 		}
 	}
 
-	h = ah->nfCalHist;
+	h = caldata->nfCalHist;
 
 	ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
-	chan->rawNoiseFloor = h[0].privNF;
+	caldata->rawNoiseFloor = h[0].privNF;
 
-	return chan->rawNoiseFloor;
+	return ah->caldata->rawNoiseFloor;
 }
 
-void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
+				  struct ath9k_channel *chan)
 {
-	struct ath_nf_limits *limit;
+	struct ath9k_nfcal_hist *h;
+	s16 default_nf;
 	int i, j;
 
-	if (!ah->curchan || IS_CHAN_2GHZ(ah->curchan))
-		limit = &ah->nf_2g;
-	else
-		limit = &ah->nf_5g;
+	if (!ah->caldata)
+		return;
 
+	h = ah->caldata->nfCalHist;
+	default_nf = ath9k_hw_get_default_nf(ah, chan);
 	for (i = 0; i < NUM_NF_READINGS; i++) {
-		ah->nfCalHist[i].currIndex = 0;
-		ah->nfCalHist[i].privNF = limit->nominal;
-		ah->nfCalHist[i].invalidNFcount =
-			AR_PHY_CCA_FILTERWINDOW_LENGTH;
+		h[i].currIndex = 0;
+		h[i].privNF = default_nf;
+		h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH;
 		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
-			ah->nfCalHist[i].nfCalBuffer[j] = limit->nominal;
+			h[i].nfCalBuffer[j] = default_nf;
 		}
 	}
 }
 
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
 {
-	s16 nf;
-
-	if (chan->rawNoiseFloor == 0)
-		nf = -96;
-	else
-		nf = chan->rawNoiseFloor;
-
-	if (!ath9k_hw_nf_in_range(ah, nf))
-		nf = ATH_DEFAULT_NOISE_FLOOR;
+	if (!ah->caldata || !ah->caldata->rawNoiseFloor)
+		return ath9k_hw_get_default_nf(ah, chan);
 
-	return nf;
+	return ah->caldata->rawNoiseFloor;
 }
 EXPORT_SYMBOL(ath9k_hw_getchan_noise);
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index cd60d09..09a0ed2 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -112,7 +112,8 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah);
 void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
 int16_t ath9k_hw_getnf(struct ath_hw *ah,
 		       struct ath9k_channel *chan);
-void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
+				  struct ath9k_channel *chan);
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
 void ath9k_hw_reset_calibration(struct ath_hw *ah,
 				struct ath9k_cal_list *currCal);
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 3756400..43b9e21 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -353,6 +353,8 @@ struct ath9k_htc_priv {
 	u16 seq_no;
 	u32 bmiss_cnt;
 
+	struct ath9k_hw_cal_data caldata[38];
+
 	spinlock_t beacon_lock;
 
 	bool tx_queues_stop;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index cf9bcc6..ebed9d1 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -125,6 +125,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 	struct ieee80211_conf *conf = &common->hw->conf;
 	bool fastcc = true;
 	struct ieee80211_channel *channel = hw->conf.channel;
+	struct ath9k_hw_cal_data *caldata;
 	enum htc_phymode mode;
 	__be16 htc_mode;
 	u8 cmd_rsp;
@@ -149,7 +150,8 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
 		  priv->ah->curchan->channel,
 		  channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
 
-	ret = ath9k_hw_reset(ah, hchan, fastcc);
+	caldata = &priv->caldata[channel->hw_value];
+	ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
 	if (ret) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset channel (%u Mhz) "
@@ -1028,7 +1030,7 @@ static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
 		ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 
 	/* Reset the HW */
-	ret = ath9k_hw_reset(ah, ah->curchan, false);
+	ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (ret) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d "
@@ -1091,7 +1093,7 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
 		ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
 
 	/* Reset the HW */
-	ret = ath9k_hw_reset(ah, ah->curchan, false);
+	ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (ret) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d "
@@ -1179,7 +1181,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
 	ath9k_hw_configpcipowersave(ah, 0, 0);
 
 	ath9k_hw_htc_resetinit(ah);
-	ret = ath9k_hw_reset(ah, init_channel, false);
+	ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
 	if (ret) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d "
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 2f83f97..ac8e0bb 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -609,7 +609,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 	else
 		ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
 
-	ath9k_init_nfcal_hist_buffer(ah);
 	ah->bb_watchdog_timeout_ms = 25;
 
 	common->state = ATH_HW_INITIALIZED;
@@ -1182,9 +1181,6 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
 
 	ath9k_hw_spur_mitigate_freq(ah, chan);
 
-	if (!chan->oneTimeCalsDone)
-		chan->oneTimeCalsDone = true;
-
 	return true;
 }
 
@@ -1217,7 +1213,7 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
 EXPORT_SYMBOL(ath9k_hw_check_alive);
 
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
-		    bool bChannelChange)
+		   struct ath9k_hw_cal_data *caldata, bool bChannelChange)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	u32 saveLedState;
@@ -1242,9 +1238,19 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
 		return -EIO;
 
-	if (curchan && !ah->chip_fullsleep)
+	if (curchan && !ah->chip_fullsleep && ah->caldata)
 		ath9k_hw_getnf(ah, curchan);
 
+	ah->caldata = caldata;
+	if (caldata &&
+	    (chan->channel != caldata->channel ||
+	     (chan->channelFlags & ~CHANNEL_CW_INT) !=
+	     (caldata->channelFlags & ~CHANNEL_CW_INT))) {
+		/* Operating channel changed, reset channel calibration data */
+		memset(caldata, 0, sizeof(*caldata));
+		ath9k_init_nfcal_hist_buffer(ah, chan);
+	}
+
 	if (bChannelChange &&
 	    (ah->chip_fullsleep != true) &&
 	    (ah->curchan != NULL) &&
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 2d30efc..c1b7011 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -346,19 +346,24 @@ enum ath9k_int {
 	 CHANNEL_HT40PLUS |			\
 	 CHANNEL_HT40MINUS)
 
-struct ath9k_channel {
-	struct ieee80211_channel *chan;
+struct ath9k_hw_cal_data {
 	u16 channel;
 	u32 channelFlags;
-	u32 chanmode;
 	int32_t CalValid;
-	bool oneTimeCalsDone;
 	int8_t iCoff;
 	int8_t qCoff;
 	int16_t rawNoiseFloor;
 	bool paprd_done;
 	u16 small_signal_gain[AR9300_MAX_CHAINS];
 	u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
+	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+};
+
+struct ath9k_channel {
+	struct ieee80211_channel *chan;
+	u16 channel;
+	u32 channelFlags;
+	u32 chanmode;
 };
 
 #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
@@ -669,7 +674,7 @@ struct ath_hw {
 	enum nl80211_iftype opmode;
 	enum ath9k_power_mode power_mode;
 
-	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+	struct ath9k_hw_cal_data *caldata;
 	struct ath9k_pacal_info pacal_info;
 	struct ar5416Stats stats;
 	struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
@@ -863,7 +868,7 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid);
 void ath9k_hw_deinit(struct ath_hw *ah);
 int ath9k_hw_init(struct ath_hw *ah);
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
-		   bool bChannelChange);
+		   struct ath9k_hw_cal_data *caldata, bool bChannelChange);
 int ath9k_hw_fill_cap_info(struct ath_hw *ah);
 u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
 
@@ -958,9 +963,10 @@ void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
 void ar9003_paprd_enable(struct ath_hw *ah, bool val);
 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
-					struct ath9k_channel *chan, int chain);
-int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
-			      int chain);
+					struct ath9k_hw_cal_data *caldata,
+					int chain);
+int ar9003_paprd_create_curve(struct ath_hw *ah,
+			      struct ath9k_hw_cal_data *caldata, int chain);
 int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain);
 int ar9003_paprd_init_table(struct ath_hw *ah);
 bool ar9003_paprd_is_done(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index c82d8c4..0b3f59a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -183,11 +183,13 @@ static void ath_start_ani(struct ath_common *common)
 int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 		    struct ath9k_channel *hchan)
 {
+	struct ath_wiphy *aphy = hw->priv;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ieee80211_conf *conf = &common->hw->conf;
 	bool fastcc = true, stopped;
 	struct ieee80211_channel *channel = hw->conf.channel;
+	struct ath9k_hw_cal_data *caldata = NULL;
 	int r;
 
 	if (sc->sc_flags & SC_OP_INVALID)
@@ -220,6 +222,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL))
 		fastcc = false;
 
+	if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
+		caldata = &aphy->caldata;
+
 	ath_print(common, ATH_DBG_CONFIG,
 		  "(%u MHz) -> (%u MHz), conf_is_ht40: %d\n",
 		  sc->sc_ah->curchan->channel,
@@ -227,7 +232,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 
 	spin_lock_bh(&sc->sc_resetlock);
 
-	r = ath9k_hw_reset(ah, hchan, fastcc);
+	r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset channel (%u MHz), "
@@ -263,9 +268,10 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 static void ath_paprd_activate(struct ath_softc *sc)
 {
 	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
 	int chain;
 
-	if (!ah->curchan->paprd_done)
+	if (!caldata || !caldata->paprd_done)
 		return;
 
 	ath9k_ps_wakeup(sc);
@@ -273,7 +279,7 @@ static void ath_paprd_activate(struct ath_softc *sc)
 		if (!(ah->caps.tx_chainmask & BIT(chain)))
 			continue;
 
-		ar9003_paprd_populate_single_table(ah, ah->curchan, chain);
+		ar9003_paprd_populate_single_table(ah, caldata, chain);
 	}
 
 	ar9003_paprd_enable(ah, true);
@@ -291,6 +297,7 @@ void ath_paprd_calibrate(struct work_struct *work)
 	int band = hw->conf.channel->band;
 	struct ieee80211_supported_band *sband = &sc->sbands[band];
 	struct ath_tx_control txctl;
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
 	int qnum, ftype;
 	int chain_ok = 0;
 	int chain;
@@ -298,6 +305,9 @@ void ath_paprd_calibrate(struct work_struct *work)
 	int time_left;
 	int i;
 
+	if (!caldata)
+		return;
+
 	skb = alloc_skb(len, GFP_KERNEL);
 	if (!skb)
 		return;
@@ -352,7 +362,7 @@ void ath_paprd_calibrate(struct work_struct *work)
 		if (!ar9003_paprd_is_done(ah))
 			break;
 
-		if (ar9003_paprd_create_curve(ah, ah->curchan, chain) != 0)
+		if (ar9003_paprd_create_curve(ah, caldata, chain) != 0)
 			break;
 
 		chain_ok = 1;
@@ -360,7 +370,7 @@ void ath_paprd_calibrate(struct work_struct *work)
 	kfree_skb(skb);
 
 	if (chain_ok) {
-		ah->curchan->paprd_done = true;
+		caldata->paprd_done = true;
 		ath_paprd_activate(sc);
 	}
 
@@ -469,8 +479,8 @@ set_timer:
 		cal_interval = min(cal_interval, (u32)short_cal_interval);
 
 	mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) {
-		if (!sc->sc_ah->curchan->paprd_done)
+	if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) {
+		if (!ah->caldata->paprd_done)
 			ieee80211_queue_work(sc->hw, &sc->paprd_work);
 		else
 			ath_paprd_activate(sc);
@@ -828,7 +838,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 		ah->curchan = ath_get_curchannel(sc, sc->hw);
 
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, ah->curchan, false);
+	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset channel (%u MHz), "
@@ -888,7 +898,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 		ah->curchan = ath_get_curchannel(sc, hw);
 
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, ah->curchan, false);
+	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (r) {
 		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
 			  "Unable to reset channel (%u MHz), "
@@ -921,7 +931,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 	ath_flushrecv(sc);
 
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
+	r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
 	if (r)
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d\n", r);
@@ -1096,7 +1106,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	 * and then setup of the interrupt mask.
 	 */
 	spin_lock_bh(&sc->sc_resetlock);
-	r = ath9k_hw_reset(ah, init_channel, false);
+	r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset hardware; reset status %d "
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 501b728..700ba8d 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1181,7 +1181,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
 			  "Failed to stop TX DMA. Resetting hardware!\n");
 
 		spin_lock_bh(&sc->sc_resetlock);
-		r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
+		r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
 		if (r)
 			ath_print(common, ATH_DBG_FATAL,
 				  "Unable to reset hardware; reset status %d\n",
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/3] ath9k_hw: fix a noise floor calibration related race condition
  2010-07-28 17:45 ` [PATCH 2/3] ath9k_hw: clean up per-channel calibration data Felix Fietkau
@ 2010-07-28 17:45   ` Felix Fietkau
  2010-07-28 20:52   ` [PATCH 2/3] ath9k_hw: clean up per-channel calibration data Luis R. Rodriguez
  1 sibling, 0 replies; 16+ messages in thread
From: Felix Fietkau @ 2010-07-28 17:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: linville, lrodriguez

On AR5008-AR9002, other forms of calibration must not be started while
the noise floor calibration is running, as this can create invalid
readings which were sometimes not even recoverable by any further
calibration attempts.

This patch also ensures that the result of noise floor measurements
are processed faster and also allows the result of the initial
calibration on reset to make it into the NF history buffer

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
 drivers/net/wireless/ath/ath9k/ar9002_calib.c |   32 ++++++++++++++++--------
 drivers/net/wireless/ath/ath9k/calib.c        |   15 ++++++-----
 drivers/net/wireless/ath/ath9k/calib.h        |    3 +-
 drivers/net/wireless/ath/ath9k/hw.h           |    1 +
 4 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 4a7bcfa..916cde7 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -687,8 +687,13 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
 {
 	bool iscaldone = true;
 	struct ath9k_cal_list *currCal = ah->cal_list_curr;
+	bool nfcal, nfcal_pending = false;
 
-	if (currCal &&
+	nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
+	if (ah->caldata)
+		nfcal_pending = ah->caldata->nfcal_pending;
+
+	if (currCal && !nfcal &&
 	    (currCal->calState == CAL_RUNNING ||
 	     currCal->calState == CAL_WAITING)) {
 		iscaldone = ar9002_hw_per_calibration(ah, chan,
@@ -704,7 +709,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
 	}
 
 	/* Do NF cal only at longer intervals */
-	if (longcal) {
+	if (longcal || nfcal_pending) {
 		/* Do periodic PAOffset Cal */
 		ar9002_hw_pa_cal(ah, false);
 		ar9002_hw_olc_temp_compensation(ah);
@@ -713,16 +718,18 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
 		 * Get the value from the previous NF cal and update
 		 * history buffer.
 		 */
-		ath9k_hw_getnf(ah, chan);
-
-		/*
-		 * Load the NF from history buffer of the current channel.
-		 * NF is slow time-variant, so it is OK to use a historical
-		 * value.
-		 */
-		ath9k_hw_loadnf(ah, ah->curchan);
+		if (ath9k_hw_getnf(ah, chan)) {
+			/*
+			 * Load the NF from history buffer of the current
+			 * channel.
+			 * NF is slow time-variant, so it is OK to use a
+			 * historical value.
+			 */
+			ath9k_hw_loadnf(ah, ah->curchan);
+		}
 
-		ath9k_hw_start_nfcal(ah);
+		if (longcal)
+			ath9k_hw_start_nfcal(ah);
 	}
 
 	return iscaldone;
@@ -873,6 +880,9 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
 		  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
 
+	if (ah->caldata)
+		ah->caldata->nfcal_pending = true;
+
 	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
 
 	/* Enable IQ, ADC Gain and ADC DC offset CALs */
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 52460bc..787657b 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -156,6 +156,9 @@ EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
 
 void ath9k_hw_start_nfcal(struct ath_hw *ah)
 {
+	if (ah->caldata)
+		ah->caldata->nfcal_pending = true;
+
 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
 		    AR_PHY_AGC_CONTROL_ENABLE_NF);
 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
@@ -282,8 +285,7 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
 	}
 }
 
-int16_t ath9k_hw_getnf(struct ath_hw *ah,
-		       struct ath9k_channel *chan)
+bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
 {
 	struct ath_common *common = ath9k_hw_common(ah);
 	int16_t nf, nfThresh;
@@ -293,7 +295,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
 	struct ath9k_hw_cal_data *caldata = ah->caldata;
 
 	if (!caldata)
-		return ath9k_hw_get_default_nf(ah, chan);
+		return false;
 
 	chan->channelFlags &= (~CHANNEL_CW_INT);
 	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
@@ -301,7 +303,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
 			  "NF did not complete in calibration window\n");
 		nf = 0;
 		caldata->rawNoiseFloor = nf;
-		return caldata->rawNoiseFloor;
+		return false;
 	} else {
 		ath9k_hw_do_getnf(ah, nfarray);
 		ath9k_hw_nf_sanitize(ah, nfarray);
@@ -317,11 +319,10 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
 	}
 
 	h = caldata->nfCalHist;
-
+	caldata->nfcal_pending = false;
 	ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
 	caldata->rawNoiseFloor = h[0].privNF;
-
-	return ah->caldata->rawNoiseFloor;
+	return true;
 }
 
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 09a0ed2..8381e81 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -110,8 +110,7 @@ struct ath9k_pacal_info{
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
 void ath9k_hw_start_nfcal(struct ath_hw *ah);
 void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
-int16_t ath9k_hw_getnf(struct ath_hw *ah,
-		       struct ath9k_channel *chan);
+bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
 				  struct ath9k_channel *chan);
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c1b7011..399f7c1 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -354,6 +354,7 @@ struct ath9k_hw_cal_data {
 	int8_t qCoff;
 	int16_t rawNoiseFloor;
 	bool paprd_done;
+	bool nfcal_pending;
 	u16 small_signal_gain[AR9300_MAX_CHAINS];
 	u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
 	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/3] ath9k: prevent calibration during off-channel activity
  2010-07-28 17:45 [PATCH 1/3] ath9k: prevent calibration during off-channel activity Felix Fietkau
  2010-07-28 17:45 ` [PATCH 2/3] ath9k_hw: clean up per-channel calibration data Felix Fietkau
@ 2010-07-28 20:43 ` Luis R. Rodriguez
  2010-07-28 21:08   ` Felix Fietkau
  1 sibling, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2010-07-28 20:43 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville

On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
> Previously the software scan callback was used to indicate to the hardware,
> when it was safe to calibrate. This didn't really work properly, because it
> depends on a specific order of software scan callbacks vs. channel changes.
> Also, software scans are not the only thing that triggers off-channel
> activity, so it's better to use the newly added indication from mac80211 for
> this and not use the software scan callback for anything calibration related.
>
> This fixes at least some of the invalid noise floor readings that I've seen
> in AP mode on AR9160

Neat!

> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -154,6 +154,27 @@ void ath9k_ps_restore(struct ath_softc *sc)
>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>  }
>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>  }
>
> +static void ath_start_ani(struct ath_common *common)
> +{
> +       struct ath_hw *ah = common->ah;
> +       unsigned long timestamp = jiffies_to_msecs(jiffies);
> +       struct ath_softc *sc = (struct ath_softc *) common->priv;
> +
> +       if (!(sc->sc_flags & SC_OP_ANI_RUN))
> +               return;
> +
> +       if (sc->sc_flags & SC_OP_OFFCHANNEL)
> +               return;
> +
> +       common->ani.longcal_timer = timestamp;
> +       common->ani.shortcal_timer = timestamp;
> +       common->ani.checkani_timer = timestamp;
> +
> +       mod_timer(&common->ani.timer,
> +                 jiffies +
> +                       msecs_to_jiffies((u32)ah->config.ani_poll_interval));
> +}

I would prefer if you do this sort of code shift in a separate patch.
In this case its pretty easy to see the code is the same so I think
its fine the way it is now but for next time please. Otherwise looks
good, thanks!!

  Luis

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/3] ath9k_hw: clean up per-channel calibration data
  2010-07-28 17:45 ` [PATCH 2/3] ath9k_hw: clean up per-channel calibration data Felix Fietkau
  2010-07-28 17:45   ` [PATCH 3/3] ath9k_hw: fix a noise floor calibration related race condition Felix Fietkau
@ 2010-07-28 20:52   ` Luis R. Rodriguez
  2010-07-28 21:10     ` Felix Fietkau
  1 sibling, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2010-07-28 20:52 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville, Jouni Malinen

On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
> The noise floor history buffer is currently not kept per channel, which
> can lead to problems when changing channels from a clean channel to a
> noisy one. Also when switching from HT20 to HT40, the noise floor
> history buffer is full of measurements, but none of them contain data
> for the extension channel, which it needs quite a bit of time to recover
> from.
>
> This patch puts all the per-channel calibration data into a single data
> structure, and gives the the driver control over whether that is used
> per-channel or even not used for some channels.
>
> For ath9k_htc, I decided to keep this per-channel in order to avoid
> creating regressions.
>
> For ath9k, the data is kept only for the operating channel, which saves
> some space. ath9k_hw takes care of wiping old data when the operating
> channel or its channel flags change.
>
> Signed-off-by: Felix Fietkau <nbd@openwrt.org>

But this also means every time we want to get operational on a channel
we have to learn the current noise all over again. This means for WiFi
Direct every channel swap we'd have to learn to walk, which happens
quite often. What do you think? Sorry, I know we discussed this
approach and I seemed fine but this just occurred to me now, and will
become really important later when we support WiFi Direct.

  Luis

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/3] ath9k: prevent calibration during off-channel  activity
  2010-07-28 20:43 ` [PATCH 1/3] ath9k: prevent calibration during off-channel activity Luis R. Rodriguez
@ 2010-07-28 21:08   ` Felix Fietkau
  2010-07-28 22:12     ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Felix Fietkau @ 2010-07-28 21:08 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless, linville

On 2010-07-28 10:43 PM, Luis R. Rodriguez wrote:
> On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
>> Previously the software scan callback was used to indicate to the hardware,
>> when it was safe to calibrate. This didn't really work properly, because it
>> depends on a specific order of software scan callbacks vs. channel changes.
>> Also, software scans are not the only thing that triggers off-channel
>> activity, so it's better to use the newly added indication from mac80211 for
>> this and not use the software scan callback for anything calibration related.
>>
>> This fixes at least some of the invalid noise floor readings that I've seen
>> in AP mode on AR9160
> 
> Neat!
> 
>> --- a/drivers/net/wireless/ath/ath9k/main.c
>> +++ b/drivers/net/wireless/ath/ath9k/main.c
>> @@ -154,6 +154,27 @@ void ath9k_ps_restore(struct ath_softc *sc)
>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>  }
>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>  }
>>
>> +static void ath_start_ani(struct ath_common *common)
>> +{
>> +       struct ath_hw *ah = common->ah;
>> +       unsigned long timestamp = jiffies_to_msecs(jiffies);
>> +       struct ath_softc *sc = (struct ath_softc *) common->priv;
>> +
>> +       if (!(sc->sc_flags & SC_OP_ANI_RUN))
>> +               return;
>> +
>> +       if (sc->sc_flags & SC_OP_OFFCHANNEL)
>> +               return;
>> +
>> +       common->ani.longcal_timer = timestamp;
>> +       common->ani.shortcal_timer = timestamp;
>> +       common->ani.checkani_timer = timestamp;
>> +
>> +       mod_timer(&common->ani.timer,
>> +                 jiffies +
>> +                       msecs_to_jiffies((u32)ah->config.ani_poll_interval));
>> +}
> 
> I would prefer if you do this sort of code shift in a separate patch.
> In this case its pretty easy to see the code is the same so I think
> its fine the way it is now but for next time please. Otherwise looks
> good, thanks!!
If it had been a bigger function, I'd have made a separate patch, but I
figured for something as trivial as this it wouldn't matter.

- Felix

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/3] ath9k_hw: clean up per-channel calibration data
  2010-07-28 20:52   ` [PATCH 2/3] ath9k_hw: clean up per-channel calibration data Luis R. Rodriguez
@ 2010-07-28 21:10     ` Felix Fietkau
  2010-07-28 21:21       ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Felix Fietkau @ 2010-07-28 21:10 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless, linville, Jouni Malinen

On 2010-07-28 10:52 PM, Luis R. Rodriguez wrote:
> On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
>> The noise floor history buffer is currently not kept per channel, which
>> can lead to problems when changing channels from a clean channel to a
>> noisy one. Also when switching from HT20 to HT40, the noise floor
>> history buffer is full of measurements, but none of them contain data
>> for the extension channel, which it needs quite a bit of time to recover
>> from.
>>
>> This patch puts all the per-channel calibration data into a single data
>> structure, and gives the the driver control over whether that is used
>> per-channel or even not used for some channels.
>>
>> For ath9k_htc, I decided to keep this per-channel in order to avoid
>> creating regressions.
>>
>> For ath9k, the data is kept only for the operating channel, which saves
>> some space. ath9k_hw takes care of wiping old data when the operating
>> channel or its channel flags change.
>>
>> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
> 
> But this also means every time we want to get operational on a channel
> we have to learn the current noise all over again. This means for WiFi
> Direct every channel swap we'd have to learn to walk, which happens
> quite often. What do you think? Sorry, I know we discussed this
> approach and I seemed fine but this just occurred to me now, and will
> become really important later when we support WiFi Direct.
When we get to implementing per-vif channel settings with switching
being done in mac80211, we can just move the calibration data to ath9k's
virtual interface data and thus keep the calibration for multiple
operating channels.

- Felix

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/3] ath9k_hw: clean up per-channel calibration data
  2010-07-28 21:10     ` Felix Fietkau
@ 2010-07-28 21:21       ` Luis R. Rodriguez
  2010-07-28 21:30         ` Felix Fietkau
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2010-07-28 21:21 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville, Jouni Malinen

On Wed, Jul 28, 2010 at 2:10 PM, Felix Fietkau <nbd@openwrt.org> wrote:
> On 2010-07-28 10:52 PM, Luis R. Rodriguez wrote:
>> On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
>>> The noise floor history buffer is currently not kept per channel, which
>>> can lead to problems when changing channels from a clean channel to a
>>> noisy one. Also when switching from HT20 to HT40, the noise floor
>>> history buffer is full of measurements, but none of them contain data
>>> for the extension channel, which it needs quite a bit of time to recover
>>> from.
>>>
>>> This patch puts all the per-channel calibration data into a single data
>>> structure, and gives the the driver control over whether that is used
>>> per-channel or even not used for some channels.
>>>
>>> For ath9k_htc, I decided to keep this per-channel in order to avoid
>>> creating regressions.
>>>
>>> For ath9k, the data is kept only for the operating channel, which saves
>>> some space. ath9k_hw takes care of wiping old data when the operating
>>> channel or its channel flags change.
>>>
>>> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
>>
>> But this also means every time we want to get operational on a channel
>> we have to learn the current noise all over again. This means for WiFi
>> Direct every channel swap we'd have to learn to walk, which happens
>> quite often. What do you think? Sorry, I know we discussed this
>> approach and I seemed fine but this just occurred to me now, and will
>> become really important later when we support WiFi Direct.
> When we get to implementing per-vif channel settings with switching
> being done in mac80211, we can just move the calibration data to ath9k's
> virtual interface data and thus keep the calibration for multiple
> operating channels.

Sounds good. This would currently break the ath9k virtual wiphy's
calibration stuff :P (not like I care), Jouni?

  Luis

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/3] ath9k_hw: clean up per-channel calibration data
  2010-07-28 21:21       ` Luis R. Rodriguez
@ 2010-07-28 21:30         ` Felix Fietkau
  2010-07-28 21:40           ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Felix Fietkau @ 2010-07-28 21:30 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless, linville, Jouni Malinen

On 2010-07-28 11:21 PM, Luis R. Rodriguez wrote:
> On Wed, Jul 28, 2010 at 2:10 PM, Felix Fietkau <nbd@openwrt.org> wrote:
>> On 2010-07-28 10:52 PM, Luis R. Rodriguez wrote:
>>> On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
>>>> The noise floor history buffer is currently not kept per channel, which
>>>> can lead to problems when changing channels from a clean channel to a
>>>> noisy one. Also when switching from HT20 to HT40, the noise floor
>>>> history buffer is full of measurements, but none of them contain data
>>>> for the extension channel, which it needs quite a bit of time to recover
>>>> from.
>>>>
>>>> This patch puts all the per-channel calibration data into a single data
>>>> structure, and gives the the driver control over whether that is used
>>>> per-channel or even not used for some channels.
>>>>
>>>> For ath9k_htc, I decided to keep this per-channel in order to avoid
>>>> creating regressions.
>>>>
>>>> For ath9k, the data is kept only for the operating channel, which saves
>>>> some space. ath9k_hw takes care of wiping old data when the operating
>>>> channel or its channel flags change.
>>>>
>>>> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
>>>
>>> But this also means every time we want to get operational on a channel
>>> we have to learn the current noise all over again. This means for WiFi
>>> Direct every channel swap we'd have to learn to walk, which happens
>>> quite often. What do you think? Sorry, I know we discussed this
>>> approach and I seemed fine but this just occurred to me now, and will
>>> become really important later when we support WiFi Direct.
>> When we get to implementing per-vif channel settings with switching
>> being done in mac80211, we can just move the calibration data to ath9k's
>> virtual interface data and thus keep the calibration for multiple
>> operating channels.
> 
> Sounds good. This would currently break the ath9k virtual wiphy's
> calibration stuff :P (not like I care), Jouni?
My current patch should work just fine with virtual wiphy's, since I
store the calibration data in the ath_wiphy struct.

- Felix

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/3] ath9k_hw: clean up per-channel calibration data
  2010-07-28 21:30         ` Felix Fietkau
@ 2010-07-28 21:40           ` Luis R. Rodriguez
  2010-07-28 22:03             ` Felix Fietkau
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2010-07-28 21:40 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: Luis Rodriguez, linux-wireless, linville, Jouni Malinen

On Wed, Jul 28, 2010 at 02:30:24PM -0700, Felix Fietkau wrote:
> On 2010-07-28 11:21 PM, Luis R. Rodriguez wrote:
> > On Wed, Jul 28, 2010 at 2:10 PM, Felix Fietkau <nbd@openwrt.org> wrote:
> >> On 2010-07-28 10:52 PM, Luis R. Rodriguez wrote:
> >>> On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
> >>>> The noise floor history buffer is currently not kept per channel, which
> >>>> can lead to problems when changing channels from a clean channel to a
> >>>> noisy one. Also when switching from HT20 to HT40, the noise floor
> >>>> history buffer is full of measurements, but none of them contain data
> >>>> for the extension channel, which it needs quite a bit of time to recover
> >>>> from.
> >>>>
> >>>> This patch puts all the per-channel calibration data into a single data
> >>>> structure, and gives the the driver control over whether that is used
> >>>> per-channel or even not used for some channels.
> >>>>
> >>>> For ath9k_htc, I decided to keep this per-channel in order to avoid
> >>>> creating regressions.
> >>>>
> >>>> For ath9k, the data is kept only for the operating channel, which saves
> >>>> some space. ath9k_hw takes care of wiping old data when the operating
> >>>> channel or its channel flags change.
> >>>>
> >>>> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
> >>>
> >>> But this also means every time we want to get operational on a channel
> >>> we have to learn the current noise all over again. This means for WiFi
> >>> Direct every channel swap we'd have to learn to walk, which happens
> >>> quite often. What do you think? Sorry, I know we discussed this
> >>> approach and I seemed fine but this just occurred to me now, and will
> >>> become really important later when we support WiFi Direct.
> >> When we get to implementing per-vif channel settings with switching
> >> being done in mac80211, we can just move the calibration data to ath9k's
> >> virtual interface data and thus keep the calibration for multiple
> >> operating channels.
> > 
> > Sounds good. This would currently break the ath9k virtual wiphy's
> > calibration stuff :P (not like I care), Jouni?
>
> My current patch should work just fine with virtual wiphy's, since I
> store the calibration data in the ath_wiphy struct.

Ah neat, this approach seems fine in the long run then. My only remaining
questions is how effective our scans are in a noisy environemnt with what
I suppose are some default settings?

  Luis

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/3] ath9k_hw: clean up per-channel calibration data
  2010-07-28 21:40           ` Luis R. Rodriguez
@ 2010-07-28 22:03             ` Felix Fietkau
  0 siblings, 0 replies; 16+ messages in thread
From: Felix Fietkau @ 2010-07-28 22:03 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: Luis Rodriguez, linux-wireless, linville, Jouni Malinen

On 2010-07-28 11:40 PM, Luis R. Rodriguez wrote:
> On Wed, Jul 28, 2010 at 02:30:24PM -0700, Felix Fietkau wrote:
>> My current patch should work just fine with virtual wiphy's, since I
>> store the calibration data in the ath_wiphy struct.
> 
> Ah neat, this approach seems fine in the long run then. My only remaining
> questions is how effective our scans are in a noisy environemnt with what
> I suppose are some default settings?
Scans in noisy environments should be fine. The hardware reset kicks off
an initial NF calibration that lets the baseband use the result
immediately and unfiltered by software. That is much more appropriate
than a calibration history of a channel that is almost never used.

- Felix

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/3] ath9k: prevent calibration during off-channel activity
  2010-07-28 21:08   ` Felix Fietkau
@ 2010-07-28 22:12     ` Luis R. Rodriguez
  2010-07-28 22:28       ` Felix Fietkau
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2010-07-28 22:12 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville

On Wed, Jul 28, 2010 at 2:08 PM, Felix Fietkau <nbd@openwrt.org> wrote:
> On 2010-07-28 10:43 PM, Luis R. Rodriguez wrote:
>> On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
>>> Previously the software scan callback was used to indicate to the hardware,
>>> when it was safe to calibrate. This didn't really work properly, because it
>>> depends on a specific order of software scan callbacks vs. channel changes.
>>> Also, software scans are not the only thing that triggers off-channel
>>> activity, so it's better to use the newly added indication from mac80211 for
>>> this and not use the software scan callback for anything calibration related.
>>>
>>> This fixes at least some of the invalid noise floor readings that I've seen
>>> in AP mode on AR9160
>>
>> Neat!
>>
>>> --- a/drivers/net/wireless/ath/ath9k/main.c
>>> +++ b/drivers/net/wireless/ath/ath9k/main.c
>>> @@ -154,6 +154,27 @@ void ath9k_ps_restore(struct ath_softc *sc)
>>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>>  }
>>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>>  }
>>>
>>> +static void ath_start_ani(struct ath_common *common)
>>> +{
>>> +       struct ath_hw *ah = common->ah;
>>> +       unsigned long timestamp = jiffies_to_msecs(jiffies);
>>> +       struct ath_softc *sc = (struct ath_softc *) common->priv;
>>> +
>>> +       if (!(sc->sc_flags & SC_OP_ANI_RUN))
>>> +               return;
>>> +
>>> +       if (sc->sc_flags & SC_OP_OFFCHANNEL)
>>> +               return;
>>> +
>>> +       common->ani.longcal_timer = timestamp;
>>> +       common->ani.shortcal_timer = timestamp;
>>> +       common->ani.checkani_timer = timestamp;
>>> +
>>> +       mod_timer(&common->ani.timer,
>>> +                 jiffies +
>>> +                       msecs_to_jiffies((u32)ah->config.ani_poll_interval));
>>> +}
>>
>> I would prefer if you do this sort of code shift in a separate patch.
>> In this case its pretty easy to see the code is the same so I think
>> its fine the way it is now but for next time please. Otherwise looks
>> good, thanks!!
> If it had been a bigger function, I'd have made a separate patch, but I
> figured for something as trivial as this it wouldn't matter.

iw event -t while  pinging and then issuing a scan:

1280354915.820607: wlan32 (phy #0): scan started
1280354920.390438: wlan32 (phy #0): scan finished: 2412 2417 2422 2427
2432 2437 2442 2447 2452 2457 2462 5180 5200 5220 5240 5260 5280 5300
5320 5500 5520 5540 5560 5580 5660 5680 5700 5745 5765 5785 5805 5825,
""
1280354923.103628: wlan32 (phy #0): deauth FOO -> BAR reason 4:
Disassociated due to inactivity
1280354923.103736: wlan32 (phy #0): disconnected (local request)
1280354923.111251: phy #0: regulatory domain change: set to world
roaming by the wireless core upon initialization request

So this seems to re-introduce the same issue I was seeing before.

  Luis

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/3] ath9k: prevent calibration during off-channel  activity
  2010-07-28 22:12     ` Luis R. Rodriguez
@ 2010-07-28 22:28       ` Felix Fietkau
  2010-07-28 22:47         ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Felix Fietkau @ 2010-07-28 22:28 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless, linville

On 2010-07-29 12:12 AM, Luis R. Rodriguez wrote:
> On Wed, Jul 28, 2010 at 2:08 PM, Felix Fietkau <nbd@openwrt.org> wrote:
>> On 2010-07-28 10:43 PM, Luis R. Rodriguez wrote:
>>> On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
>>>> Previously the software scan callback was used to indicate to the hardware,
>>>> when it was safe to calibrate. This didn't really work properly, because it
>>>> depends on a specific order of software scan callbacks vs. channel changes.
>>>> Also, software scans are not the only thing that triggers off-channel
>>>> activity, so it's better to use the newly added indication from mac80211 for
>>>> this and not use the software scan callback for anything calibration related.
>>>>
>>>> This fixes at least some of the invalid noise floor readings that I've seen
>>>> in AP mode on AR9160
>>>
>>> Neat!
>>>
>>>> --- a/drivers/net/wireless/ath/ath9k/main.c
>>>> +++ b/drivers/net/wireless/ath/ath9k/main.c
>>>> @@ -154,6 +154,27 @@ void ath9k_ps_restore(struct ath_softc *sc)
>>>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>>>  }
>>>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>>>  }
>>>>
>>>> +static void ath_start_ani(struct ath_common *common)
>>>> +{
>>>> +       struct ath_hw *ah = common->ah;
>>>> +       unsigned long timestamp = jiffies_to_msecs(jiffies);
>>>> +       struct ath_softc *sc = (struct ath_softc *) common->priv;
>>>> +
>>>> +       if (!(sc->sc_flags & SC_OP_ANI_RUN))
>>>> +               return;
>>>> +
>>>> +       if (sc->sc_flags & SC_OP_OFFCHANNEL)
>>>> +               return;
>>>> +
>>>> +       common->ani.longcal_timer = timestamp;
>>>> +       common->ani.shortcal_timer = timestamp;
>>>> +       common->ani.checkani_timer = timestamp;
>>>> +
>>>> +       mod_timer(&common->ani.timer,
>>>> +                 jiffies +
>>>> +                       msecs_to_jiffies((u32)ah->config.ani_poll_interval));
>>>> +}
>>>
>>> I would prefer if you do this sort of code shift in a separate patch.
>>> In this case its pretty easy to see the code is the same so I think
>>> its fine the way it is now but for next time please. Otherwise looks
>>> good, thanks!!
>> If it had been a bigger function, I'd have made a separate patch, but I
>> figured for something as trivial as this it wouldn't matter.
> 
> iw event -t while  pinging and then issuing a scan:
> 
> 1280354915.820607: wlan32 (phy #0): scan started
> 1280354920.390438: wlan32 (phy #0): scan finished: 2412 2417 2422 2427
> 2432 2437 2442 2447 2452 2457 2462 5180 5200 5220 5240 5260 5280 5300
> 5320 5500 5520 5540 5560 5580 5660 5680 5700 5745 5765 5785 5805 5825,
> ""
> 1280354923.103628: wlan32 (phy #0): deauth FOO -> BAR reason 4:
> Disassociated due to inactivity
> 1280354923.103736: wlan32 (phy #0): disconnected (local request)
> 1280354923.111251: phy #0: regulatory domain change: set to world
> roaming by the wireless core upon initialization request
> 
> So this seems to re-introduce the same issue I was seeing before.
Are you sure it's this change? Can you make a log with debug=0x8?
What's the specific symptom here? Does the rx path turn deaf?

- Felix

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/3] ath9k: prevent calibration during off-channel activity
  2010-07-28 22:28       ` Felix Fietkau
@ 2010-07-28 22:47         ` Luis R. Rodriguez
  2010-07-28 22:48           ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2010-07-28 22:47 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville

On Wed, Jul 28, 2010 at 3:28 PM, Felix Fietkau <nbd@openwrt.org> wrote:
> On 2010-07-29 12:12 AM, Luis R. Rodriguez wrote:
>> On Wed, Jul 28, 2010 at 2:08 PM, Felix Fietkau <nbd@openwrt.org> wrote:
>>> On 2010-07-28 10:43 PM, Luis R. Rodriguez wrote:
>>>> On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
>>>>> Previously the software scan callback was used to indicate to the hardware,
>>>>> when it was safe to calibrate. This didn't really work properly, because it
>>>>> depends on a specific order of software scan callbacks vs. channel changes.
>>>>> Also, software scans are not the only thing that triggers off-channel
>>>>> activity, so it's better to use the newly added indication from mac80211 for
>>>>> this and not use the software scan callback for anything calibration related.
>>>>>
>>>>> This fixes at least some of the invalid noise floor readings that I've seen
>>>>> in AP mode on AR9160
>>>>
>>>> Neat!
>>>>
>>>>> --- a/drivers/net/wireless/ath/ath9k/main.c
>>>>> +++ b/drivers/net/wireless/ath/ath9k/main.c
>>>>> @@ -154,6 +154,27 @@ void ath9k_ps_restore(struct ath_softc *sc)
>>>>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>>>>  }
>>>>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>>>>  }
>>>>>
>>>>> +static void ath_start_ani(struct ath_common *common)
>>>>> +{
>>>>> +       struct ath_hw *ah = common->ah;
>>>>> +       unsigned long timestamp = jiffies_to_msecs(jiffies);
>>>>> +       struct ath_softc *sc = (struct ath_softc *) common->priv;
>>>>> +
>>>>> +       if (!(sc->sc_flags & SC_OP_ANI_RUN))
>>>>> +               return;
>>>>> +
>>>>> +       if (sc->sc_flags & SC_OP_OFFCHANNEL)
>>>>> +               return;
>>>>> +
>>>>> +       common->ani.longcal_timer = timestamp;
>>>>> +       common->ani.shortcal_timer = timestamp;
>>>>> +       common->ani.checkani_timer = timestamp;
>>>>> +
>>>>> +       mod_timer(&common->ani.timer,
>>>>> +                 jiffies +
>>>>> +                       msecs_to_jiffies((u32)ah->config.ani_poll_interval));
>>>>> +}
>>>>
>>>> I would prefer if you do this sort of code shift in a separate patch.
>>>> In this case its pretty easy to see the code is the same so I think
>>>> its fine the way it is now but for next time please. Otherwise looks
>>>> good, thanks!!
>>> If it had been a bigger function, I'd have made a separate patch, but I
>>> figured for something as trivial as this it wouldn't matter.
>>
>> iw event -t while  pinging and then issuing a scan:
>>
>> 1280354915.820607: wlan32 (phy #0): scan started
>> 1280354920.390438: wlan32 (phy #0): scan finished: 2412 2417 2422 2427
>> 2432 2437 2442 2447 2452 2457 2462 5180 5200 5220 5240 5260 5280 5300
>> 5320 5500 5520 5540 5560 5580 5660 5680 5700 5745 5765 5785 5805 5825,
>> ""
>> 1280354923.103628: wlan32 (phy #0): deauth FOO -> BAR reason 4:
>> Disassociated due to inactivity
>> 1280354923.103736: wlan32 (phy #0): disconnected (local request)
>> 1280354923.111251: phy #0: regulatory domain change: set to world
>> roaming by the wireless core upon initialization request
>>
>> So this seems to re-introduce the same issue I was seeing before.
>
> Are you sure it's this change?

Just reverted the changes and it works without these issues.

> Can you make a log with debug=0x8?

Sure, one sec let me open that branch up again and recompile again.

> What's the specific symptom here? Does the rx path turn deaf?

Not sure exactly, but what I immediately see is disconnects right after scans.

  Luis

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/3] ath9k: prevent calibration during off-channel activity
  2010-07-28 22:47         ` Luis R. Rodriguez
@ 2010-07-28 22:48           ` Luis R. Rodriguez
  2010-07-29 16:58             ` wireless-next-2.6 rebase -- " John W. Linville
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2010-07-28 22:48 UTC (permalink / raw)
  To: Felix Fietkau; +Cc: linux-wireless, linville

On Wed, Jul 28, 2010 at 3:47 PM, Luis R. Rodriguez
<lrodriguez@atheros.com> wrote:
> On Wed, Jul 28, 2010 at 3:28 PM, Felix Fietkau <nbd@openwrt.org> wrote:
>> On 2010-07-29 12:12 AM, Luis R. Rodriguez wrote:
>>> On Wed, Jul 28, 2010 at 2:08 PM, Felix Fietkau <nbd@openwrt.org> wrote:
>>>> On 2010-07-28 10:43 PM, Luis R. Rodriguez wrote:
>>>>> On Wed, Jul 28, 2010 at 10:45 AM, Felix Fietkau <nbd@openwrt.org> wrote:
>>>>>> Previously the software scan callback was used to indicate to the hardware,
>>>>>> when it was safe to calibrate. This didn't really work properly, because it
>>>>>> depends on a specific order of software scan callbacks vs. channel changes.
>>>>>> Also, software scans are not the only thing that triggers off-channel
>>>>>> activity, so it's better to use the newly added indication from mac80211 for
>>>>>> this and not use the software scan callback for anything calibration related.
>>>>>>
>>>>>> This fixes at least some of the invalid noise floor readings that I've seen
>>>>>> in AP mode on AR9160
>>>>>
>>>>> Neat!
>>>>>
>>>>>> --- a/drivers/net/wireless/ath/ath9k/main.c
>>>>>> +++ b/drivers/net/wireless/ath/ath9k/main.c
>>>>>> @@ -154,6 +154,27 @@ void ath9k_ps_restore(struct ath_softc *sc)
>>>>>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>>>>>  }
>>>>>>        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
>>>>>>  }
>>>>>>
>>>>>> +static void ath_start_ani(struct ath_common *common)
>>>>>> +{
>>>>>> +       struct ath_hw *ah = common->ah;
>>>>>> +       unsigned long timestamp = jiffies_to_msecs(jiffies);
>>>>>> +       struct ath_softc *sc = (struct ath_softc *) common->priv;
>>>>>> +
>>>>>> +       if (!(sc->sc_flags & SC_OP_ANI_RUN))
>>>>>> +               return;
>>>>>> +
>>>>>> +       if (sc->sc_flags & SC_OP_OFFCHANNEL)
>>>>>> +               return;
>>>>>> +
>>>>>> +       common->ani.longcal_timer = timestamp;
>>>>>> +       common->ani.shortcal_timer = timestamp;
>>>>>> +       common->ani.checkani_timer = timestamp;
>>>>>> +
>>>>>> +       mod_timer(&common->ani.timer,
>>>>>> +                 jiffies +
>>>>>> +                       msecs_to_jiffies((u32)ah->config.ani_poll_interval));
>>>>>> +}
>>>>>
>>>>> I would prefer if you do this sort of code shift in a separate patch.
>>>>> In this case its pretty easy to see the code is the same so I think
>>>>> its fine the way it is now but for next time please. Otherwise looks
>>>>> good, thanks!!
>>>> If it had been a bigger function, I'd have made a separate patch, but I
>>>> figured for something as trivial as this it wouldn't matter.
>>>
>>> iw event -t while  pinging and then issuing a scan:
>>>
>>> 1280354915.820607: wlan32 (phy #0): scan started
>>> 1280354920.390438: wlan32 (phy #0): scan finished: 2412 2417 2422 2427
>>> 2432 2437 2442 2447 2452 2457 2462 5180 5200 5220 5240 5260 5280 5300
>>> 5320 5500 5520 5540 5560 5580 5660 5680 5700 5745 5765 5785 5805 5825,
>>> ""
>>> 1280354923.103628: wlan32 (phy #0): deauth FOO -> BAR reason 4:
>>> Disassociated due to inactivity
>>> 1280354923.103736: wlan32 (phy #0): disconnected (local request)
>>> 1280354923.111251: phy #0: regulatory domain change: set to world
>>> roaming by the wireless core upon initialization request
>>>
>>> So this seems to re-introduce the same issue I was seeing before.
>>
>> Are you sure it's this change?
>
> Just reverted the changes and it works without these issues.

Also without these patches I get 0% packet loss, with the patches
applied I get some packet loss.

  Luis

^ permalink raw reply	[flat|nested] 16+ messages in thread

* wireless-next-2.6 rebase -- Re: [PATCH 1/3] ath9k: prevent calibration during off-channel activity
  2010-07-28 22:48           ` Luis R. Rodriguez
@ 2010-07-29 16:58             ` John W. Linville
  0 siblings, 0 replies; 16+ messages in thread
From: John W. Linville @ 2010-07-29 16:58 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: Felix Fietkau, linux-wireless

On Wed, Jul 28, 2010 at 03:48:18PM -0700, Luis R. Rodriguez wrote:

> Also without these patches I get 0% packet loss, with the patches
> applied I get some packet loss.

Based on this report, I'm dropping this series from wireless-next-2.6
(requiring a rebase) -- FYI...

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2010-07-29 17:00 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-28 17:45 [PATCH 1/3] ath9k: prevent calibration during off-channel activity Felix Fietkau
2010-07-28 17:45 ` [PATCH 2/3] ath9k_hw: clean up per-channel calibration data Felix Fietkau
2010-07-28 17:45   ` [PATCH 3/3] ath9k_hw: fix a noise floor calibration related race condition Felix Fietkau
2010-07-28 20:52   ` [PATCH 2/3] ath9k_hw: clean up per-channel calibration data Luis R. Rodriguez
2010-07-28 21:10     ` Felix Fietkau
2010-07-28 21:21       ` Luis R. Rodriguez
2010-07-28 21:30         ` Felix Fietkau
2010-07-28 21:40           ` Luis R. Rodriguez
2010-07-28 22:03             ` Felix Fietkau
2010-07-28 20:43 ` [PATCH 1/3] ath9k: prevent calibration during off-channel activity Luis R. Rodriguez
2010-07-28 21:08   ` Felix Fietkau
2010-07-28 22:12     ` Luis R. Rodriguez
2010-07-28 22:28       ` Felix Fietkau
2010-07-28 22:47         ` Luis R. Rodriguez
2010-07-28 22:48           ` Luis R. Rodriguez
2010-07-29 16:58             ` wireless-next-2.6 rebase -- " John W. Linville

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).