@@ -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);
@@ -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,
@@ -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) |
@@ -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,
@@ -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,
@@ -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;