From: Johannes Berg <[email protected]>

Signed-off-by: Johannes Berg <[email protected]>
---
 drivers/net/wireless/mac80211_hwsim.c |  1 +
 include/net/mac80211.h                |  6 ++-
 net/mac80211/debugfs.c                |  2 +-
 net/mac80211/debugfs_netdev.c         |  2 +-
 net/mac80211/debugfs_sta.c            |  2 +-
 net/mac80211/ieee80211_i.h            |  2 +
 net/mac80211/iface.c                  | 17 +++----
 net/mac80211/main.c                   |  8 ++++
 net/mac80211/sta_info.c               |  3 --
 net/mac80211/tx.c                     | 83 +++++++++++++++++++----------------
 net/mac80211/util.c                   |  4 +-
 11 files changed, 71 insertions(+), 59 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index c8852acc1462..1f11c5ccc880 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2299,6 +2299,7 @@ static void mac80211_hwsim_get_et_stats(struct 
ieee80211_hw *hw,
 
 #define HWSIM_COMMON_OPS                                       \
        .tx = mac80211_hwsim_tx,                                \
+       .wake_tx_queue = ieee80211_wake_tx_queue,               \
        .start = mac80211_hwsim_start,                          \
        .stop = mac80211_hwsim_stop,                            \
        .add_interface = mac80211_hwsim_add_interface,          \
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index f2c6f0e0f928..3fc92c0e8779 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -97,7 +97,8 @@
  * Other frames (e.g. control or management) are still pushed using drv_tx().
  *
  * Drivers indicate that they use this model by implementing the .wake_tx_queue
- * driver operation.
+ * driver operation; if they don't want to use this model they need to set the
+ * .wake_tx_queue operation to point to ieee80211_wake_tx_queue().
  *
  * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with
  * another per-sta for non-data/non-mgmt and bufferable management frames, and
@@ -5867,6 +5868,9 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, 
u8 tid);
 struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
                                     struct ieee80211_txq *txq);
 
+void ieee80211_wake_tx_queue(struct ieee80211_hw *hw,
+                            struct ieee80211_txq *txq);
+
 /**
  * ieee80211_txq_get_depth - get pending frame/byte count of given txq
  *
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 5fae001f286c..9ab432bde8b4 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -373,7 +373,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_ADD(user_power);
        DEBUGFS_ADD(power);
 
-       if (local->ops->wake_tx_queue)
+       if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
                DEBUGFS_ADD_MODE(aqm, 0600);
 
        statsd = debugfs_create_dir("statistics", phyd);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index c813207bb123..2098767353ac 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -659,7 +659,7 @@ static void add_common_files(struct ieee80211_sub_if_data 
*sdata)
        DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
        DEBUGFS_ADD(hw_queues);
 
-       if (sdata->local->ops->wake_tx_queue)
+       if (sdata->local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
                DEBUGFS_ADD(aqm);
 }
 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index d046c17ea48d..80194f82f6a9 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -539,7 +539,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments);
        DEBUGFS_ADD_COUNTER(tx_filtered, status_stats.filtered);
 
-       if (local->ops->wake_tx_queue)
+       if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
                DEBUGFS_ADD(aqm);
 
        if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 011c18077e21..3413a1f6408e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -815,6 +815,8 @@ enum txq_info_flags {
        IEEE80211_TXQ_STOP,
        IEEE80211_TXQ_AMPDU,
        IEEE80211_TXQ_NO_AMSDU,
+       IEEE80211_TXQ_PENDING,
+       IEEE80211_TXQ_RESULT,
 };
 
 /**
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 492cc65b9871..b2545899bc6b 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -729,7 +729,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool 
coming_up)
 
        if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-           local->ops->wake_tx_queue) {
+           local->ops->wake_tx_queue != ieee80211_wake_tx_queue) {
                /* XXX: for AP_VLAN, actually track AP queues */
                netif_tx_start_all_queues(dev);
        } else if (dev) {
@@ -1756,13 +1756,10 @@ int ieee80211_if_add(struct ieee80211_local *local, 
const char *name,
        } else {
                int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
                                 sizeof(void *));
-               int txq_size = 0;
+               int txq_size = sizeof(struct txq_info) +
+                              local->hw.txq_data_size;
 
-               if (local->ops->wake_tx_queue)
-                       txq_size += sizeof(struct txq_info) +
-                                   local->hw.txq_data_size;
-
-               if (local->ops->wake_tx_queue)
+               if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
                        if_setup = ieee80211_if_setup_no_queue;
                else
                        if_setup = ieee80211_if_setup;
@@ -1812,10 +1809,8 @@ int ieee80211_if_add(struct ieee80211_local *local, 
const char *name,
                memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN);
                memcpy(sdata->name, ndev->name, IFNAMSIZ);
 
-               if (txq_size) {
-                       txqi = netdev_priv(ndev) + size;
-                       ieee80211_txq_init(local, sdata, NULL, txqi, 0);
-               }
+               txqi = netdev_priv(ndev) + size;
+               ieee80211_txq_init(local, sdata, NULL, txqi, 0);
 
                sdata->dev = ndev;
        }
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8c33c07e47a5..8eaac8e29bb4 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -508,6 +508,9 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t 
priv_data_len,
                return NULL;
        use_chanctx = i == 5;
 
