Search Linux Wireless

[RFC] ath9k: add locking for rc private data

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

 



Signed-off-by: Luis R. Rodriguez <lrodriguez@xxxxxxxxxxx>
---
 drivers/net/wireless/ath/ath9k/rc.c |   62 +++++++++++++++++++++++++++++------
 drivers/net/wireless/ath/ath9k/rc.h |    2 +
 2 files changed, 54 insertions(+), 10 deletions(-)

Here's an attempt to lock the ath9k rc private data but I
get a lockdep complaint on this and not sure how to resolve it yet.

[   47.834736] =======================================================
[   47.834848] [ INFO: possible circular locking dependency detected ]
[   47.834912] 2.6.30-rc7-wl #31
[   47.834962] -------------------------------------------------------
[   47.835018] swapper/0 is trying to acquire lock:
[   47.835077]  (_xmit_IEEE80211#2){+.-...}, at: [<ffffffff804dcb51>] __qdisc_run+0x241/0x2b0
[   47.835320] 
[   47.835321] but task is already holding lock:
[   47.835419]  (&rate_priv->ath_rc_lock){+.-...}, at: [<ffffffffa0330eda>] ath_tx_status+0x3a/0x3e0 [ath9k]
[   47.835630] 
[   47.835631] which lock already depends on the new lock.
[   47.835632] 
[   47.835775] 
[   47.835780] the existing dependency chain (in reverse order) is:
[   47.835884] 
[   47.835885] -> #1 (&rate_priv->ath_rc_lock){+.-...}:
[   47.836114]        [<ffffffffffffffff>] 0xffffffffffffffff
[   47.836224] 
[   47.836225] -> #0 (_xmit_IEEE80211#2){+.-...}:
[   47.836538]        [<ffffffffffffffff>] 0xffffffffffffffff
[   47.836659] 
[   47.836660] other info that might help us debug this:
[   47.836662] 
[   47.836861] 1 lock held by swapper/0:
[   47.836933]  #0:  (&rate_priv->ath_rc_lock){+.-...}, at: [<ffffffffa0330eda>] ath_tx_status+0x3a/0x3e0 [ath9k]
[   47.837215] 
[   47.837216] stack backtrace:
[   47.837347] Pid: 0, comm: swapper Not tainted 2.6.30-rc7-wl #31
[   47.837423] Call Trace:
[   47.837493]  <IRQ>  [<ffffffff8026a9fe>] print_circular_bug_tail+0xae/0x100
[   47.837625]  [<ffffffff8026cdf0>] __lock_acquire+0xff0/0x1370
[   47.837702]  [<ffffffff802693c8>] ? add_lock_to_list+0x68/0xf0
[   47.837774]  [<ffffffff8026d279>] lock_acquire+0x109/0x150
[   47.837849]  [<ffffffff804dcb51>] ? __qdisc_run+0x241/0x2b0
[   47.837931]  [<ffffffff8055fe0c>] _spin_lock+0x3c/0x80
[   47.838000]  [<ffffffff804dcb51>] ? __qdisc_run+0x241/0x2b0
[   47.838074]  [<ffffffff805604c0>] ? _spin_unlock+0x30/0x60
[   47.838149]  [<ffffffff804dcb51>] __qdisc_run+0x241/0x2b0
[   47.838231]  [<ffffffff804cb6e8>] dev_queue_xmit+0x2c8/0x4a0
[   47.838329]  [<ffffffffa02e7fa7>] ieee80211_tx_skb+0x67/0x70 [mac80211]
[   47.838423]  [<ffffffffa02d4128>] ieee80211_start_tx_ba_session+0x498/0x5a0 [mac80211]
[   47.838521]  [<ffffffffa033125d>] ath_tx_status+0x3bd/0x3e0 [ath9k]
[   47.838617]  [<ffffffffa02ce329>] ieee80211_tx_status+0x479/0x4b0 [mac80211]
[   47.838703]  [<ffffffffa032b9dc>] ath_tx_complete_buf+0x20c/0x230 [ath9k]
[   47.838795]  [<ffffffffa032e3a8>] ath_tx_tasklet+0x198/0x4c0 [ath9k]
[   47.838882]  [<ffffffffa03295f8>] ath9k_tasklet+0xf8/0x1f0 [ath9k]
[   47.838960]  [<ffffffff80244fad>] tasklet_action+0x9d/0x130
[   47.839036]  [<ffffffff80245620>] __do_softirq+0xf0/0x220
[   47.839114]  [<ffffffff8020d17c>] call_softirq+0x1c/0x30
[   47.839190]  [<ffffffff8020e6c5>] do_softirq+0x75/0xb0
[   47.839259]  [<ffffffff8024530d>] irq_exit+0x9d/0xb0
[   47.839339]  [<ffffffff8020df4d>] do_IRQ+0x8d/0xf0
[   47.839414]  [<ffffffff8020c993>] ret_from_intr+0x0/0xf
[   47.839489]  <EOI>  [<ffffffff8021424f>] ? default_idle+0x7f/0x180
[   47.839608]  [<ffffffff8021424d>] ? default_idle+0x7d/0x180
[   47.839690]  [<ffffffff802646ed>] ? clockevents_notify+0x3d/0x90
[   47.839761]  [<ffffffff802143fd>] ? c1e_idle+0xad/0x120
[   47.839837]  [<ffffffff805638c1>] ? atomic_notifier_call_chain+0x11/0x20
[   47.839916]  [<ffffffff8020ab44>] ? cpu_idle+0x64/0xd0
[   47.839993]  [<ffffffff805594e9>] ? start_secondary+0x168/0x1bf


diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index ba06e78..b7fa0f2 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -741,12 +741,26 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
 	if (rate > (ath_rc_priv->rate_table_size - 1))
 		rate = ath_rc_priv->rate_table_size - 1;
 
-	ASSERT((rate_table->info[rate].valid &&
-		(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) ||
-	       (rate_table->info[rate].valid_single_stream &&
-		!(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)));
+	/* Rate is a valid and dual stream */
+	if (rate_table->info[rate].valid &&
+	    (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+		return rate;
 
-	return rate;
+	/* Rate is valid and single stream */
+	if (rate_table->info[rate].valid_single_stream &&
+	    !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+		return rate;
+
+	WARN_ON(!rate_table->info[rate].valid &&
+		!rate_table->info[rate].valid_single_stream);
+
+	/*
+	 * This is not expected, getting here would indicate no
+	 * valid dual stream or single stream rate.
+	 */
+	WARN_ON(1);
+
+	return minindex;
 }
 
 static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table,
@@ -1389,6 +1403,7 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
 	return sc->hw_rate_table[mode];
 }
 
+/* Must hold rc priv lock */
 static void ath_rc_init(struct ath_softc *sc,
 			struct ath_rate_priv *ath_rc_priv,
 			struct ieee80211_supported_band *sband,
@@ -1506,6 +1521,9 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
 	int final_ts_idx, tx_status = 0, is_underrun = 0;
 	__le16 fc;
 
+	/* Could be called from the mac80211 tasklet */
+	spin_lock_bh(&ath_rc_priv->ath_rc_lock);
+
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = hdr->frame_control;
 	tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
@@ -1558,6 +1576,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
 	ath_debug_stat_rc(sc, skb);
 exit:
 	kfree(tx_info_priv);
+	spin_unlock_bh(&ath_rc_priv->ath_rc_lock);
 }
 
 static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
@@ -1582,7 +1601,9 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 	}
 
 	/* Find tx rate for unicast frames */
+	spin_lock_bh(&ath_rc_priv->ath_rc_lock);
 	ath_rc_ratefind(sc, ath_rc_priv, txrc);
+	spin_unlock_bh(&ath_rc_priv->ath_rc_lock);
 }
 
 static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
@@ -1594,6 +1615,8 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
 	bool is_cw40, is_sgi40;
 	int i, j = 0;
 
+	spin_lock_bh(&ath_rc_priv->ath_rc_lock);
+
 	for (i = 0; i < sband->n_bitrates; i++) {
 		if (sta->supp_rates[sband->band] & BIT(i)) {
 			ath_rc_priv->neg_rates.rs_rates[j]
@@ -1631,6 +1654,9 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
 
 	ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40);
 	ath_rc_init(sc, priv_sta, sband, sta, rate_table);
+
+	spin_unlock_bh(&ath_rc_priv->ath_rc_lock);
+
 }
 
 static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
@@ -1641,16 +1667,18 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
 	struct ath_rate_priv *ath_rc_priv = priv_sta;
 	const struct ath_rate_table *rate_table = NULL;
 	bool oper_cw40 = false, oper_sgi40;
-	bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ?
-		true : false;
-	bool local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ?
-		true : false;
+	bool local_cw40, local_sgi40;
+	/* Test */
+	spin_lock_bh(&ath_rc_priv->ath_rc_lock);
+
+	local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ? true : false;
+	local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ? true : false;
 
 	/* FIXME: Handle AP mode later when we support CWM */
 
 	if (changed & IEEE80211_RC_HT_CHANGED) {
 		if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
-			return;
+			goto out;
 
 		if (sc->hw->conf.channel_type == NL80211_CHAN_HT40MINUS ||
 		    sc->hw->conf.channel_type == NL80211_CHAN_HT40PLUS)
@@ -1672,6 +1700,9 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
 				sc->hw->conf.channel_type);
 		}
 	}
