summaryrefslogtreecommitdiff
path: root/drivers/staging/wfx/queue.c
diff options
context:
space:
mode:
authorJérôme Pouiller <jerome.pouiller@silabs.com>2020-01-15 13:55:25 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-01-16 20:59:52 +0100
commita3c529a835890b0eecd324d9f0c37c67345f84e2 (patch)
tree6fe2feabcbb779233a3c2314d8d73abd781d3145 /drivers/staging/wfx/queue.c
parent22c03264e5a914966c93baa367d63eb77f60ebaf (diff)
staging: wfx: simplify handling of IEEE80211_TX_CTL_SEND_AFTER_DTIM
When mac80211 ask for a frame to be sent after a DTIM, driver should: 1. Update TIM with multicast bit set (using update_ie). This function can be called whenever. 2. Keep buffered all frames marked "after dtim" 3. When it receive a suspend_resume indication (see wfx_suspend_resume_mc()), send all the buffered frames. This indication is sent by the firmware 4ms before the dtim. 4. If one of the frames returns status "REQUEUE", it means that the DTIM period was ended before to be able to send the frame. 5. When all the buffered frames were sent or if DTIM period was ended, driver should update the TIM with multicast bit reset. All the mess with the asynchronous works can be dropped. Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com> Link: https://lore.kernel.org/r/20200115135338.14374-58-Jerome.Pouiller@silabs.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/wfx/queue.c')
-rw-r--r--drivers/staging/wfx/queue.c98
1 files changed, 48 insertions, 50 deletions
diff --git a/drivers/staging/wfx/queue.c b/drivers/staging/wfx/queue.c
index 42d64534c92c..ec11a63a2ff9 100644
--- a/drivers/staging/wfx/queue.c
+++ b/drivers/staging/wfx/queue.c
@@ -235,7 +235,6 @@ static struct sk_buff *wfx_tx_queue_get(struct wfx_dev *wdev,
break;
}
}
- WARN_ON(!skb);
if (skb) {
tx_priv = wfx_skb_tx_priv(skb);
tx_priv->xmit_timestamp = ktime_get();
@@ -473,23 +472,12 @@ static int wfx_get_prio_queue(struct wfx_vif *wvif,
static int wfx_tx_queue_mask_get(struct wfx_vif *wvif,
struct wfx_queue **queue_p,
- u32 *tx_allowed_mask_p,
- bool *more)
+ u32 *tx_allowed_mask_p)
{
int idx;
u32 tx_allowed_mask;
int total = 0;
- /* Search for a queue with multicast frames buffered */
- if (wvif->mcast_tx) {
- tx_allowed_mask = BIT(WFX_LINK_ID_AFTER_DTIM);
- idx = wfx_get_prio_queue(wvif, tx_allowed_mask, &total);
- if (idx >= 0) {
- *more = total > 1;
- goto found;
- }
- }
-
/* Search for unicast traffic */
tx_allowed_mask = ~wvif->sta_asleep_mask;
tx_allowed_mask |= BIT(WFX_LINK_ID_UAPSD);
@@ -501,64 +489,83 @@ static int wfx_tx_queue_mask_get(struct wfx_vif *wvif,
if (idx < 0)
return -ENOENT;
-found:
*queue_p = &wvif->wdev->tx_queue[idx];
*tx_allowed_mask_p = tx_allowed_mask;
return 0;
}
+struct hif_msg *wfx_tx_queues_get_after_dtim(struct wfx_vif *wvif)
+{
+ struct wfx_dev *wdev = wvif->wdev;
+ struct ieee80211_tx_info *tx_info;
+ struct hif_msg *hif;
+ struct sk_buff *skb;
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
+ skb_queue_walk(&wdev->tx_queue[i].queue, skb) {
+ tx_info = IEEE80211_SKB_CB(skb);
+ hif = (struct hif_msg *)skb->data;
+ if ((tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) &&
+ (hif->interface == wvif->id))
+ return (struct hif_msg *)skb->data;
+ }
+ }
+ return NULL;
+}
+
struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev)
{
struct sk_buff *skb;
struct hif_msg *hif = NULL;
- struct hif_req_tx *req = NULL;
struct wfx_queue *queue = NULL;
struct wfx_queue *vif_queue = NULL;
u32 tx_allowed_mask = 0;
u32 vif_tx_allowed_mask = 0;
const struct wfx_tx_priv *tx_priv = NULL;
struct wfx_vif *wvif;
- /* More is used only for broadcasts. */
- bool more = false;
- bool vif_more = false;
int not_found;
int burst;
+ int i;
+
+ if (atomic_read(&wdev->tx_lock))
+ return NULL;
+
+ wvif = NULL;
+ while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
+ if (wvif->after_dtim_tx_allowed) {
+ for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
+ skb = wfx_tx_queue_get(wvif->wdev,
+ &wdev->tx_queue[i],
+ BIT(WFX_LINK_ID_AFTER_DTIM));
+ if (skb) {
+ hif = (struct hif_msg *)skb->data;
+ // Cannot happen since only one vif can
+ // be AP at time
+ WARN_ON(wvif->id != hif->interface);
+ return hif;
+ }
+ }
+ // No more multicast to sent
+ wvif->after_dtim_tx_allowed = false;
+ schedule_work(&wvif->update_tim_work);
+ }
+ }
for (;;) {
int ret = -ENOENT;
int queue_num;
- struct ieee80211_hdr *hdr;
-
- if (atomic_read(&wdev->tx_lock))
- return NULL;
wvif = NULL;
while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
spin_lock_bh(&wvif->ps_state_lock);
not_found = wfx_tx_queue_mask_get(wvif, &vif_queue,
- &vif_tx_allowed_mask,
- &vif_more);
-
- if (wvif->mcast_buffered && (not_found || !vif_more) &&
- (wvif->mcast_tx ||
- !wvif->sta_asleep_mask)) {
- wvif->mcast_buffered = false;
- if (wvif->mcast_tx) {
- wvif->mcast_tx = false;
- schedule_work(&wvif->mcast_stop_work);
- }
- }
+ &vif_tx_allowed_mask);
spin_unlock_bh(&wvif->ps_state_lock);
- if (vif_more) {
- more = true;
- tx_allowed_mask = vif_tx_allowed_mask;
- queue = vif_queue;
- ret = 0;
- break;
- } else if (!not_found) {
+ if (!not_found) {
if (queue && queue != vif_queue)
dev_info(wdev->dev, "vifs disagree about queue priority\n");
tx_allowed_mask |= vif_tx_allowed_mask;
@@ -595,15 +602,6 @@ struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev)
else
wdev->tx_burst_idx = -1;
- /* more buffered multicast/broadcast frames
- * ==> set MoreData flag in IEEE 802.11 header
- * to inform PS STAs
- */
- if (more) {
- req = (struct hif_req_tx *) hif->body;
- hdr = (struct ieee80211_hdr *) (req->frame + req->data_flags.fc_offset);
- hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
- }
return hif;
}
}