All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] ath9k: more PCU locking enhancements
@ 2010-10-26 22:27 Luis R. Rodriguez
  2010-10-26 22:27 ` [PATCH 1/3] ath9k: simplify hw reset locking Luis R. Rodriguez
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Luis R. Rodriguez @ 2010-10-26 22:27 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, greearb, kyungwan.nam, amod.bodas, Luis R. Rodriguez

This addresses some more DMA / PCU locking. It simplifies the locking
and includes now TX control over the PCU. These patches help with the
overall realiability of RX and TX and conflicts between them and
resets. When you start/stop RX or TX or do resets it will all be
done atomically now. These all now go tested by Ben Greear over at
candelatech.com using a proprietary userspace applicatin which
creates 130 STAs associating to one AP that only accepts 30 STAs at
a time. Ben had never seen this test run more than about 10 minutes
without poison warnings and/or lockups.

This last series (first series addressed RX poison issues) addresses
the last bit of complaints on DMA that he got when testing with these
large amount of STAs on one 802.11 device.
    
For more details about this issue refer to this thread:

http://marc.info/?l=linux-wireless&m=128629803703756&w=2

Many thanks to Ben Greear @ candelatech.com for the testing, reports
and patience with this.

Luis R. Rodriguez (3):
  ath9k: simplify hw reset locking
  ath9k: move the PCU lock to the sc structure
  ath9k: content DMA start / stop through the PCU lock

 drivers/net/wireless/ath/ath9k/ath9k.h |    3 +-
 drivers/net/wireless/ath/ath9k/init.c  |    1 -
 drivers/net/wireless/ath/ath9k/main.c  |   70 ++++++++++++++------------------
 drivers/net/wireless/ath/ath9k/recv.c  |    2 +-
 drivers/net/wireless/ath/ath9k/xmit.c  |    4 +-
 5 files changed, 34 insertions(+), 46 deletions(-)

-- 
1.7.3.2.90.gd4c43


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

* [PATCH 1/3] ath9k: simplify hw reset locking
  2010-10-26 22:27 [PATCH 0/3] ath9k: more PCU locking enhancements Luis R. Rodriguez
@ 2010-10-26 22:27 ` Luis R. Rodriguez
  2010-10-26 22:27 ` [PATCH 2/3] ath9k: move the PCU lock to the sc structure Luis R. Rodriguez
  2010-10-26 22:27 ` [PATCH 3/3] ath9k: content DMA start / stop through the PCU lock Luis R. Rodriguez
  2 siblings, 0 replies; 4+ messages in thread
From: Luis R. Rodriguez @ 2010-10-26 22:27 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, greearb, kyungwan.nam, amod.bodas,
	Luis R. Rodriguez, stable

The new PCU lock is better placed so we can just contend
against that when trying to reset hardware.

This is part of a series of patches which fix stopping
TX DMA completley when requested on the driver.
For more details about this issue refer to this thread:

http://marc.info/?l=linux-wireless&m=128629803703756&w=2

Tested-by:  Ben Greear <greearb@candelatech.com>
Cc: Kyungwan Nam <kyungwan.nam@atheros.com>
Cc: stable@kernel.org
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    1 -
 drivers/net/wireless/ath/ath9k/init.c  |    1 -
 drivers/net/wireless/ath/ath9k/main.c  |   22 ++++++----------------
 drivers/net/wireless/ath/ath9k/xmit.c  |    4 ++--
 4 files changed, 8 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9b8e7e3..1b64a30 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -600,7 +600,6 @@ struct ath_softc {
 	struct ath_hw *sc_ah;
 	void __iomem *mem;
 	int irq;
-	spinlock_t sc_resetlock;
 	spinlock_t sc_serial_rw;
 	spinlock_t sc_pm_lock;
 	struct mutex mutex;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 95b41db..081179d 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -580,7 +580,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
 	spin_lock_init(&common->cc_lock);
 
 	spin_lock_init(&sc->wiphy_lock);
-	spin_lock_init(&sc->sc_resetlock);
 	spin_lock_init(&sc->sc_serial_rw);
 	spin_lock_init(&sc->sc_pm_lock);
 	mutex_init(&sc->mutex);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index b52f1cf..5e036af 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -262,19 +262,15 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 		  channel->center_freq, conf_is_ht40(conf),
 		  fastcc);
 
