diff mbox

[2/2] ath9k_htc: Handle buffered frames in AP mode

Message ID 19481.60104.126860.616742@gargle.gargle.HOWL (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Sujith June 17, 2010, 9:28 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 58f52a1..8583bf8 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -402,6 +402,7 @@  static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
 void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
 			     struct ieee80211_vif *vif);
+void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv);
 void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
 
 void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
@@ -417,7 +418,8 @@  void ath9k_ani_work(struct work_struct *work);;
 
 int ath9k_tx_init(struct ath9k_htc_priv *priv);
 void ath9k_tx_tasklet(unsigned long data);
-int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb);
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb,
+		       bool is_cab);
 void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
 bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype);
 int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index bd1506e..8901732 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -138,8 +138,8 @@  static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 	WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
 }
 
-static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
-					  struct htc_beacon_config *bss_conf)
+static void ath9k_htc_beacon_config_gen(struct ath9k_htc_priv *priv,
+					struct htc_beacon_config *bss_conf)
 {
 	struct ath_common *common = ath9k_hw_common(priv->ah);
 	enum ath9k_int imask = 0;
@@ -155,7 +155,7 @@  static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
 		imask |= ATH9K_INT_SWBA;
 
 	ath_print(common, ATH_DBG_BEACON,
-		  "IBSS Beacon config, intval: %d, imask: 0x%x\n",
+		  "Beacon config, intval: %d, imask: 0x%x\n",
 		  bss_conf->beacon_interval, imask);
 
 	WMI_CMD(WMI_DISABLE_INTR_CMDID);
@@ -171,6 +171,39 @@  void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
 	dev_kfree_skb_any(skb);
 }
 
+void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv)
+{
+	struct ath_common *common = ath9k_hw_common(priv->ah);
+	struct sk_buff *skb;
+	struct ieee80211_hdr *hdr;
+	int padpos, padsize, ret;
+
+	skb = ieee80211_get_buffered_bc(priv->hw, priv->vif);
+	while(skb) {
+		hdr = (struct ieee80211_hdr *) skb->data;
+
+		padpos = ath9k_cmn_padpos(hdr->frame_control);
+		padsize = padpos & 3;
+		if (padsize && skb->len > padpos) {
+			if (skb_headroom(skb) < padsize) {
+				dev_kfree_skb_any(skb);
+				goto next;
+			}
+			skb_push(skb, padsize);
+			memmove(skb->data, skb->data + padsize, padpos);
+		}
+
+		ret = ath9k_htc_tx_start(priv, skb, true);
+		if (ret != 0) {
+			ath_print(common, ATH_DBG_FATAL,
+				  "Failed to send CAB frame\n");
+			dev_kfree_skb_any(skb);
+		}
+	next:
+		skb = ieee80211_get_buffered_bc(priv->hw, priv->vif);
+	}
+}
+
 void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
 {
 	struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv;
@@ -268,7 +301,8 @@  void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
 		ath9k_htc_beacon_config_sta(priv, cur_conf);
 		break;
 	case NL80211_IFTYPE_ADHOC:
-		ath9k_htc_beacon_config_adhoc(priv, cur_conf);
+	case NL80211_IFTYPE_AP:
+		ath9k_htc_beacon_config_gen(priv, cur_conf);
 		break;
 	default:
 		ath_print(common, ATH_DBG_CONFIG,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index e1840b1..02651ff 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -696,7 +696,8 @@  static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
 		IEEE80211_HW_HAS_RATE_CONTROL |
 		IEEE80211_HW_RX_INCLUDES_FCS |
 		IEEE80211_HW_SUPPORTS_PS |
-		IEEE80211_HW_PS_NULLFUNC_STACK;
+		IEEE80211_HW_PS_NULLFUNC_STACK |
+		IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
 
 	hw->wiphy->interface_modes =
 		BIT(NL80211_IFTYPE_STATION) |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 2869cff..f8c1217 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1118,7 +1118,7 @@  static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 		memmove(skb->data, skb->data + padsize, padpos);
 	}
 
-	ret = ath9k_htc_tx_start(priv, skb);
+	ret = ath9k_htc_tx_start(priv, skb, false);
 	if (ret != 0) {
 		if (ret == -ENOMEM) {
 			ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index bd0b4ac..4d4b9b8 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -72,7 +72,8 @@  int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
 	return error;
 }
 
-int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb,
+		       bool is_cab)
 {
 	struct ieee80211_hdr *hdr;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -140,6 +141,11 @@  int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
 		tx_fhdr = skb_push(skb, sizeof(tx_hdr));
 		memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
 
+		if (is_cab) {
+			epid = priv->cab_ep;
+			goto send;
+		}
+
 		qnum = skb_get_queue_mapping(skb);
 
 		switch (qnum) {
@@ -183,7 +189,7 @@  int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
 		memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
 		epid = priv->mgmt_ep;
 	}
-
+send:
 	return htc_send(priv->htc, skb, epid, &tx_ctl);
 }
 
@@ -281,7 +287,8 @@  void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
 	} else if ((ep_id == priv->data_bk_ep) ||
 		   (ep_id == priv->data_be_ep) ||
 		   (ep_id == priv->data_vi_ep) ||
-		   (ep_id == priv->data_vo_ep)) {
+		   (ep_id == priv->data_vo_ep) ||
+		   (ep_id == priv->cab_ep)) {
 		skb_pull(skb, sizeof(struct tx_frame_hdr));
 	} else {
 		ath_print(common, ATH_DBG_FATAL,
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 6260faa..0b35f16 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -149,6 +149,7 @@  void ath9k_wmi_tasklet(unsigned long data)
 	case WMI_SWBA_EVENTID:
 		swba_hdr = (struct wmi_swba *) wmi_event;
 		ath9k_htc_swba(priv, swba_hdr->beacon_pending);
+		ath9k_htc_send_buffered(priv);
 		break;
 	case WMI_FATAL_EVENTID:
 		break;