Search Linux Wireless

Re: [PATCH] ath5k: fix print on warning on ath5k_hw_to_driver_rix()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Aug 25, 2009 at 12:22:55PM -0700, Bob Copeland wrote:
> On Tue, Aug 25, 2009 at 2:58 PM, Luis R.
> Rodriguez<lrodriguez@xxxxxxxxxxx> wrote:
> > OK how about the band info, think that's useful?
> 
> Yeah, band is useful.  We don't have to pretty print it though
> (unless you really feel like it), %d would work just as well.
> 
> Also WARN_ON_ONCE might be a good idea.

Alright, first let me see if I can reproduce after cleaning
curband crap a little.

> >> which could indicate some
> >> race condition with flushing the rx queue on channel changes.
> >
> > I'll see if I can reproduce somehow.
> >
> >> I haven't yet seen a hw rate we didn't know about.
> >
> > So you've seen this lately as well?
> 
> I saw it some time ago, but then changed the order of how the
> curchan/curband variables were set when we change channels and
> haven't seen since.  But kerneloops says a lot of other people
> are still hitting it as well :(

OK that's good to know too.

> Hmm, ath5k_rx_stop probably wants an equivalent to txq_drainq in
> there somewhere.

True.

First thing I saw upon a quick review was we were relying on our own
curband for RX instead of the cfg80211 hw->conf band. Now granted
that *may* be updated properly, and it seems that may be the case,
but since do not tend to trust drivers here's a removal of all that
crap first. I'll test this first to see if I run into the same warning.
If this doesn't cure it then we are indeed processing old frames on RX
and need to flush 'em out prior to a channel change first.

Good thing is after a few hours I can reproduce at least.

  Luis

From: Luis R. Rodriguez <lrodriguez@xxxxxxxxxxx>
Subject: [PATCH] ath5k: remove curband, curchan, curmode

It still possible for ath5k tasklet to trigger and the
curband to be off. There seems to be some race against it
somewhere. To help aid with this review we simplify the
notion of current band and current channel assumptions
ath5k and only rely on cfg80211's as it already does the
book keeping for us.

Signed-off-by: Luis R. Rodriguez <lrodriguez@xxxxxxxxxxx>
---
 drivers/net/wireless/ath/ath5k/base.c |   87 +++++++++++++++------------------
 drivers/net/wireless/ath/ath5k/base.h |    6 --
 2 files changed, 39 insertions(+), 54 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 5056410..feffc92 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -220,7 +220,8 @@ static struct pci_driver ath5k_pci_driver = {
 static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
 		struct ath5k_txq *txq);
-static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
+static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
+		       bool chan_change);
 static int ath5k_reset_wake(struct ath5k_softc *sc);
 static int ath5k_start(struct ieee80211_hw *hw);
 static void ath5k_stop(struct ieee80211_hw *hw);
@@ -293,8 +294,6 @@ static unsigned int ath5k_copy_channels(struct ath5k_hw *ah,
 static int 	ath5k_setup_bands(struct ieee80211_hw *hw);
 static int 	ath5k_chan_set(struct ath5k_softc *sc,
 				struct ieee80211_channel *chan);
-static void	ath5k_setcurmode(struct ath5k_softc *sc,
-				unsigned int mode);
 static void	ath5k_mode_setup(struct ath5k_softc *sc);
 
 /* Descriptor setup */
@@ -759,12 +758,6 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 		goto err;
 	}
 
-	/* NB: setup here so ath5k_rate_update is happy */
-	if (test_bit(AR5K_MODE_11A, ah->ah_modes))
-		ath5k_setcurmode(sc, AR5K_MODE_11A);
-	else
-		ath5k_setcurmode(sc, AR5K_MODE_11B);
-
 	/*
 	 * Allocate tx+rx descriptors and populate the lists.
 	 */
@@ -1084,7 +1077,7 @@ static int
 ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
 {
 	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "(%u MHz) -> (%u MHz)\n",
-		sc->curchan->center_freq, chan->center_freq);
+		sc->hw->conf.channel->center_freq, chan->center_freq);
 
 	/*
 	 * To switch channels clear any pending DMA operations;
@@ -1092,19 +1085,12 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
 	 * hardware at the new frequency, and then re-enable
 	 * the relevant bits of the h/w.
 	 */
-	return ath5k_reset(sc, chan);
-}
 
-static void
-ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
-{
-	sc->curmode = mode;
+	ath5k_hw_set_imr(sc->ah, 0);
+	ath5k_txq_cleanup(sc);
+	ath5k_rx_stop(sc);
 
-	if (mode == AR5K_MODE_11A) {
-		sc->curband = &sc->sbands[IEEE80211_BAND_5GHZ];
-	} else {
-		sc->curband = &sc->sbands[IEEE80211_BAND_2GHZ];
-	}
+	return ath5k_reset(sc, chan, true);
 }
 
 static void
@@ -1136,11 +1122,15 @@ ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix)
 
 	/* return base rate on errors */
 	if (WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES,
-			"hw_rix out of bounds: %x\n", hw_rix))
+		 "hardware rate index out of bounds: %x"
+		 "on freq: %d\n", hw_rix,
+		 sc->hw->conf.channel->center_freq))
 		return 0;
 
-	rix = sc->rate_idx[sc->curband->band][hw_rix];
-	if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix))
+	rix = sc->rate_idx[sc->hw->conf.channel->band][hw_rix];
+	if (WARN(rix < 0, "invalid driver rate index mapped for "
+		 "hw_rix: %x on freq: %d\n", hw_rix,
+		 sc->hw->conf.channel->center_freq))
 		rix = 0;
 
 	return rix;