-	spin_lock_bh(&sc->sc_resetlock);
-
 	r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to reset channel (%u MHz), "
 			  "reset status %d\n",
 			  channel->center_freq, r);
-		spin_unlock_bh(&sc->sc_resetlock);
 		spin_unlock_bh(&sc->rx.pcu_lock);
 		goto ps_restore;
 	}
-	spin_unlock_bh(&sc->sc_resetlock);
 
 	if (ath_startrecv(sc) != 0) {
 		ath_print(common, ATH_DBG_FATAL,
@@ -884,7 +880,6 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 		ah->curchan = ath_get_curchannel(sc, sc->hw);
 
 	spin_lock_bh(&sc->rx.pcu_lock);
-	spin_lock_bh(&sc->sc_resetlock);
 	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
@@ -892,7 +887,6 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 			  "reset status %d\n",
 			  channel->center_freq, r);
 	}
-	spin_unlock_bh(&sc->sc_resetlock);
 
 	ath_update_txpow(sc);
 	if (ath_startrecv(sc) != 0) {
@@ -949,7 +943,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 	if (!ah->curchan)
 		ah->curchan = ath_get_curchannel(sc, hw);
 
-	spin_lock_bh(&sc->sc_resetlock);
 	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (r) {
 		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
@@ -957,7 +950,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 			  "reset status %d\n",
 			  channel->center_freq, r);
 	}
-	spin_unlock_bh(&sc->sc_resetlock);
 
 	ath9k_hw_phy_disable(ah);
 
@@ -988,12 +980,10 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 	ath_stoprecv(sc);
 	ath_flushrecv(sc);
 
-	spin_lock_bh(&sc->sc_resetlock);
 	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);
-	spin_unlock_bh(&sc->sc_resetlock);
 
 	if (ath_startrecv(sc) != 0)
 		ath_print(common, ATH_DBG_FATAL,
@@ -1164,18 +1154,15 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	 * and then setup of the interrupt mask.
 	 */
 	spin_lock_bh(&sc->rx.pcu_lock);
-	spin_lock_bh(&sc->sc_resetlock);
 	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 "
 			  "(freq %u MHz)\n", r,
 			  curchan->center_freq);
-		spin_unlock_bh(&sc->sc_resetlock);
 		spin_unlock_bh(&sc->rx.pcu_lock);
 		goto mutex_unlock;
 	}
-	spin_unlock_bh(&sc->sc_resetlock);
 
 	/*
 	 * This is needed only to setup initial state
@@ -1396,14 +1383,17 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 	 * before setting the invalid flag. */
 	ath9k_hw_set_interrupts(ah, 0);
 
-	spin_lock_bh(&sc->rx.pcu_lock);
 	if (!(sc->sc_flags & SC_OP_INVALID)) {
 		ath_drain_all_txq(sc, false);
+		spin_lock_bh(&sc->rx.pcu_lock);
 		ath_stoprecv(sc);
 		ath9k_hw_phy_disable(ah);
-	} else
+		spin_unlock_bh(&sc->rx.pcu_lock);
+	} else {
+		spin_lock_bh(&sc->rx.pcu_lock);
 		sc->rx.rxlink = NULL;
-	spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->rx.pcu_lock);
+	}
 
 	/* disable HAL and put h/w to sleep */
 	ath9k_hw_disable(ah);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 30ef2df..6c0de85 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1148,13 +1148,13 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
 		ath_print(common, ATH_DBG_FATAL,
 			  "Failed to stop TX DMA. Resetting hardware!\n");
 
-		spin_lock_bh(&sc->sc_resetlock);
+		spin_lock_bh(&sc->rx.pcu_lock);
 		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);
-		spin_unlock_bh(&sc->sc_resetlock);
+		spin_unlock_bh(&sc->rx.pcu_lock);
 	}
 
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-- 
1.7.3.2.90.gd4c43


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

