Commit 7d547eb4 authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville

ath9k_htc: Handle buffered frames in AP mode

Use the CAB endpoint to send buffered multicast or
broadcast frames after each SWBA event.
Signed-off-by: default avatarSujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2493a547
...@@ -292,6 +292,7 @@ struct ath9k_htc_tx_ctl { ...@@ -292,6 +292,7 @@ struct ath9k_htc_tx_ctl {
#define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++)
#define CAB_STAT_INC priv->debug.tx_stats.cab_queued++
#define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
...@@ -301,6 +302,7 @@ struct ath_tx_stats { ...@@ -301,6 +302,7 @@ struct ath_tx_stats {
u32 skb_queued; u32 skb_queued;
u32 skb_completed; u32 skb_completed;
u32 skb_dropped; u32 skb_dropped;
u32 cab_queued;
u32 queue_stats[WME_NUM_AC]; u32 queue_stats[WME_NUM_AC];
}; };
...@@ -324,6 +326,7 @@ struct ath9k_debug { ...@@ -324,6 +326,7 @@ struct ath9k_debug {
#define TX_STAT_INC(c) do { } while (0) #define TX_STAT_INC(c) do { } while (0)
#define RX_STAT_INC(c) do { } while (0) #define RX_STAT_INC(c) do { } while (0)
#define CAB_STAT_INC do { } while (0)
#define TX_QSTAT_INC(c) do { } while (0) #define TX_QSTAT_INC(c) do { } while (0)
...@@ -505,7 +508,8 @@ void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); ...@@ -505,7 +508,8 @@ void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv);
int ath9k_tx_init(struct ath9k_htc_priv *priv); int ath9k_tx_init(struct ath9k_htc_priv *priv);
void ath9k_tx_tasklet(unsigned long data); 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); void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype);
int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv);
......
...@@ -272,6 +272,48 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, ...@@ -272,6 +272,48 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
int slot)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ieee80211_vif *vif;
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
int padpos, padsize, ret;
spin_lock_bh(&priv->beacon_lock);
vif = priv->cur_beacon_conf.bslot[slot];
skb = ieee80211_get_buffered_bc(priv->hw, 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_dbg(common, ATH_DBG_FATAL,
"Failed to send CAB frame\n");
dev_kfree_skb_any(skb);
}
next:
skb = ieee80211_get_buffered_bc(priv->hw, vif);
}
spin_unlock_bh(&priv->beacon_lock);
}
static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
int slot) int slot)
{ {
...@@ -390,6 +432,7 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv) ...@@ -390,6 +432,7 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv)
} }
spin_unlock_bh(&priv->beacon_lock); spin_unlock_bh(&priv->beacon_lock);
ath9k_htc_send_buffered(priv, slot);
ath9k_htc_send_beacon(priv, slot); ath9k_htc_send_beacon(priv, slot);
} }
......
...@@ -748,7 +748,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, ...@@ -748,7 +748,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK; IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
hw->wiphy->interface_modes = hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_STATION) |
......
...@@ -797,6 +797,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, ...@@ -797,6 +797,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len, len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs dropped", "%20s : %10u\n", "SKBs dropped",
priv->debug.tx_stats.skb_dropped); priv->debug.tx_stats.skb_dropped);
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "CAB queued",
priv->debug.tx_stats.cab_queued);
len += snprintf(buf + len, sizeof(buf) - len, len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "BE queued", "%20s : %10u\n", "BE queued",
...@@ -1054,7 +1057,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ...@@ -1054,7 +1057,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
memmove(skb->data, skb->data + padsize, padpos); 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 != 0) {
if (ret == -ENOMEM) { if (ret == -ENOMEM) {
ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
......
...@@ -79,7 +79,8 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, ...@@ -79,7 +79,8 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
return error; 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_hdr *hdr;
struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt;
...@@ -170,6 +171,12 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) ...@@ -170,6 +171,12 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
tx_fhdr = skb_push(skb, sizeof(tx_hdr)); tx_fhdr = skb_push(skb, sizeof(tx_hdr));
memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
if (is_cab) {
CAB_STAT_INC;
epid = priv->cab_ep;
goto send;
}
qnum = skb_get_queue_mapping(skb); qnum = skb_get_queue_mapping(skb);
switch (qnum) { switch (qnum) {
...@@ -222,7 +229,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) ...@@ -222,7 +229,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
epid = priv->mgmt_ep; epid = priv->mgmt_ep;
} }
send:
return htc_send(priv->htc, skb, epid, &tx_ctl); return htc_send(priv->htc, skb, epid, &tx_ctl);
} }
...@@ -326,7 +333,8 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, ...@@ -326,7 +333,8 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
} else if ((ep_id == priv->data_bk_ep) || } else if ((ep_id == priv->data_bk_ep) ||
(ep_id == priv->data_be_ep) || (ep_id == priv->data_be_ep) ||
(ep_id == priv->data_vi_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)); skb_pull(skb, sizeof(struct tx_frame_hdr));
} else { } else {
ath_err(common, "Unsupported TX EPID: %d\n", ep_id); ath_err(common, "Unsupported TX EPID: %d\n", ep_id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment