[PATCH 1/6] staging: brcm80211: implement flush driver callback for mac80211

Arend van Spriel arend at broadcom.com
Mon Apr 18 13:31:46 UTC 2011


The mac80211 interface has a flush callback which is used by mac80211
to assure all pending transmit packets have been transmitted. This
is used before scanning off-channel.

Reviewed-by: Roland Vossen <rvossen at broadcom.com>
Reviewed-by: Henry Ptasinski <henryp at broadcom.com>
Reviewed-by: Brett Rudley <brudley at broadcom.com>
Signed-off-by: Arend van Spriel <arend at broadcom.com>
Cc: devel at linuxdriverproject.org
Cc: linux-wireless at vger.kernel.org
---
 drivers/staging/brcm80211/brcmsmac/wl_export.h   |    1 +
 drivers/staging/brcm80211/brcmsmac/wl_mac80211.c |   24 ++++++++++++++++++++++
 drivers/staging/brcm80211/brcmsmac/wlc_main.c    |   13 +++++++++++
 drivers/staging/brcm80211/brcmsmac/wlc_pub.h     |    1 +
 4 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/brcm80211/brcmsmac/wl_export.h b/drivers/staging/brcm80211/brcmsmac/wl_export.h
index 9ff760f..0fe0b24 100644
--- a/drivers/staging/brcm80211/brcmsmac/wl_export.h
+++ b/drivers/staging/brcm80211/brcmsmac/wl_export.h
@@ -42,5 +42,6 @@ extern void wl_free_timer(struct wl_info *wl, struct wl_timer *timer);
 extern void wl_add_timer(struct wl_info *wl, struct wl_timer *timer, uint ms,
 			 int periodic);
 extern bool wl_del_timer(struct wl_info *wl, struct wl_timer *timer);
+extern void wl_msleep(struct wl_info *wl, uint ms);
 
 #endif				/* _wl_export_h_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
index 169d26b..6ea747f 100644
--- a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
+++ b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
@@ -151,6 +151,7 @@ static int wl_ops_ampdu_action(struct ieee80211_hw *hw,
 			       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
 			       u8 buf_size);
 static void wl_ops_rfkill_poll(struct ieee80211_hw *hw);
+static void wl_ops_flush(struct ieee80211_hw *hw, bool drop);
 
 static void wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
@@ -690,6 +691,18 @@ static void wl_ops_rfkill_poll(struct ieee80211_hw *hw)
 	wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);
 }
 
+static void wl_ops_flush(struct ieee80211_hw *hw, bool drop)
+{
+	struct wl_info *wl = HW_TO_WL(hw);
+
+	no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false");
+
+	/* wait for packet queue and dma fifos to run empty */
+	WL_LOCK(wl);
+	wlc_wait_for_tx_completion(wl->wlc, drop);
+	WL_UNLOCK(wl);
+}
+
 static const struct ieee80211_ops wl_ops = {
 	.tx = wl_ops_tx,
 	.start = wl_ops_start,
@@ -711,6 +724,7 @@ static const struct ieee80211_ops wl_ops = {
 	.sta_remove = wl_ops_sta_remove,
 	.ampdu_action = wl_ops_ampdu_action,
 	.rfkill_poll = wl_ops_rfkill_poll,
+	.flush = wl_ops_flush,
 };
 
 /*
@@ -1981,3 +1995,13 @@ bool wl_rfkill_set_hw_state(struct wl_info *wl)
 	WL_LOCK(wl);
 	return blocked;
 }
+
+/*
+ * precondition: perimeter lock has been acquired
+ */
+void wl_msleep(struct wl_info *wl, uint ms)
+{
+	WL_UNLOCK(wl);
+	msleep(ms);
+	WL_LOCK(wl);
+}
diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_main.c b/drivers/staging/brcm80211/brcmsmac/wlc_main.c
index 93e2f2c..3e5d884 100644
--- a/drivers/staging/brcm80211/brcmsmac/wlc_main.c
+++ b/drivers/staging/brcm80211/brcmsmac/wlc_main.c
@@ -8097,3 +8097,16 @@ int wlc_get_curband(struct wlc_info *wlc)
 {
 	return wlc->band->bandunit;
 }
+
+void wlc_wait_for_tx_completion(struct wlc_info *wlc, bool drop)
+{
+	/* flush packet queue when requested */
+	if (drop)
+		pktq_flush(&wlc->active_queue->q, false, NULL, 0);
+
+	/* wait for queue and DMA fifos to run dry */
+	while (!pktq_empty(&wlc->active_queue->q) ||
+	       TXPKTPENDTOT(wlc) > 0) {
+		wl_msleep(wlc->wl, 1);
+	}
+}
diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_pub.h b/drivers/staging/brcm80211/brcmsmac/wlc_pub.h
index eea9aa7..626d424 100644
--- a/drivers/staging/brcm80211/brcmsmac/wlc_pub.h
+++ b/drivers/staging/brcm80211/brcmsmac/wlc_pub.h
@@ -569,6 +569,7 @@ extern void wlc_scan_start(struct wlc_info *wlc);
 extern void wlc_scan_stop(struct wlc_info *wlc);
 extern void wlc_associate_upd(struct wlc_info *wlc, bool state);
 extern int wlc_get_curband(struct wlc_info *wlc);
+extern void wlc_wait_for_tx_completion(struct wlc_info *wlc, bool drop);
 
 static inline int wlc_iovar_getuint(struct wlc_info *wlc, const char *name,
 				    uint *arg)
-- 
1.7.1





More information about the devel mailing list