* [PATCH 2/3] ath9k: move the PCU lock to the sc structure
  2010-10-26 22:27 [PATCH 0/3] ath9k: more PCU locking enhancements Luis R. Rodriguez
  2010-10-26 22:27 ` [PATCH 1/3] ath9k: simplify hw reset locking Luis R. Rodriguez
@ 2010-10-26 22:27 ` Luis R. Rodriguez
  2010-10-26 22:27 ` [PATCH 3/3] ath9k: content DMA start / stop through the PCU lock Luis R. Rodriguez
  2 siblings, 0 replies; 4+ messages in thread
From: Luis R. Rodriguez @ 2010-10-26 22:27 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, greearb, kyungwan.nam, amod.bodas,
	Luis R. Rodriguez, stable

The PCU lock should be used to contend TX DMA as well,
this will be done next.

This is part of a series of patches which fix stopping
TX DMA completley when requested on the driver.
For more details about this issue refer to this thread:

http://marc.info/?l=linux-wireless&m=128629803703756&w=2

Tested-by:  Ben Greear <greearb@candelatech.com>
Cc: Kyungwan Nam <kyungwan.nam@atheros.com>
Cc: stable@kernel.org
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |    2 +-
 drivers/net/wireless/ath/ath9k/main.c  |   42 ++++++++++++++++----------------
 drivers/net/wireless/ath/ath9k/recv.c  |    2 +-
 drivers/net/wireless/ath/ath9k/xmit.c  |    4 +-
 4 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1b64a30..622f42e 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -310,7 +310,6 @@ struct ath_rx {
 	u8 rxotherant;
 	u32 *rxlink;
 	unsigned int rxfilter;
-	spinlock_t pcu_lock;
 	spinlock_t rxbuflock;
 	struct list_head rxbuf;
 	struct ath_descdma rxdma;
@@ -602,6 +601,7 @@ struct ath_softc {
 	int irq;
 	spinlock_t sc_serial_rw;
 	spinlock_t sc_pm_lock;
+	spinlock_t sc_pcu_lock;
 	struct mutex mutex;
 	struct work_struct paprd_work;
 	struct work_struct hw_check_work;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 5e036af..4196336 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -242,7 +242,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	ath9k_hw_set_interrupts(ah, 0);
 	ath_drain_all_txq(sc, false);
 
-	spin_lock_bh(&sc->rx.pcu_lock);
+	spin_lock_bh(&sc->sc_pcu_lock);
 
 	stopped = ath_stoprecv(sc);
 
@@ -268,7 +268,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 			  "Unable to reset channel (%u MHz), "
 			  "reset status %d\n",
 			  channel->center_freq, r);
-		spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->sc_pcu_lock);
 		goto ps_restore;
 	}
 
@@ -276,11 +276,11 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to restart recv logic\n");
 		r = -EIO;
-		spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->sc_pcu_lock);
 		goto ps_restore;
 	}
 
-	spin_unlock_bh(&sc->rx.pcu_lock);
+	spin_unlock_bh(&sc->sc_pcu_lock);
 
 	ath_update_txpow(sc);
 	ath9k_hw_set_interrupts(ah, ah->imask);
@@ -616,7 +616,7 @@ void ath9k_tasklet(unsigned long data)
 		rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
 
 	if (status & rxmask) {
-		spin_lock_bh(&sc->rx.pcu_lock);
+		spin_lock_bh(&sc->sc_pcu_lock);
 
 		/* Check for high priority Rx first */
 		if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
@@ -624,7 +624,7 @@ void ath9k_tasklet(unsigned long data)
 			ath_rx_tasklet(sc, 0, true);
 
 		ath_rx_tasklet(sc, 0, false);
-		spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->sc_pcu_lock);
 	}
 
 	if (status & ATH9K_INT_TX) {
@@ -879,7 +879,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 	if (!ah->curchan)
 		ah->curchan = ath_get_curchannel(sc, sc->hw);
 
-	spin_lock_bh(&sc->rx.pcu_lock);
+	spin_lock_bh(&sc->sc_pcu_lock);
 	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
@@ -892,10 +892,10 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 	if (ath_startrecv(sc) != 0) {
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to restart recv logic\n");
-		spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->sc_pcu_lock);
 		return;
 	}
-	spin_unlock_bh(&sc->rx.pcu_lock);
+	spin_unlock_bh(&sc->sc_pcu_lock);
 
 	if (sc->sc_flags & SC_OP_BEACONS)
 		ath_beacon_config(sc, NULL);	/* restart beacons */
@@ -935,7 +935,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
 	ath_drain_all_txq(sc, false);	/* clear pending tx frames */
 
-	spin_lock_bh(&sc->rx.pcu_lock);
+	spin_lock_bh(&sc->sc_pcu_lock);
 
 	ath_stoprecv(sc);		/* turn off frame recv */
 	ath_flushrecv(sc);		/* flush recv queue */
@@ -953,7 +953,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
 	ath9k_hw_phy_disable(ah);
 
-	spin_unlock_bh(&sc->rx.pcu_lock);
+	spin_unlock_bh(&sc->sc_pcu_lock);
 
 	ath9k_hw_configpcipowersave(ah, 1, 1);
 	ath9k_ps_restore(sc);
@@ -975,7 +975,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 	ath9k_hw_set_interrupts(ah, 0);
 	ath_drain_all_txq(sc, retry_tx);
 
-	spin_lock_bh(&sc->rx.pcu_lock);
+	spin_lock_bh(&sc->sc_pcu_lock);
 
 	ath_stoprecv(sc);
 	ath_flushrecv(sc);
@@ -989,7 +989,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to start recv logic\n");
 
-	spin_unlock_bh(&sc->rx.pcu_lock);
+	spin_unlock_bh(&sc->sc_pcu_lock);
 
 	/*
 	 * We may be doing a reset in response to a request
@@ -1153,14 +1153,14 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	 * be followed by initialization of the appropriate bits
 	 * and then setup of the interrupt mask.
 	 */
-	spin_lock_bh(&sc->rx.pcu_lock);
+	spin_lock_bh(&sc->sc_pcu_lock);
 	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 "
 			  "(freq %u MHz)\n", r,
 			  curchan->center_freq);
-		spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->sc_pcu_lock);
 		goto mutex_unlock;
 	}
 
@@ -1181,10 +1181,10 @@ static int ath9k_start(struct ieee80211_hw *hw)
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to start recv logic\n");
 		r = -EIO;
-		spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->sc_pcu_lock);
 		goto mutex_unlock;
 	}
-	spin_unlock_bh(&sc->rx.pcu_lock);
+	spin_unlock_bh(&sc->sc_pcu_lock);
 
 	/* Setup our intr mask. */
 	ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
@@ -1385,14 +1385,14 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
 	if (!(sc->sc_flags & SC_OP_INVALID)) {
 		ath_drain_all_txq(sc, false);
-		spin_lock_bh(&sc->rx.pcu_lock);
+		spin_lock_bh(&sc->sc_pcu_lock);
 		ath_stoprecv(sc);
 		ath9k_hw_phy_disable(ah);
-		spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->sc_pcu_lock);
 	} else {
-		spin_lock_bh(&sc->rx.pcu_lock);
+		spin_lock_bh(&sc->sc_pcu_lock);
 		sc->rx.rxlink = NULL;
-		spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->sc_pcu_lock);
 	}
 
 	/* disable HAL and put h/w to sleep */
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 26ac6d8..0821664 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -317,7 +317,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
 	struct ath_buf *bf;
 	int error = 0;
 
-	spin_lock_init(&sc->rx.pcu_lock);
+	spin_lock_init(&sc->sc_pcu_lock);
 	sc->sc_flags &= ~SC_OP_RXFLUSH;
 	spin_lock_init(&sc->rx.rxbuflock);
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 6c0de85..81f63e52 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1148,13 +1148,13 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
 		ath_print(common, ATH_DBG_FATAL,
 			  "Failed to stop TX DMA. Resetting hardware!\n");
 
-		spin_lock_bh(&sc->rx.pcu_lock);
+		spin_lock_bh(&sc->sc_pcu_lock);
 		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);
-		spin_unlock_bh(&sc->rx.pcu_lock);
+		spin_unlock_bh(&sc->sc_pcu_lock);
 	}
 
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-- 
1.7.3.2.90.gd4c43


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

* [PATCH 3/3] ath9k: content DMA start / stop through the PCU lock
  2010-10-26 22:27 [PATCH 0/3] ath9k: more PCU locking enhancements Luis R. Rodriguez
  2010-10-26 22:27 ` [PATCH 1/3] ath9k: simplify hw reset locking Luis R. Rodriguez
  2010-10-26 22:27 ` [PATCH 2/3] ath9k: move the PCU lock to the sc structure Luis R. Rodriguez
@ 2010-10-26 22:27 ` Luis R. Rodriguez
  2 siblings, 0 replies; 4+ messages in thread