+
+out:
+	spin_unlock_bh(&ath_rc_priv->ath_rc_lock);
 }
 
 static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
@@ -1700,6 +1731,8 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
 	rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
 	rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
 
+	spin_lock_init(&rate_priv->ath_rc_lock);
+
 	return rate_priv;
 }
 
@@ -1707,6 +1740,15 @@ static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
 			      void *priv_sta)
 {
 	struct ath_rate_priv *rate_priv = priv_sta;
+
+	/*
+	 * Let whoever is working on the sta priv to finish.
+	 * There is a _small_ race here between rate_control_free_sta()
+	 * which called us and the actual free of the sta.
+	 */
+	spin_lock_bh(&rate_priv->ath_rc_lock);
+	spin_unlock_bh(&rate_priv->ath_rc_lock);
+
 	kfree(rate_priv);
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index e3abd76..1508184 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -137,6 +137,7 @@ struct ath_rateset {
 
 /**
  * struct ath_rate_priv - Rate Control priv data
+ * @ath_rc_lock: used to protect the private rate sta struct
  * @state: RC state
  * @rssi_last: last ACK rssi
  * @rssi_last_lookup: last ACK rssi used for lookup
@@ -161,6 +162,7 @@ struct ath_rateset {
  * @neg_ht_rates: Negotiated HT rates
  */
 struct ath_rate_priv {
+	spinlock_t ath_rc_lock;
 	int8_t rssi_last;
 	int8_t rssi_last_lookup;
 	int8_t rssi_last_prev;
-- 
1.5.6.4

--
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