summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartosz Markowski <bartosz.markowski@tieto.com>2011-09-27 08:34:33 +0200
committerPhilippe LANGLAIS <philippe.langlais@stericsson.com>2011-10-13 10:19:11 +0200
commit5e666fdc2c0bf1fc6157ca6b66a6b5af809b9d2b (patch)
treef0e73f8a78ae8df11e9901f85b23e8ecf9877e6d
parent4716cbebb6bb0f839605f68bdec0f1558d69a728 (diff)
cw1200: Adaptation to U-APSD/AP support as on Thu, Sep 22, 2011
New mac80211 API for reporting buffered frames in SoftAP mode is supported. SoftAP stability is significantly improved by that. ST-Ericsson ID: 355584 Change-Id: I0f12c71fff05f7f6b79cd508181b7daab6838c7e Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31927 Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Tested-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33530 Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
-rwxr-xr-xdrivers/staging/cw1200/ap.c25
-rw-r--r--drivers/staging/cw1200/cw1200.h3
-rw-r--r--drivers/staging/cw1200/main.c3
-rw-r--r--drivers/staging/cw1200/queue.c9
-rw-r--r--drivers/staging/cw1200/queue.h5
-rw-r--r--drivers/staging/cw1200/txrx.c64
-rw-r--r--drivers/staging/cw1200/txrx.h2
-rw-r--r--drivers/staging/cw1200/wsm.c8
8 files changed, 78 insertions, 41 deletions
diff --git a/drivers/staging/cw1200/ap.c b/drivers/staging/cw1200/ap.c
index aabca5ca06e..f35eef5fae6 100755
--- a/drivers/staging/cw1200/ap.c
+++ b/drivers/staging/cw1200/ap.c
@@ -84,30 +84,6 @@ void cw1200_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
enum sta_notify_cmd notify_cmd,
struct ieee80211_sta *sta)
{
- struct cw1200_common *priv = dev->priv;
- struct cw1200_sta_priv *sta_priv =
- (struct cw1200_sta_priv *)&sta->drv_priv;
- u32 bit = BIT(sta_priv->link_id);
-
- spin_lock_bh(&priv->buffered_multicasts_lock);
- switch (notify_cmd) {
- case STA_NOTIFY_SLEEP:
- if (priv->buffered_multicasts &&
- !priv->sta_asleep_mask)
- queue_work(priv->workqueue,
- &priv->multicast_start_work);
- priv->sta_asleep_mask |= bit;
- break;
- case STA_NOTIFY_AWAKE:
- priv->sta_asleep_mask &= ~bit;
- if (priv->tx_multicast &&
- !priv->sta_asleep_mask)
- queue_work(priv->workqueue,
- &priv->multicast_stop_work);
- cw1200_bh_wakeup(priv);
- break;
- }
- spin_unlock_bh(&priv->buffered_multicasts_lock);
}
static void __cw1200_ps_notify(struct cw1200_common *priv,
@@ -901,6 +877,7 @@ int cw1200_alloc_link_id(struct cw1200_common *priv, const u8 *mac)
ret);
priv->link_id_db[ret - 1].status = CW1200_LINK_RESERVE;
memcpy(&priv->link_id_db[ret - 1].mac, mac, ETH_ALEN);
+ memset(&priv->link_id_db[ret - 1].buffered, 0, CW1200_MAX_TID);
wsm_lock_tx_async(priv);
if (queue_work(priv->workqueue, &priv->link_id_work) <= 0)
wsm_unlock_tx(priv);
diff --git a/drivers/staging/cw1200/cw1200.h b/drivers/staging/cw1200/cw1200.h
index 24bf929e4a3..90df67952f5 100644
--- a/drivers/staging/cw1200/cw1200.h
+++ b/drivers/staging/cw1200/cw1200.h
@@ -50,6 +50,8 @@
#define CW1200_LINK_ID_MAX (CW1200_MAX_STA_IN_AP_MODE + 3)
#define CW1200_MAX_REQUEUE_ATTEMPTS (5)
+#define CW1200_MAX_TID (8)
+
/* Please keep order */
enum cw1200_join_status {
CW1200_JOIN_STATUS_PASSIVE = 0,
@@ -69,6 +71,7 @@ struct cw1200_link_entry {
unsigned long timestamp;
enum cw1200_link_status status;
u8 mac[ETH_ALEN];
+ u8 buffered[CW1200_MAX_TID];
bool ps;
};
diff --git a/drivers/staging/cw1200/main.c b/drivers/staging/cw1200/main.c
index d8e4ecf1af4..a931a059f6f 100644
--- a/drivers/staging/cw1200/main.c
+++ b/drivers/staging/cw1200/main.c
@@ -251,7 +251,6 @@ struct ieee80211_hw *cw1200_init_common(size_t priv_data_len)
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_AP_LINK_PS |
IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_SUPPORTS_CQM_RSSI |
@@ -277,7 +276,7 @@ struct ieee80211_hw *cw1200_init_common(size_t priv_data_len)
WIPHY_WOWLAN_DISCONNECT;
hw->wiphy->wowlan.n_patterns = 0;
- hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_UAPSD;
+ hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
hw->channel_change_time = 1000; /* TODO: find actual value */
/* priv->beacon_req_id = cpu_to_le32(0); */
diff --git a/drivers/staging/cw1200/queue.c b/drivers/staging/cw1200/queue.c
index 2ba26f32178..ef7d48488bd 100644
--- a/drivers/staging/cw1200/queue.c
+++ b/drivers/staging/cw1200/queue.c
@@ -29,7 +29,7 @@
u8 generation;
u8 link_id;
u8 raw_link_id;
- u8 reserved[1];
+ u8 tid;
};
static inline void __cw1200_queue_lock(struct cw1200_queue *queue,
@@ -200,7 +200,8 @@ size_t cw1200_queue_get_num_queued(struct cw1200_queue *queue,
}
int cw1200_queue_put(struct cw1200_queue *queue, struct cw1200_common *priv,
- struct sk_buff *skb, struct tx_info *txinfo, u8 raw_link_id)
+ struct sk_buff *skb, struct tx_info *txinfo,
+ u8 raw_link_id, u8 tid)
{
int ret;
struct wsm_tx *wsm;
@@ -230,6 +231,7 @@ int cw1200_queue_put(struct cw1200_queue *queue, struct cw1200_common *priv,
wsm->packetID = __cpu_to_le32(item->packetID);
item->link_id = link_id;
item->raw_link_id = raw_link_id;
+ item->tid = tid;
++queue->num_queued;
++queue->link_map_cache[link_id];
@@ -409,7 +411,7 @@ int cw1200_queue_remove(struct cw1200_queue *queue, struct cw1200_common *priv,
}
int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packetID,
- struct sk_buff **skb)
+ struct sk_buff **skb, int *tid)
{
int ret = 0;
u8 queue_generation, queue_id, item_generation, item_id;
@@ -431,6 +433,7 @@ int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packetID,
ret = -ENOENT;
} else {
*skb = item->skb;
+ *tid = item->tid;
item->skb = NULL;
}
spin_unlock_bh(&queue->lock);
diff --git a/drivers/staging/cw1200/queue.h b/drivers/staging/cw1200/queue.h
index 3ddfdaf910e..d1802c36f02 100644
--- a/drivers/staging/cw1200/queue.h
+++ b/drivers/staging/cw1200/queue.h
@@ -61,7 +61,8 @@ void cw1200_queue_deinit(struct cw1200_queue *queue);
size_t cw1200_queue_get_num_queued(struct cw1200_queue *queue,
u32 link_id_map);
int cw1200_queue_put(struct cw1200_queue *queue, struct cw1200_common *cw1200,
- struct sk_buff *skb, struct tx_info *txinfo, u8 raw_link_id);
+ struct sk_buff *skb, struct tx_info *txinfo,
+ u8 raw_link_id, u8 tid);
int cw1200_queue_get(struct cw1200_queue *queue,
u32 link_id_map,
struct wsm_tx **tx,
@@ -72,7 +73,7 @@ int cw1200_queue_requeue_all(struct cw1200_queue *queue);
int cw1200_queue_remove(struct cw1200_queue *queue, struct cw1200_common *priv,
u32 packetID);
int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packetID,
- struct sk_buff **skb);
+ struct sk_buff **skb, int *tid);
void cw1200_queue_lock(struct cw1200_queue *queue,
struct cw1200_common *cw1200);
void cw1200_queue_unlock(struct cw1200_queue *queue,
diff --git a/drivers/staging/cw1200/txrx.c b/drivers/staging/cw1200/txrx.c
index 5cd1857dd17..ef871325eee 100644
--- a/drivers/staging/cw1200/txrx.c
+++ b/drivers/staging/cw1200/txrx.c
@@ -448,6 +448,8 @@ void cw1200_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr =
(struct ieee80211_hdr *)skb->data;
+ int was_buffered = 0;
+ int tid = CW1200_MAX_TID;
const u8 *da = ieee80211_get_DA(hdr);
struct cw1200_sta_priv *sta_priv =
(struct cw1200_sta_priv *)&tx_info->control.sta->drv_priv;
@@ -477,15 +479,15 @@ void cw1200_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
__func__);
goto err;
}
- if (tx_info->control.sta &&
- (tx_info->control.sta->uapsd_queues & BIT(queue)))
- link_id = CW1200_LINK_ID_UAPSD;
- else
- link_id = raw_link_id;
+ link_id = raw_link_id;
}
if (raw_link_id)
priv->link_id_db[raw_link_id - 1].timestamp = jiffies;
+ if (tx_info->control.sta &&
+ (tx_info->control.sta->uapsd_queues & BIT(queue)))
+ link_id = CW1200_LINK_ID_UAPSD;
+
txrx_printk(KERN_DEBUG "[TX] TX %d bytes (queue: %d, link_id: %d (%d)).\n",
skb->len, queue, link_id, raw_link_id);
@@ -498,6 +500,13 @@ void cw1200_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
for (i = 0; i < 4; ++i)
priv->tx_suspend_mask[i] &= ~BIT(raw_link_id);
spin_unlock_bh(&priv->buffered_multicasts_lock);
+ } else if (ieee80211_is_data_qos(hdr->frame_control) ||
+ ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+ u8 *qos = ieee80211_get_qos_ctl(hdr);
+ tid = qos[0] & IEEE80211_QOS_CTL_TID_MASK;
+ } else if (ieee80211_is_data(hdr->frame_control) ||
+ ieee80211_is_nullfunc(hdr->frame_control)) {
+ tid = 0;
}
/* BT Coex support related configuration */
@@ -613,10 +622,19 @@ void cw1200_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
}
txinfo.link_id = link_id;
+
+ if (raw_link_id && tid < CW1200_MAX_TID)
+ was_buffered = priv->link_id_db[raw_link_id - 1]
+ .buffered[tid]++;
+
ret = cw1200_queue_put(&priv->tx_queue[queue], priv, skb,
- &txinfo, raw_link_id);
+ &txinfo, raw_link_id, tid);
+
spin_unlock_bh(&priv->buffered_multicasts_lock);
+ if (raw_link_id && !was_buffered && tid < CW1200_MAX_TID)
+ ieee80211_sta_set_buffered(tx_info->control.sta, tid, true);
+
if (!WARN_ON(ret))
cw1200_bh_wakeup(priv);
else
@@ -721,6 +739,7 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
u8 queue_id = cw1200_queue_get_queue_id(arg->packetID);
struct cw1200_queue *queue = &priv->tx_queue[queue_id];
struct sk_buff *skb;
+ int tid = CW1200_MAX_TID;
txrx_printk(KERN_DEBUG "[TX] TX confirm.\n");
@@ -750,7 +769,7 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
WARN_ON(cw1200_queue_requeue(queue,
arg->packetID));
} else if (!WARN_ON(cw1200_queue_get_skb(
- queue, arg->packetID, &skb))) {
+ queue, arg->packetID, &skb, &tid))) {
struct ieee80211_tx_info *tx = IEEE80211_SKB_CB(skb);
struct wsm_tx *wsm_tx = (struct wsm_tx *)skb->data;
int rate_id = (wsm_tx->flags >> 4) & 0x07;
@@ -802,12 +821,41 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
}
skb_pull(skb, sizeof(struct wsm_tx));
+ cw1200_notify_buffered_tx(priv, skb, arg->link_id, tid);
ieee80211_tx_status(priv->hw, skb);
-
WARN_ON(cw1200_queue_remove(queue, priv, arg->packetID));
}
}
+void cw1200_notify_buffered_tx(struct cw1200_common *priv,
+ struct sk_buff *skb, int link_id, int tid)
+{
+ struct ieee80211_sta *sta;
+ struct ieee80211_hdr *hdr;
+ u8 *buffered;
+ u8 still_buffered = 0;
+
+ if (link_id && tid < CW1200_MAX_TID) {
+ buffered = priv->link_id_db
+ [link_id - 1].buffered;
+
+ spin_lock_bh(&priv->buffered_multicasts_lock);
+ if (!WARN_ON(!buffered[tid]))
+ still_buffered = --buffered[tid];
+ spin_unlock_bh(&priv->buffered_multicasts_lock);
+
+ if (!still_buffered && tid < CW1200_MAX_TID) {
+ hdr = (struct ieee80211_hdr *) skb->data;
+ rcu_read_lock();
+ sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+ if (sta)
+ ieee80211_sta_set_buffered(sta, tid, false);
+ rcu_read_unlock();
+ }
+ }
+
+}
+
void cw1200_rx_cb(struct cw1200_common *priv,
struct wsm_rx *arg,
struct sk_buff **skb_p)
diff --git a/drivers/staging/cw1200/txrx.h b/drivers/staging/cw1200/txrx.h
index e41ac43bc7f..4bf792f23a8 100644
--- a/drivers/staging/cw1200/txrx.h
+++ b/drivers/staging/cw1200/txrx.h
@@ -68,6 +68,8 @@ int cw1200_skb_to_wsm(struct cw1200_common *priv,
struct sk_buff *skb, struct wsm_tx *wsm,
struct tx_info *txinfo);
void cw1200_tx(struct ieee80211_hw *dev, struct sk_buff *skb);
+void cw1200_notify_buffered_tx(struct cw1200_common *priv,
+ struct sk_buff *skb, int link_id, int tid);
/* ******************************************************************** */
/* WSM callbacks */
diff --git a/drivers/staging/cw1200/wsm.c b/drivers/staging/cw1200/wsm.c
index b05548f34a8..69672992982 100644
--- a/drivers/staging/cw1200/wsm.c
+++ b/drivers/staging/cw1200/wsm.c
@@ -1395,6 +1395,7 @@ static bool wsm_handle_tx_data(struct cw1200_common *priv,
* probe responses.
* The easiest way to get it back is to convert
* probe request into WSM start_scan command. */
+ int tid;
int rate_id = (wsm->flags >> 4) & 0x07;
struct cw1200_queue *queue =
&priv->tx_queue[cw1200_queue_get_queue_id(
@@ -1405,7 +1406,7 @@ static bool wsm_handle_tx_data(struct cw1200_common *priv,
BUG_ON(priv->scan.probe_skb);
BUG_ON(cw1200_queue_get_skb(queue,
wsm->packetID,
- &priv->scan.probe_skb));
+ &priv->scan.probe_skb, &tid));
BUG_ON(cw1200_queue_remove(queue, priv,
wsm->packetID));
/* Release used TX rate policy */
@@ -1421,12 +1422,15 @@ static bool wsm_handle_tx_data(struct cw1200_common *priv,
* We are dropping everything except AUTH in non-joined mode. */
struct sk_buff *skb;
int rate_id = (wsm->flags >> 4) & 0x07;
+ int tid = 8;
struct cw1200_queue *queue =
&priv->tx_queue[cw1200_queue_get_queue_id(
wsm->packetID)];
wsm_printk(KERN_DEBUG "[WSM] Drop frame (0x%.4X):"
" not joined.\n", fctl);
- BUG_ON(cw1200_queue_get_skb(queue, wsm->packetID, &skb));
+ BUG_ON(cw1200_queue_get_skb(queue, wsm->packetID, &skb, &tid));
+ skb_pull(skb, sizeof(struct wsm_tx));
+ cw1200_notify_buffered_tx(priv, skb, link_id, tid);
BUG_ON(cw1200_queue_remove(queue, priv, wsm->packetID));
/* Release used TX rate policy */
tx_policy_put(priv, rate_id);