diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_main.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1271_tx.h | 1 |
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 */ |
415 | void wl1271_tx_flush(struct wl1271 *wl) | 419 | void 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 */ | ||
445 | void 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 | ||
159 | void wl1271_tx_work(struct work_struct *work); | 159 | void wl1271_tx_work(struct work_struct *work); |
160 | void wl1271_tx_complete(struct wl1271 *wl); | 160 | void wl1271_tx_complete(struct wl1271 *wl); |
161 | void wl1271_tx_reset(struct wl1271 *wl); | ||
161 | void wl1271_tx_flush(struct wl1271 *wl); | 162 | void wl1271_tx_flush(struct wl1271 *wl); |
162 | u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); | 163 | u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); |
163 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); | 164 | u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); |