Browse Source

wlcore: fixes for connection_loss_work

We can't use cancel_delayed_work_sync() from functions that take the
wl->mutex, since connection_loss_work also takes the mutex. This might
result in a deadlock. Restructure the code so the work is synchronously
canceled before taking the mutex.
Avoid a bug where we would indefinitely delay the connection loss
indication by re-queuing the connection loss work on consecutive beacon
loss events.

Cc: bartosz.markowski <bartosz.markowski@tieto.com>
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
Arik Nemtsov 13 years ago
parent
commit
6b8bf5bc5e
2 changed files with 19 additions and 6 deletions
  1. 12 3
      drivers/net/wireless/ti/wlcore/event.c
  2. 7 3
      drivers/net/wireless/ti/wlcore/main.c

+ 12 - 3
drivers/net/wireless/ti/wlcore/event.c

@@ -148,15 +148,24 @@ static int wl1271_event_process(struct wl1271 *wl)
 		int delay = wl->conf.conn.synch_fail_thold *
 					wl->conf.conn.bss_lose_timeout;
 		wl1271_info("Beacon loss detected.");
-		cancel_delayed_work_sync(&wl->connection_loss_work);
+
+		/*
+		 * if the work is already queued, it should take place. We
+		 * don't want to delay the connection loss indication
+		 * any more.
+		 */
 		ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
-		      msecs_to_jiffies(delay));
+					     msecs_to_jiffies(delay));
 	}
 
 	if (vector & REGAINED_BSS_EVENT_ID) {
 		/* TODO: check for multi-role */
 		wl1271_info("Beacon regained.");
-		cancel_delayed_work_sync(&wl->connection_loss_work);
+		cancel_delayed_work(&wl->connection_loss_work);
+
+		/* sanity check - we can't lose and gain the beacon together */
+		WARN(vector & BSS_LOSE_EVENT_ID,
+		     "Concurrent beacon loss and gain from FW");
 	}
 
 	if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {

+ 7 - 3
drivers/net/wireless/ti/wlcore/main.c

@@ -3712,9 +3712,6 @@ sta_not_found:
 			do_join = true;
 			set_assoc = true;
 
-			/* Cancel connection_loss_work */
-			cancel_delayed_work_sync(&wl->connection_loss_work);
-
 			/*
 			 * use basic rates from AP, and determine lowest rate
 			 * to use with control frames.
@@ -3964,6 +3961,13 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 	wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
 		     (int)changed);
 
+	/*
+	 * make sure to cancel pending disconnections if our association
+	 * state changed
+	 */
+	if (!is_ap && (changed & BSS_CHANGED_ASSOC))
+		cancel_delayed_work_sync(&wl->connection_loss_work);
+
 	mutex_lock(&wl->mutex);
 
 	if (unlikely(wl->state == WL1271_STATE_OFF))