@@ -1742,6 +1732,8 @@ static void
 ath5k_tasklet_rx(unsigned long data)
 {
 	struct ieee80211_rx_status rxs = {};
+	struct ieee80211_rate *bitrate;
+	struct ieee80211_supported_band *sband;
 	struct ath5k_rx_status rs = {};
 	struct sk_buff *skb, *next_skb;
 	dma_addr_t next_skb_addr;
@@ -1751,6 +1743,7 @@ ath5k_tasklet_rx(unsigned long data)
 	int ret;
 	int hdrlen;
 	int padsize;
+	int cur_band;
 
 	spin_lock(&sc->rxbuflock);
 	if (list_empty(&sc->rxbuf)) {
@@ -1864,8 +1857,8 @@ accept:
 		rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
 		rxs.flag |= RX_FLAG_TSFT;
 
-		rxs.freq = sc->curchan->center_freq;
-		rxs.band = sc->curband->band;
+		rxs.freq = sc->hw->conf.channel->center_freq;
+		rxs.band = sc->hw->conf.channel->band;
 
 		rxs.noise = sc->ah->ah_noise_floor;
 		rxs.signal = rxs.noise + rs.rs_rssi;
@@ -1885,8 +1878,11 @@ accept:
 		rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
 		rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
 
-		if (rxs.rate_idx >= 0 && rs.rs_rate ==
-		    sc->curband->bitrates[rxs.rate_idx].hw_value_short)
+		cur_band = sc->hw->conf.channel->band;
+		sband = sc->hw->wiphy->bands[cur_band];
+		bitrate = &sband->bitrates[rxs.rate_idx];
+
+		if (rxs.rate_idx >= 0 && rs.rs_rate == bitrate->hw_value_short)
 			rxs.flag |= RX_FLAG_SHORTPRE;
 
 		ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
@@ -2328,6 +2324,11 @@ static void ath5k_tasklet_beacon(unsigned long data)
 	}
 }
 
+static int
+ath5k_reset_init(struct ath5k_softc *sc)
+{
+	return ath5k_reset(sc, sc->hw->conf.channel, false);
+}
 
 /********************\
 * Interrupt handling *
@@ -2356,12 +2357,10 @@ ath5k_init(struct ath5k_softc *sc)
 	 * be followed by initialization of the appropriate bits
 	 * and then setup of the interrupt mask.
 	 */
-	sc->curchan = sc->hw->conf.channel;
-	sc->curband = &sc->sbands[sc->curchan->band];
 	sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
 		AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
 		AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI;
-	ret = ath5k_reset(sc, NULL);
+	ret = ath5k_reset_init(sc);
 	if (ret)
 		goto done;
 
@@ -2581,8 +2580,8 @@ ath5k_tasklet_calibrate(unsigned long data)
 	ieee80211_stop_queues(sc->hw);
 
 	ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
-		ieee80211_frequency_to_channel(sc->curchan->center_freq),
-		sc->curchan->hw_value);
+		ieee80211_frequency_to_channel(sc->hw->conf.channel->center_freq),
+		sc->hw->conf.channel->hw_value);
 
 	if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
 		/*
@@ -2592,10 +2591,10 @@ ath5k_tasklet_calibrate(unsigned long data)
 		ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
 		ath5k_reset_wake(sc);
 	}
-	if (ath5k_hw_phy_calibrate(ah, sc->curchan))
+	if (ath5k_hw_phy_calibrate(ah, sc->hw->conf.channel))
 		ATH5K_ERR(sc, "calibration of channel %u failed\n",
 			ieee80211_frequency_to_channel(
-				sc->curchan->center_freq));
+				sc->hw->conf.channel->center_freq));
 
 	ah->ah_swi_mask = 0;
 
@@ -2680,26 +2679,18 @@ drop_packet:
 }
 
 /*
- * Reset the hardware.  If chan is not NULL, then also pause rx/tx
- * and change to the given channel.
+ * Reset the hardware.
  */
 static int
-ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
+ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
+	    bool chan_change)
 {
 	struct ath5k_hw *ah = sc->ah;
 	int ret;
 
 	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
 
-	if (chan) {
-		ath5k_hw_set_imr(ah, 0);
-		ath5k_txq_cleanup(sc);
-		ath5k_rx_stop(sc);
-
-		sc->curchan = chan;
-		sc->curband = &sc->sbands[chan->band];
-	}
-	ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
+	ret = ath5k_hw_reset(ah, sc->opmode, chan, chan_change);
 	if (ret) {
 		ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
 		goto err;
@@ -2735,7 +2726,7 @@ ath5k_reset_wake(struct ath5k_softc *sc)
 {
 	int ret;
 
-	ret = ath5k_reset(sc, sc->curchan);
+	ret = ath5k_reset_init(sc);
 	if (!ret)
 		ieee80211_wake_queues(sc->hw);
 
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index a28c42f..1b88814 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -128,8 +128,6 @@ struct ath5k_softc {
 	enum nl80211_iftype	opmode;
 	struct ath5k_hw		*ah;		/* Atheros HW */
 
-	struct ieee80211_supported_band		*curband;
-
 #ifdef CONFIG_ATH5K_DEBUG
 	struct ath5k_dbg_info	debug;		/* debug info */
 #endif /* CONFIG_ATH5K_DEBUG */
@@ -147,11 +145,7 @@ struct ath5k_softc {
 #define ATH_STAT_STARTED	4		/* opened & irqs enabled */
 
 	unsigned int		filter_flags;	/* HW flags, AR5K_RX_FILTER_* */
-	unsigned int		curmode;	/* current phy mode */
-	struct ieee80211_channel *curchan;	/* current h/w channel */
-
 	struct ieee80211_vif *vif;
-
 	enum ath5k_int		imask;		/* interrupt mask copy */
 
 	DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux