aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-05-24 04:18:17 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-02 16:13:35 -0400
commit781608c41386b560b501404233fc43d8ef100c71 (patch)
treec6e4e60c7cb9298afdd5f1e92696dc49a877bcf1 /drivers/net/wireless/wl12xx
parent0d58cbff2495fda8b2389719d30da694d3077a87 (diff)
wl1271: Flush TX buffers to air before going to idle
The mac80211 changes to idle almost immediately after transmitting some frames, such as deauth etc. When going to idle, the wl1271 is disconnected, which causes TX frames already on buffers, but not yet transmitted, to be deleted. To make sure deauth frames reach the air, allow the TX buffers to flush before proceeding to idle. Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Reviewed-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com> Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h1
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c11
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c36
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h1
4 files changed, 45 insertions, 4 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index a170aed2d66..4984f46626d 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -396,6 +396,7 @@ struct wl1271 {
396 396
397 /* Pending TX frames */ 397 /* Pending TX frames */
398 struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; 398 struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
399 int tx_frames_cnt;
399 400
400 /* Security sequence number counters */ 401 /* Security sequence number counters */
401 u8 tx_security_last_seq; 402 u8 tx_security_last_seq;
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 65301266286..7bf655d5515 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -1051,7 +1051,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1051 mutex_lock(&wl->mutex); 1051 mutex_lock(&wl->mutex);
1052 1052
1053 /* let's notify MAC80211 about the remaining pending TX frames */ 1053 /* let's notify MAC80211 about the remaining pending TX frames */
1054 wl1271_tx_flush(wl); 1054 wl1271_tx_reset(wl);
1055 wl1271_power_off(wl); 1055 wl1271_power_off(wl);
1056 1056
1057 memset(wl->bssid, 0, ETH_ALEN); 1057 memset(wl->bssid, 0, ETH_ALEN);
@@ -1298,6 +1298,15 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1298 conf->power_level, 1298 conf->power_level,
1299 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use"); 1299 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
1300 1300
1301 /*
1302 * mac80211 will go to idle nearly immediately after transmitting some
1303 * frames, such as the deauth. To make sure those frames reach the air,
1304 * wait here until the TX queue is fully flushed.
1305 */
1306 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1307 (conf->flags & IEEE80211_CONF_IDLE))
1308 wl1271_tx_flush(wl);
1309
1301 mutex_lock(&wl->mutex); 1310 mutex_lock(&wl->mutex);
1302 1311
1303 if (unlikely(wl->state == WL1271_STATE_OFF)) 1312 if (unlikely(wl->state == WL1271_STATE_OFF))
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 62db79508dd..c592cc2e9fe 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -36,6 +36,7 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
36 for (i = 0; i < ACX_TX_DESCRIPTORS; i++) 36 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
37 if (wl->tx_frames[i] == NULL) { 37 if (wl->tx_frames[i] == NULL) {
38 wl->tx_frames[i] = skb; 38 wl->tx_frames[i] = skb;
39 wl->tx_frames_cnt++;
39 return i; 40 return i;
40 } 41 }
41 42
@@ -73,8 +74,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
73 wl1271_debug(DEBUG_TX, 74 wl1271_debug(DEBUG_TX,
74 "tx_allocate: size: %d, blocks: %d, id: %d", 75 "tx_allocate: size: %d, blocks: %d, id: %d",
75 total_len, total_blocks, id); 76 total_len, total_blocks, id);
76 } else 77 } else {
77 wl->tx_frames[id] = NULL; 78 wl->tx_frames[id] = NULL;
79 wl->tx_frames_cnt--;
80 }
78 81
79 return ret; 82 return ret;
80} 83}
@@ -358,6 +361,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
358 /* return the packet to the stack */ 361 /* return the packet to the stack */
359 ieee80211_tx_status(wl->hw, skb); 362 ieee80211_tx_status(wl->hw, skb);
360 wl->tx_frames[result->id] = NULL; 363 wl->tx_frames[result->id] = NULL;
364 wl->tx_frames_cnt--;
361} 365}
362 366
363/* Called upon reception of a TX complete interrupt */ 367/* Called upon reception of a TX complete interrupt */
@@ -412,7 +416,7 @@ void wl1271_tx_complete(struct wl1271 *wl)
412} 416}
413 417
414/* caller must hold wl->mutex */ 418/* caller must hold wl->mutex */
415void wl1271_tx_flush(struct wl1271 *wl) 419void wl1271_tx_reset(struct wl1271 *wl)
416{ 420{
417 int i; 421 int i;
418 struct sk_buff *skb; 422 struct sk_buff *skb;
@@ -421,7 +425,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
421/* control->flags = 0; FIXME */ 425/* control->flags = 0; FIXME */
422 426
423 while ((skb = skb_dequeue(&wl->tx_queue))) { 427 while ((skb = skb_dequeue(&wl->tx_queue))) {
424 wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb); 428 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
425 ieee80211_tx_status(wl->hw, skb); 429 ieee80211_tx_status(wl->hw, skb);
426 } 430 }
427 431
@@ -429,6 +433,32 @@ void wl1271_tx_flush(struct wl1271 *wl)
429 if (wl->tx_frames[i] != NULL) { 433 if (wl->tx_frames[i] != NULL) {
430 skb = wl->tx_frames[i]; 434 skb = wl->tx_frames[i];
431 wl->tx_frames[i] = NULL; 435 wl->tx_frames[i] = NULL;
436 wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
432 ieee80211_tx_status(wl->hw, skb); 437 ieee80211_tx_status(wl->hw, skb);
433 } 438 }
439 wl->tx_frames_cnt = 0;
440}
441
442#define WL1271_TX_FLUSH_TIMEOUT 500000
443
444/* caller must *NOT* hold wl->mutex */
445void wl1271_tx_flush(struct wl1271 *wl)
446{
447 unsigned long timeout;
448 timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
449
450 while (!time_after(jiffies, timeout)) {
451 mutex_lock(&wl->mutex);
452 wl1271_debug(DEBUG_TX, "flushing tx buffer: %d",
453 wl->tx_frames_cnt);
454 if ((wl->tx_frames_cnt == 0) &&
455 skb_queue_empty(&wl->tx_queue)) {
456 mutex_unlock(&wl->mutex);
457 return;
458 }
459 mutex_unlock(&wl->mutex);
460 msleep(1);
461 }
462
463 wl1271_warning("Unable to flush all TX buffers, timed out.");
434} 464}
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 3b8b7ac253f..0ae00637933 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -158,6 +158,7 @@ static inline int wl1271_tx_ac_to_tid(int ac)
158 158
159void wl1271_tx_work(struct work_struct *work); 159void wl1271_tx_work(struct work_struct *work);
160void wl1271_tx_complete(struct wl1271 *wl); 160void wl1271_tx_complete(struct wl1271 *wl);
161void wl1271_tx_reset(struct wl1271 *wl);
161void wl1271_tx_flush(struct wl1271 *wl); 162void wl1271_tx_flush(struct wl1271 *wl);
162u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); 163u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
163u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); 164u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);