diff options
4 files changed, 27 insertions, 29 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 0f71d1d4339d..e5fd20994bec 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include "debug.h" | 36 | #include "debug.h" |
| 37 | 37 | ||
| 38 | #define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ | 38 | #define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ |
| 39 | #define BRCMS_FLUSH_TIMEOUT 500 /* msec */ | ||
| 39 | 40 | ||
| 40 | /* Flags we support */ | 41 | /* Flags we support */ |
| 41 | #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ | 42 | #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ |
| @@ -708,16 +709,29 @@ static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw) | |||
| 708 | wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); | 709 | wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); |
| 709 | } | 710 | } |
| 710 | 711 | ||
| 712 | static bool brcms_tx_flush_completed(struct brcms_info *wl) | ||
| 713 | { | ||
| 714 | bool result; | ||
| 715 | |||
| 716 | spin_lock_bh(&wl->lock); | ||
| 717 | result = brcms_c_tx_flush_completed(wl->wlc); | ||
| 718 | spin_unlock_bh(&wl->lock); | ||
| 719 | return result; | ||
| 720 | } | ||
| 721 | |||
| 711 | static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop) | 722 | static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop) |
| 712 | { | 723 | { |
| 713 | struct brcms_info *wl = hw->priv; | 724 | struct brcms_info *wl = hw->priv; |
| 725 | int ret; | ||
| 714 | 726 | ||
| 715 | no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); | 727 | no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); |
| 716 | 728 | ||
| 717 | /* wait for packet queue and dma fifos to run empty */ | 729 | ret = wait_event_timeout(wl->tx_flush_wq, |
| 718 | spin_lock_bh(&wl->lock); | 730 | brcms_tx_flush_completed(wl), |
| 719 | brcms_c_wait_for_tx_completion(wl->wlc, drop); | 731 | msecs_to_jiffies(BRCMS_FLUSH_TIMEOUT)); |
| 720 | spin_unlock_bh(&wl->lock); | 732 | |
| 733 | brcms_dbg_mac80211(wl->wlc->hw->d11core, | ||
| 734 | "ret=%d\n", jiffies_to_msecs(ret)); | ||
| 721 | } | 735 | } |
| 722 | 736 | ||
| 723 | static const struct ieee80211_ops brcms_ops = { | 737 | static const struct ieee80211_ops brcms_ops = { |
| @@ -772,6 +786,7 @@ void brcms_dpc(unsigned long data) | |||
| 772 | 786 | ||
| 773 | done: | 787 | done: |
| 774 | spin_unlock_bh(&wl->lock); | 788 | spin_unlock_bh(&wl->lock); |
| 789 | wake_up(&wl->tx_flush_wq); | ||
| 775 | } | 790 | } |
| 776 | 791 | ||
| 777 | /* | 792 | /* |
| @@ -1020,6 +1035,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) | |||
| 1020 | 1035 | ||
| 1021 | atomic_set(&wl->callbacks, 0); | 1036 | atomic_set(&wl->callbacks, 0); |
| 1022 | 1037 | ||
| 1038 | init_waitqueue_head(&wl->tx_flush_wq); | ||
| 1039 | |||
| 1023 | /* setup the bottom half handler */ | 1040 | /* setup the bottom half handler */ |
| 1024 | tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); | 1041 | tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); |
| 1025 | 1042 | ||
| @@ -1609,13 +1626,3 @@ bool brcms_rfkill_set_hw_state(struct brcms_info *wl) | |||
| 1609 | spin_lock_bh(&wl->lock); | 1626 | spin_lock_bh(&wl->lock); |
| 1610 | return blocked; | 1627 | return blocked; |
| 1611 | } | 1628 | } |
| 1612 | |||
| 1613 | /* | ||
| 1614 | * precondition: perimeter lock has been acquired | ||
| 1615 | */ | ||
| 1616 | void brcms_msleep(struct brcms_info *wl, uint ms) | ||
| 1617 | { | ||
| 1618 | spin_unlock_bh(&wl->lock); | ||
| 1619 | msleep(ms); | ||
| 1620 | spin_lock_bh(&wl->lock); | ||
| 1621 | } | ||
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h index 9358bd5ebd35..947ccacf43e6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h | |||
| @@ -68,6 +68,8 @@ struct brcms_info { | |||
| 68 | spinlock_t lock; /* per-device perimeter lock */ | 68 | spinlock_t lock; /* per-device perimeter lock */ |
| 69 | spinlock_t isr_lock; /* per-device ISR synchronization lock */ | 69 | spinlock_t isr_lock; /* per-device ISR synchronization lock */ |
| 70 | 70 | ||
| 71 | /* tx flush */ | ||
| 72 | wait_queue_head_t tx_flush_wq; | ||
| 71 | 73 | ||
| 72 | /* timer related fields */ | 74 | /* timer related fields */ |
| 73 | atomic_t callbacks; /* # outstanding callback functions */ | 75 | atomic_t callbacks; /* # outstanding callback functions */ |
| @@ -100,7 +102,6 @@ extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl, | |||
| 100 | extern void brcms_free_timer(struct brcms_timer *timer); | 102 | extern void brcms_free_timer(struct brcms_timer *timer); |
| 101 | extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic); | 103 | extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic); |
| 102 | extern bool brcms_del_timer(struct brcms_timer *timer); | 104 | extern bool brcms_del_timer(struct brcms_timer *timer); |
| 103 | extern void brcms_msleep(struct brcms_info *wl, uint ms); | ||
| 104 | extern void brcms_dpc(unsigned long data); | 105 | extern void brcms_dpc(unsigned long data); |
| 105 | extern void brcms_timer(struct brcms_timer *t); | 106 | extern void brcms_timer(struct brcms_timer *t); |
| 106 | extern void brcms_fatal_error(struct brcms_info *wl); | 107 | extern void brcms_fatal_error(struct brcms_info *wl); |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 9f3d7e9f3bb5..8b5839008af3 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c | |||
| @@ -7511,25 +7511,16 @@ int brcms_c_get_curband(struct brcms_c_info *wlc) | |||
| 7511 | return wlc->band->bandunit; | 7511 | return wlc->band->bandunit; |
| 7512 | } | 7512 | } |
| 7513 | 7513 | ||
| 7514 | void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop) | 7514 | bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc) |
| 7515 | { | 7515 | { |
| 7516 | int timeout = 20; | ||
| 7517 | int i; | 7516 | int i; |
| 7518 | 7517 | ||
| 7519 | /* Kick DMA to send any pending AMPDU */ | 7518 | /* Kick DMA to send any pending AMPDU */ |
| 7520 | for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++) | 7519 | for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++) |
| 7521 | if (wlc->hw->di[i]) | 7520 | if (wlc->hw->di[i]) |
| 7522 | dma_txflush(wlc->hw->di[i]); | 7521 | dma_kick_tx(wlc->hw->di[i]); |
| 7523 | 7522 | ||
| 7524 | /* wait for queue and DMA fifos to run dry */ | 7523 | return !brcms_txpktpendtot(wlc); |
| 7525 | while (brcms_txpktpendtot(wlc) > 0) { | ||
| 7526 | brcms_msleep(wlc->wl, 1); | ||
| 7527 | |||
| 7528 | if (--timeout == 0) | ||
| 7529 | break; | ||
| 7530 | } | ||
| 7531 | |||
| 7532 | WARN_ON_ONCE(timeout == 0); | ||
| 7533 | } | 7524 | } |
| 7534 | 7525 | ||
| 7535 | void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval) | 7526 | void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval) |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index 4fb2834f4e64..b0f14b7b8616 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h | |||
| @@ -314,8 +314,6 @@ extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state); | |||
| 314 | extern void brcms_c_scan_start(struct brcms_c_info *wlc); | 314 | extern void brcms_c_scan_start(struct brcms_c_info *wlc); |
| 315 | extern void brcms_c_scan_stop(struct brcms_c_info *wlc); | 315 | extern void brcms_c_scan_stop(struct brcms_c_info *wlc); |
| 316 | extern int brcms_c_get_curband(struct brcms_c_info *wlc); | 316 | extern int brcms_c_get_curband(struct brcms_c_info *wlc); |
| 317 | extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, | ||
| 318 | bool drop); | ||
| 319 | extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel); | 317 | extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel); |
| 320 | extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl); | 318 | extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl); |
| 321 | extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc, | 319 | extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc, |
| @@ -332,5 +330,6 @@ extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr); | |||
| 332 | extern int brcms_c_get_tx_power(struct brcms_c_info *wlc); | 330 | extern int brcms_c_get_tx_power(struct brcms_c_info *wlc); |
| 333 | extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc); | 331 | extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc); |
| 334 | extern void brcms_c_mute(struct brcms_c_info *wlc, bool on); | 332 | extern void brcms_c_mute(struct brcms_c_info *wlc, bool on); |
| 333 | extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc); | ||
| 335 | 334 | ||
| 336 | #endif /* _BRCM_PUB_H_ */ | 335 | #endif /* _BRCM_PUB_H_ */ |