From: Luis R. Rodriguez @ 2010-10-26 22:27 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, greearb, kyungwan.nam, amod.bodas,
	Luis R. Rodriguez, stable

This helps align resets / RX enable & disable / TX stop / start.
Locking around the PCU is important to ensure the hardware doesn't
get stale data when working with DMA'able data.

This is part of a series of patches which fix stopping
TX DMA completley when requested on the driver.
For more details about this issue refer to this thread:

http://marc.info/?l=linux-wireless&m=128629803703756&w=2

Tested-by:  Ben Greear <greearb@candelatech.com>
Cc: Kyungwan Nam <kyungwan.nam@atheros.com>
Cc: stable@kernel.org
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/main.c |   52 ++++++++++++++++----------------
 drivers/net/wireless/ath/ath9k/xmit.c |    4 +-
 2 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 4196336..f494bb2 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -230,6 +230,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 
 	ath9k_ps_wakeup(sc);
 
+	spin_lock_bh(&sc->sc_pcu_lock);
+
 	/*
 	 * This is only performed if the channel settings have
 	 * actually changed.
@@ -242,8 +244,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	ath9k_hw_set_interrupts(ah, 0);
 	ath_drain_all_txq(sc, false);
 
-	spin_lock_bh(&sc->sc_pcu_lock);
-
 	stopped = ath_stoprecv(sc);
 
 	/* XXX: do not flush receive queue here. We don't want
@@ -268,7 +268,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 			  "Unable to reset channel (%u MHz), "
 			  "reset status %d\n",
 			  channel->center_freq, r);
-		spin_unlock_bh(&sc->sc_pcu_lock);
 		goto ps_restore;
 	}
 
@@ -276,12 +275,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to restart recv logic\n");
 		r = -EIO;
-		spin_unlock_bh(&sc->sc_pcu_lock);
 		goto ps_restore;
 	}
 
-	spin_unlock_bh(&sc->sc_pcu_lock);
-
 	ath_update_txpow(sc);
 	ath9k_hw_set_interrupts(ah, ah->imask);
 
@@ -292,6 +288,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 	}
 
  ps_restore:
+	spin_unlock_bh(&sc->sc_pcu_lock);
+
 	ath9k_ps_restore(sc);
 	return r;
 }
@@ -606,6 +604,8 @@ void ath9k_tasklet(unsigned long data)
 		return;
 	}
 
+	spin_lock_bh(&sc->sc_pcu_lock);
+
 	if (!ath9k_hw_check_alive(ah))
 		ieee80211_queue_work(sc->hw, &sc->hw_check_work);
 
@@ -616,15 +616,12 @@ void ath9k_tasklet(unsigned long data)
 		rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
 
 	if (status & rxmask) {
-		spin_lock_bh(&sc->sc_pcu_lock);
-
 		/* Check for high priority Rx first */
 		if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
 		    (status & ATH9K_INT_RXHP))
 			ath_rx_tasklet(sc, 0, true);
 
 		ath_rx_tasklet(sc, 0, false);