+       if (WARN_ON(!ops->wake_tx_queue))
+               return NULL;
+
        /* Ensure 32-byte alignment of our private data and hw private data.
         * We use the wiphy priv data for both our ieee80211_local and for
         * the driver's private data
@@ -849,6 +852,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                return -EINVAL;
 #endif
 
+       if (local->ops->wake_tx_queue == ieee80211_wake_tx_queue) {
+               if (WARN_ON(local->hw.txq_data_size))
+                       return -EINVAL;
+       }
+
        if (!local->use_chanctx) {
                for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
                        const struct ieee80211_iface_combination *comb;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index e99da54c2270..c1c73125bcd9 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2319,9 +2319,6 @@ unsigned long ieee80211_sta_last_active(struct sta_info 
*sta)
 
 static void sta_update_codel_params(struct sta_info *sta, u32 thr)
 {
-       if (!sta->sdata->local->ops->wake_tx_queue)
-               return;
-
        if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) {
                sta->cparams.target = MS2TIME(50);
                sta->cparams.interval = MS2TIME(300);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index ce78ac4d781e..7f8b8cb60109 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1248,7 +1248,8 @@ static struct txq_info *ieee80211_get_txq(struct 
ieee80211_local *local,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_txq *txq;
 
-       if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
+       if (vif->type == NL80211_IFTYPE_MONITOR ||
+           (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
            (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) {
                txq = NULL;
        } else if (!ieee80211_is_data_present(hdr->frame_control)) {
@@ -1448,9 +1449,6 @@ int ieee80211_txq_setup_flows(struct ieee80211_local 
*local)
        bool supp_vht = false;
        enum nl80211_band band;
 
-       if (!local->ops->wake_tx_queue)
-               return 0;
-
        ret = fq_init(fq, 4096);
        if (ret)
                return ret;
@@ -1496,9 +1494,6 @@ void ieee80211_txq_teardown_flows(struct ieee80211_local 
*local)
 {
        struct fq *fq = &local->fq;
 
-       if (!local->ops->wake_tx_queue)
-               return;
-
        kfree(local->cvars);
        local->cvars = NULL;
 
@@ -1509,17 +1504,13 @@ void ieee80211_txq_teardown_flows(struct 
ieee80211_local *local)
 
 static bool ieee80211_queue_skb(struct ieee80211_local *local,
                                struct ieee80211_sub_if_data *sdata,
-                               struct sta_info *sta,
-                               struct sk_buff *skb)
+                               struct sta_info *sta, struct sk_buff *skb,
+                               bool txpending)
 {
        struct fq *fq = &local->fq;
        struct ieee80211_vif *vif;
        struct txq_info *txqi;
 
-       if (!local->ops->wake_tx_queue ||
-           sdata->vif.type == NL80211_IFTYPE_MONITOR)
-               return false;
-
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                sdata = container_of(sdata->bss,
                                     struct ieee80211_sub_if_data, u.ap);
@@ -1527,16 +1518,23 @@ static bool ieee80211_queue_skb(struct ieee80211_local 
*local,
        vif = &sdata->vif;
        txqi = ieee80211_get_txq(local, vif, sta, skb);
 
-       if (WARN_ON(!txqi))
-               return false;
+       if (WARN_ON(!txqi)) {
+               ieee80211_free_txskb(&local->hw, skb);
+               return true;
+       }
 
        spin_lock_bh(&fq->lock);
        ieee80211_txq_enqueue(local, txqi, skb);
        spin_unlock_bh(&fq->lock);
 
+       if (txpending)
+               set_bit(IEEE80211_TXQ_PENDING, &txqi->flags);
+       else
+               clear_bit(IEEE80211_TXQ_PENDING, &txqi->flags);
+       set_bit(IEEE80211_TXQ_RESULT, &txqi->flags);
        drv_wake_tx_queue(local, txqi);
-
-       return true;
+       clear_bit(IEEE80211_TXQ_PENDING, &txqi->flags);
+       return test_bit(IEEE80211_TXQ_RESULT, &txqi->flags);
 }
 
 static bool ieee80211_tx_frags(struct ieee80211_local *local,
@@ -1820,8 +1818,6 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data 
*sdata,
        struct ieee80211_tx_data tx;
        ieee80211_tx_result res_prepare;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       bool result = true;
-       int led_len;
 
        if (unlikely(skb->len < 10)) {
                dev_kfree_skb(skb);
@@ -1829,7 +1825,6 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data 
*sdata,
        }
 
        /* initialises tx */
