From 5e666fdc2c0bf1fc6157ca6b66a6b5af809b9d2b Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Tue, 27 Sep 2011 08:34:33 +0200 Subject: 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 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/31927 Reviewed-by: Bartosz MARKOWSKI Tested-by: Bartosz MARKOWSKI Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33530 Reviewed-by: Philippe LANGLAIS --- drivers/staging/cw1200/ap.c | 25 +--------------- drivers/staging/cw1200/cw1200.h | 3 ++ drivers/staging/cw1200/main.c | 3 +- drivers/staging/cw1200/queue.c | 9 ++++-- drivers/staging/cw1200/queue.h | 5 ++-- drivers/staging/cw1200/txrx.c | 64 +++++++++++++++++++++++++++++++++++------ drivers/staging/cw1200/txrx.h | 2 ++ drivers/staging/cw1200/wsm.c | 8 ++++-- 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); -- cgit v1.2.3