Merge tag 'staging-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-microblaze.git] / drivers / staging / wfx / queue.c
index 680fed3..0bcc61f 100644 (file)
@@ -31,8 +31,6 @@ void wfx_tx_flush(struct wfx_dev *wdev)
 {
        int ret;
 
-       WARN(!atomic_read(&wdev->tx_lock), "tx_lock is not locked");
-
        // Do not wait for any reply if chip is frozen
        if (wdev->chip_frozen)
                return;
@@ -177,11 +175,9 @@ void wfx_tx_queues_deinit(struct wfx_dev *wdev)
        wfx_tx_queues_clear(wdev);
 }
 
-size_t wfx_tx_queue_get_num_queued(struct wfx_queue *queue,
-                                  u32 link_id_map)
+int wfx_tx_queue_get_num_queued(struct wfx_queue *queue, u32 link_id_map)
 {
-       size_t ret;
-       int i, bit;
+       int ret, i;
 
        if (!link_id_map)
                return 0;
@@ -191,11 +187,9 @@ size_t wfx_tx_queue_get_num_queued(struct wfx_queue *queue,
                ret = skb_queue_len(&queue->queue);
        } else {
                ret = 0;
-               for (i = 0, bit = 1; i < ARRAY_SIZE(queue->link_map_cache);
-                    ++i, bit <<= 1) {
-                       if (link_id_map & bit)
+               for (i = 0; i < ARRAY_SIZE(queue->link_map_cache); i++)
+                       if (link_id_map & BIT(i))
                                ret += queue->link_map_cache[i];
-               }
        }
        spin_unlock_bh(&queue->queue.lock);
        return ret;
@@ -237,7 +231,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();
@@ -362,80 +355,38 @@ bool wfx_tx_queues_is_empty(struct wfx_dev *wdev)
 static bool hif_handle_tx_data(struct wfx_vif *wvif, struct sk_buff *skb,
                               struct wfx_queue *queue)
 {
-       bool handled = false;
-       struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb);
        struct hif_req_tx *req = wfx_skb_txreq(skb);
-       struct ieee80211_hdr *frame = (struct ieee80211_hdr *) (req->frame + req->data_flags.fc_offset);
-
-       enum {
-               do_probe,
-               do_drop,
-               do_wep,
-               do_tx,
-       } action = do_tx;
-
-       switch (wvif->vif->type) {
-       case NL80211_IFTYPE_STATION:
-               if (wvif->state < WFX_STATE_PRE_STA)
-                       action = do_drop;
-               break;
-       case NL80211_IFTYPE_AP:
-               if (!wvif->state) {
-                       action = do_drop;
-               } else if (!(BIT(tx_priv->raw_link_id) &
-                            (BIT(0) | wvif->link_id_map))) {
-                       dev_warn(wvif->wdev->dev, "a frame with expired link-id is dropped\n");
-                       action = do_drop;
-               }
-               break;
-       case NL80211_IFTYPE_ADHOC:
-               if (wvif->state != WFX_STATE_IBSS)
-                       action = do_drop;
-               break;
-       case NL80211_IFTYPE_MONITOR:
-       default:
-               action = do_drop;
-               break;
-       }
-
-       if (action == do_tx) {
-               if (ieee80211_is_nullfunc(frame->frame_control)) {
-                       mutex_lock(&wvif->bss_loss_lock);
-                       if (wvif->bss_loss_state) {
-                               wvif->bss_loss_confirm_id = req->packet_id;
-                               req->queue_id.queue_id = HIF_QUEUE_ID_VOICE;
-                       }
-                       mutex_unlock(&wvif->bss_loss_lock);
-               } else if (ieee80211_has_protected(frame->frame_control) &&
-                          tx_priv->hw_key &&
-                          tx_priv->hw_key->keyidx != wvif->wep_default_key_id &&
-                          (tx_priv->hw_key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-                           tx_priv->hw_key->cipher == WLAN_CIPHER_SUITE_WEP104)) {
-                       action = do_wep;
+       struct ieee80211_key_conf *hw_key = wfx_skb_tx_priv(skb)->hw_key;
+       struct ieee80211_hdr *frame =
+               (struct ieee80211_hdr *)(req->frame + req->data_flags.fc_offset);
+
+       // FIXME: mac80211 is smart enough to handle BSS loss. Driver should not
+       // try to do anything about that.
+       if (ieee80211_is_nullfunc(frame->frame_control)) {
+               mutex_lock(&wvif->bss_loss_lock);
+               if (wvif->bss_loss_state) {
+                       wvif->bss_loss_confirm_id = req->packet_id;
+                       req->queue_id.queue_id = HIF_QUEUE_ID_VOICE;
                }
+               mutex_unlock(&wvif->bss_loss_lock);
        }
 
-       switch (action) {
-       case do_drop:
-               wfx_pending_remove(wvif->wdev, skb);
-               handled = true;
-               break;
-       case do_wep:
+       // FIXME: identify the exact scenario matched by this condition. Does it
+       // happen yet?
+       if (ieee80211_has_protected(frame->frame_control) &&
+           hw_key && hw_key->keyidx != wvif->wep_default_key_id &&
+           (hw_key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            hw_key->cipher == WLAN_CIPHER_SUITE_WEP104)) {
                wfx_tx_lock(wvif->wdev);
                WARN_ON(wvif->wep_pending_skb);
-               wvif->wep_default_key_id = tx_priv->hw_key->keyidx;
+               wvif->wep_default_key_id = hw_key->keyidx;
                wvif->wep_pending_skb = skb;
                if (!schedule_work(&wvif->wep_key_work))
                        wfx_tx_unlock(wvif->wdev);
-               handled = true;
-               break;
-       case do_tx:
-               break;
-       default:
-               /* Do nothing */
-               break;
+               return true;
+       } else {
+               return false;
        }
-       return handled;
 }
 
 static int wfx_get_prio_queue(struct wfx_vif *wvif,
@@ -443,7 +394,7 @@ static int wfx_get_prio_queue(struct wfx_vif *wvif,
 {
        static const int urgent = BIT(WFX_LINK_ID_AFTER_DTIM) |
                BIT(WFX_LINK_ID_UAPSD);
-       struct hif_req_edca_queue_params *edca;
+       const struct ieee80211_tx_queue_params *edca;
        unsigned int score, best = -1;
        int winner = -1;
        int i;
@@ -452,13 +403,13 @@ static int wfx_get_prio_queue(struct wfx_vif *wvif,
        for (i = 0; i < IEEE80211_NUM_ACS; ++i) {
                int queued;
 
-               edca = &wvif->edca.params[i];
+               edca = &wvif->edca_params[i];
                queued = wfx_tx_queue_get_num_queued(&wvif->wdev->tx_queue[i],
                                tx_allowed_mask);
                if (!queued)
                        continue;
                *total += queued;
-               score = ((edca->aifsn + edca->cw_min) << 16) +
+               score = ((edca->aifs + edca->cw_min) << 16) +
                        ((edca->cw_max - edca->cw_min) *
                         (get_random_int() & 0xFFFF));
                if (score < best && (winner < 0 || i != 3)) {
@@ -480,94 +431,100 @@ 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);
-       if (wvif->sta_asleep_mask) {
-               tx_allowed_mask |= wvif->pspoll_mask;
+       if (wvif->sta_asleep_mask)
                tx_allowed_mask &= ~BIT(WFX_LINK_ID_AFTER_DTIM);
-       } else {
+       else
                tx_allowed_mask |= BIT(WFX_LINK_ID_AFTER_DTIM);
-       }
        idx = wfx_get_prio_queue(wvif, tx_allowed_mask, &total);
        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;
@@ -592,11 +549,9 @@ struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev)
                if (hif_handle_tx_data(wvif, skb, queue))
                        continue;  /* Handled by WSM */
 
-               wvif->pspoll_mask &= ~BIT(tx_priv->raw_link_id);
-
                /* allow bursting if txop is set */
-               if (wvif->edca.params[queue_num].tx_op_limit)
-                       burst = (int)wfx_tx_queue_get_num_queued(queue, tx_allowed_mask) + 1;
+               if (wvif->edca_params[queue_num].txop)
+                       burst = wfx_tx_queue_get_num_queued(queue, tx_allowed_mask) + 1;
                else
                        burst = 1;
 
@@ -606,15 +561,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;
        }
 }