-		spin_unlock_bh(&sc->sc_pcu_lock);
 	}
 
 	if (status & ATH9K_INT_TX) {
@@ -650,6 +647,8 @@ void ath9k_tasklet(unsigned long data)
 
 	/* re-enable hardware interrupt */
 	ath9k_hw_set_interrupts(ah, ah->imask);
+
+	spin_unlock_bh(&sc->sc_pcu_lock);
 	ath9k_ps_restore(sc);
 }
 
@@ -874,12 +873,13 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 	int r;
 
 	ath9k_ps_wakeup(sc);
+	spin_lock_bh(&sc->sc_pcu_lock);
+
 	ath9k_hw_configpcipowersave(ah, 0, 0);
 
 	if (!ah->curchan)
 		ah->curchan = ath_get_curchannel(sc, sc->hw);
 
-	spin_lock_bh(&sc->sc_pcu_lock);
 	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 	if (r) {
 		ath_print(common, ATH_DBG_FATAL,
@@ -895,8 +895,6 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 		spin_unlock_bh(&sc->sc_pcu_lock);
 		return;
 	}
-	spin_unlock_bh(&sc->sc_pcu_lock);
-
 	if (sc->sc_flags & SC_OP_BEACONS)
 		ath_beacon_config(sc, NULL);	/* restart beacons */
 
@@ -909,6 +907,8 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 	ath9k_hw_set_gpio(ah, ah->led_pin, 0);
 
 	ieee80211_wake_queues(hw);
+	spin_unlock_bh(&sc->sc_pcu_lock);
+
 	ath9k_ps_restore(sc);
 }
 