-       led_len = skb->len;
        res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
 
        if (unlikely(res_prepare == TX_DROP)) {
@@ -1848,14 +1843,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data 
*sdata,
        if (invoke_tx_handlers_early(&tx))
                return false;
 
-       if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb))
-               return true;
-
-       if (!invoke_tx_handlers_late(&tx))
-               result = __ieee80211_tx(local, &tx.skbs, led_len,
-                                       tx.sta, txpending);
-
-       return result;
+       return ieee80211_queue_skb(local, sdata, tx.sta, tx.skb, txpending);
 }
 
 /* device xmit handlers */
@@ -3300,6 +3288,8 @@ static bool ieee80211_xmit_fast(struct 
ieee80211_sub_if_data *sdata,
        struct tid_ampdu_tx *tid_tx = NULL;
        u8 tid = IEEE80211_NUM_TIDS;
 
+       return false;
+
        /* control port protocol needs a lot of special handling */
        if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
                return false;
@@ -3392,18 +3382,8 @@ static bool ieee80211_xmit_fast(struct 
ieee80211_sub_if_data *sdata,
                }
        }
 
-       if (ieee80211_queue_skb(local, sdata, sta, skb))
-               return true;
-
-       ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
-                                  fast_tx->key, skb);
-
-       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               sdata = container_of(sdata->bss,
-                                    struct ieee80211_sub_if_data, u.ap);
+       ieee80211_queue_skb(local, sdata, sta, skb, false);
 
-       __skb_queue_tail(&tx.skbs, skb);
-       ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
        return true;
 }
 
@@ -4704,3 +4684,28 @@ void __ieee80211_tx_skb_tid_band(struct 
ieee80211_sub_if_data *sdata,
        ieee80211_xmit(sdata, NULL, skb);
        local_bh_enable();
 }
+
+void ieee80211_wake_tx_queue(struct ieee80211_hw *hw,
+                            struct ieee80211_txq *txq)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct txq_info *txqi = container_of(txq, struct txq_info, txq);
+       struct sk_buff *skb;
+       struct sk_buff_head skbs;
+       struct sta_info *sta = NULL;
+
+       if (txq->sta)
+               sta = container_of(txq->sta, struct sta_info, sta);
+
+       while ((skb = ieee80211_tx_dequeue(hw, txq))) {
+               __skb_queue_head_init(&skbs);
+               __skb_queue_head(&skbs, skb);
+               skb_queue_splice_tail_init(&txqi->frags, &skbs);
+
+               /* use approximate length for fragmented frames for LED 
blinking */
+               if (!__ieee80211_tx(local, &skbs, skbs.qlen * skb->len, sta,
+                                   test_bit(IEEE80211_TXQ_PENDING, 
&txqi->flags)))
+                       clear_bit(IEEE80211_TXQ_RESULT, &txqi->flags);
+       }
+}
+EXPORT_SYMBOL_GPL(ieee80211_wake_tx_queue);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 259698de569f..ed2dba05f340 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -244,7 +244,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local 
*local, int queue)
        struct ieee80211_sub_if_data *sdata;
        int n_acs = IEEE80211_NUM_ACS;
 
-       if (local->ops->wake_tx_queue)
+       if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
                return;
 
        if (local->hw.queues < IEEE80211_NUM_ACS)
@@ -350,7 +350,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, 
int queue,
        if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
                return;
 
-       if (local->ops->wake_tx_queue)
+       if (local->ops->wake_tx_queue != ieee80211_wake_tx_queue)
                return;
 
        if (local->hw.queues < IEEE80211_NUM_ACS)
-- 
2.11.0

Reply via email to