summaryrefslogtreecommitdiff
path: root/drivers/staging/brcm80211
diff options
context:
space:
mode:
authorRoland Vossen <rvossen@broadcom.com>2011-03-10 11:35:08 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2011-03-14 11:44:03 -0700
commit61f4420597b750e932ad0e8567715f1a3439bb03 (patch)
tree1a79d8faea042251e6934f0a2a21526541d9b825 /drivers/staging/brcm80211
parent8ada0be34014565dc4e57d1194d18594a5bcd161 (diff)
staging: brcm80211: added IEEE80211_AMPDU_TX_STOP handling
Driver now flushes AMPDU packets for a specified station on Mac80211 calling wl_ops_ampdu_action(IEEE80211_AMPDU_TX_STOP). Not all AMPDU packets are flushed yet: there can still be AMPDU packets pending in hardware (DMA). That is the subject of the next patch in this series. Signed-off-by: Roland Vossen <rvossen@broadcom.com> Reviewed-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/brcm80211')
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wl_mac80211.c3
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c43
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_pub.h4
3 files changed, 50 insertions, 0 deletions
diff --git a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
index 3550551da316..a523b231cffe 100644
--- a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
+++ b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c
@@ -648,6 +648,9 @@ wl_ops_ampdu_action(struct ieee80211_hw *hw,
break;
case IEEE80211_AMPDU_TX_STOP:
+ WL_LOCK(wl);
+ wlc_ampdu_flush(wl->wlc, sta, tid);
+ WL_UNLOCK(wl);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c b/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c
index 26dd9b6a8757..3d00180efacc 100644
--- a/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c
+++ b/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c
@@ -1363,3 +1363,46 @@ void wlc_ampdu_shm_upd(struct ampdu_info *ampdu)
wlc_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
}
}
+
+struct cb_del_ampdu_pars {
+ struct ieee80211_sta *sta;
+ u16 tid;
+};
+
+/*
+ * callback function that helps flushing ampdu packets from a priority queue
+ */
+static bool cb_del_ampdu_pkt(void *p, int arg_a)
+{
+ struct sk_buff *mpdu = (struct sk_buff *)p;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu);
+ struct cb_del_ampdu_pars *ampdu_pars =
+ (struct cb_del_ampdu_pars *)arg_a;
+ bool rc;
+
+ rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false;
+ rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL ||
+ tx_info->control.sta == ampdu_pars->sta);
+ rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid);
+ return rc;
+}
+
+/*
+ * When a remote party is no longer available for ampdu communication, any
+ * pending tx ampdu packets in the driver have to be flushed.
+ */
+void wlc_ampdu_flush(struct wlc_info *wlc,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct wlc_txq_info *qi = wlc->active_queue;
+ struct pktq *pq = &qi->q;
+ int prec;
+ struct cb_del_ampdu_pars ampdu_pars;
+
+ ampdu_pars.sta = sta;
+ ampdu_pars.tid = tid;
+ for (prec = 0; prec < pq->num_prec; prec++) {
+ pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
+ (int)&ampdu_pars);
+ }
+}
diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_pub.h b/drivers/staging/brcm80211/brcmsmac/wlc_pub.h
index 5536f5111f48..b956c23fa467 100644
--- a/drivers/staging/brcm80211/brcmsmac/wlc_pub.h
+++ b/drivers/staging/brcm80211/brcmsmac/wlc_pub.h
@@ -536,6 +536,10 @@ extern u32 wlc_delta_txfunfl(struct wlc_info *wlc, int fifo);
extern void wlc_rate_lookup_init(struct wlc_info *wlc, wlc_rateset_t *rateset);
extern void wlc_default_rateset(struct wlc_info *wlc, wlc_rateset_t *rs);
+struct ieee80211_sta;
+extern void wlc_ampdu_flush(struct wlc_info *wlc, struct ieee80211_sta *sta,
+ u16 tid);
+
/* wlc_phy.c helper functions */
extern void wlc_set_ps_ctrl(struct wlc_info *wlc);
extern void wlc_mctrl(struct wlc_info *wlc, u32 mask, u32 val);