@@ -919,6 +919,8 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 	int r;
 
 	ath9k_ps_wakeup(sc);
+	spin_lock_bh(&sc->sc_pcu_lock);
+
 	ieee80211_stop_queues(hw);
 
 	/*
@@ -935,8 +937,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
 	ath_drain_all_txq(sc, false);	/* clear pending tx frames */
 
-	spin_lock_bh(&sc->sc_pcu_lock);
-
 	ath_stoprecv(sc);		/* turn off frame recv */
 	ath_flushrecv(sc);		/* flush recv queue */
 
@@ -953,10 +953,11 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
 	ath9k_hw_phy_disable(ah);
 
-	spin_unlock_bh(&sc->sc_pcu_lock);
-
 	ath9k_hw_configpcipowersave(ah, 1, 1);
+
+	spin_unlock_bh(&sc->sc_pcu_lock);
 	ath9k_ps_restore(sc);
+
 	ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
 }
 
@@ -970,13 +971,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 	/* Stop ANI */
 	del_timer_sync(&common->ani.timer);
 
+	spin_lock_bh(&sc->sc_pcu_lock);
+
 	ieee80211_stop_queues(hw);
 
 	ath9k_hw_set_interrupts(ah, 0);
 	ath_drain_all_txq(sc, retry_tx);
 
-	spin_lock_bh(&sc->sc_pcu_lock);
-
 	ath_stoprecv(sc);
 	ath_flushrecv(sc);
 
@@ -989,8 +990,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 		ath_print(common, ATH_DBG_FATAL,
 			  "Unable to start recv logic\n");
 
-	spin_unlock_bh(&sc->sc_pcu_lock);
-
 	/*
 	 * We may be doing a reset in response to a request
 	 * that changes the channel so update any state that
@@ -1015,6 +1014,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 	}
 
 	ieee80211_wake_queues(hw);
+	spin_unlock_bh(&sc->sc_pcu_lock);
 
 	/* Start ANI */
 	ath_start_ani(common);
@@ -1379,25 +1379,25 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 			ath9k_btcoex_timer_pause(sc);
 	}
 
+	spin_lock_bh(&sc->sc_pcu_lock);
+
 	/* make sure h/w will not generate any interrupt
 	 * before setting the invalid flag. */
 	ath9k_hw_set_interrupts(ah, 0);
 
 	if (!(sc->sc_flags & SC_OP_INVALID)) {
 		ath_drain_all_txq(sc, false);
-		spin_lock_bh(&sc->sc_pcu_lock);
 		ath_stoprecv(sc);
 		ath9k_hw_phy_disable(ah);
-		spin_unlock_bh(&sc->sc_pcu_lock);
-	} else {
-		spin_lock_bh(&sc->sc_pcu_lock);
+	} else
 		sc->rx.rxlink = NULL;
-		spin_unlock_bh(&sc->sc_pcu_lock);
-	}
 
 	/* disable HAL and put h/w to sleep */
 	ath9k_hw_disable(ah);
 	ath9k_hw_configpcipowersave(ah, 1, 1);
+
+	spin_unlock_bh(&sc->sc_pcu_lock);
+
 	ath9k_ps_restore(sc);
 
 	/* Finally, put the chip in FULL SLEEP mode */
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 81f63e52..e1383e5 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1148,13 +1148,11 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
 		ath_print(common, ATH_DBG_FATAL,
 			  "Failed to stop TX DMA. Resetting hardware!\n");
 
-		spin_lock_bh(&sc->sc_pcu_lock);
 		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);
-		spin_unlock_bh(&sc->sc_pcu_lock);
 	}
 
 	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
-- 
1.7.3.2.90.gd4c43


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

end of thread, other threads:[~2010-10-26 22:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-26 22:27 [PATCH 0/3] ath9k: more PCU locking enhancements Luis R. Rodriguez
2010-10-26 22:27 ` [PATCH 1/3] ath9k: simplify hw reset locking Luis R. Rodriguez
2010-10-26 22:27 ` [PATCH 2/3] ath9k: move the PCU lock to the sc structure Luis R. Rodriguez
2010-10-26 22:27 ` [PATCH 3/3] ath9k: content DMA start / stop through the PCU lock Luis R. Rodriguez

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.