mt76: mt76x02: split beaconing
authorMarkus Theil <markus.theil@tu-ilmenau.de>
Wed, 18 Dec 2019 16:07:50 +0000 (17:07 +0100)
committerFelix Fietkau <nbd@nbd.name>
Fri, 14 Feb 2020 09:06:01 +0000 (10:06 +0100)
Sending beacons to the hardware always happens in batches. In order to
speed up beacon processing on usb devices, this patch splits out common
code an calls it only once.

Beacons are sequentially written into the beacon memory area, by
tracking its usage with the dev->beacon_data_count. For MBSS support
and buffered traffic dev->beacon_data_count is used to create the bypass
mask.

The code is also adapted for the mmio part of the driver, but should not
have any performance implication there.

MBSS tests were performed with AVM AC860 USB NIC with temporary support
for 5 BSS'. Different combinations of active vifs were created and
brought up. Afterwards connection and data transfer was tested for the
announced BSS'.

Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt76x02.h
drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c

index 57665516d00e2719c2c7aaa2f6213fe3a6cddfff..23040c193ca54de6248b1b9dab249c0edcd37c5c 100644 (file)
@@ -98,8 +98,7 @@ struct mt76x02_dev {
 
        const struct mt76x02_beacon_ops *beacon_ops;
 
-       struct sk_buff *beacons[8];
-       u8 beacon_data_mask;
+       u8 beacon_data_count;
 
        u8 tbtt_count;
 
index 403866496640a995a7481cd0e2ff4905b5ebc374..c93e2e8749f02fb026de1702aedc0b2405e9fdff 100644 (file)
@@ -40,63 +40,22 @@ mt76x02_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb)
        return 0;
 }
 
-static int
-__mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx,
-                        struct sk_buff *skb)
+int mt76x02_mac_set_beacon(struct mt76x02_dev *dev,
+                          struct sk_buff *skb)
 {
-       int beacon_len = dev->beacon_ops->slot_size;
-       int beacon_addr = MT_BEACON_BASE + (beacon_len * bcn_idx);
+       int bcn_len = dev->beacon_ops->slot_size;
+       int bcn_addr = MT_BEACON_BASE + (bcn_len * dev->beacon_data_count);
        int ret = 0;
-       int i;
-
-       /* Prevent corrupt transmissions during update */
-       mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx));
 
        if (skb) {
-               ret = mt76x02_write_beacon(dev, beacon_addr, skb);
+               ret = mt76x02_write_beacon(dev, bcn_addr, skb);
                if (!ret)
-                       dev->beacon_data_mask |= BIT(bcn_idx);
-       } else {
-               dev->beacon_data_mask &= ~BIT(bcn_idx);
+                       dev->beacon_data_count++;
        }
 
-       mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask);
-
+       dev_kfree_skb(skb);
        return ret;
 }
-
-int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
-                          struct sk_buff *skb)
-{
-       bool force_update = false;
-       int bcn_idx = 0;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) {
-               if (vif_idx == i) {
-                       force_update = !!dev->beacons[i] ^ !!skb;
-                       dev_kfree_skb(dev->beacons[i]);
-                       dev->beacons[i] = skb;
-                       __mt76x02_mac_set_beacon(dev, bcn_idx, skb);
-               } else if (force_update && dev->beacons[i]) {
-                       __mt76x02_mac_set_beacon(dev, bcn_idx,
-                                                dev->beacons[i]);
-               }
-
-               bcn_idx += !!dev->beacons[i];
-       }
-
-       for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) {
-               if (!(dev->beacon_data_mask & BIT(i)))
-                       break;
-
-               __mt76x02_mac_set_beacon(dev, i, NULL);
-       }
-
-       mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N,
-                      bcn_idx - 1);
-       return 0;
-}
 EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon);
 
 void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
@@ -114,7 +73,6 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
                dev->mt76.beacon_mask |= BIT(mvif->idx);
        } else {
                dev->mt76.beacon_mask &= ~BIT(mvif->idx);
-               mt76x02_mac_set_beacon(dev, mvif->idx, NULL);
        }
 
        if (!!old_mask == !!dev->mt76.beacon_mask)
@@ -180,7 +138,7 @@ mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
        if (!skb)
                return;
 
-       mt76x02_mac_set_beacon(dev, mvif->idx, skb);
+       mt76x02_mac_set_beacon(dev, skb);
 }
 EXPORT_SYMBOL_GPL(mt76x02_update_beacon_iter);
 
index 5b512e4ce6b88ae1945700c7e2f785c7e18f0a7e..484cb5770fd927aff025e0ad8ab9b219807ff7e3 100644 (file)
@@ -741,6 +741,8 @@ void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr)
                get_unaligned_le16(dev->mt76.macaddr + 4) |
                FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 APs + 8 STAs */
                MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT);
+       /* enable 7 additional beacon slots and control them with bypass mask */
+       mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, 7);
 
        for (i = 0; i < 16; i++)
                mt76x02_mac_set_bssid(dev, i, null_addr);
index 37445bc7b546b38d0aff043927a4f61ff90f0c6a..89db7b3671d301bf6e16833d637f5a00784ef028 100644 (file)
@@ -201,8 +201,7 @@ void mt76x02_mac_work(struct work_struct *work);
 
 void mt76x02_mac_cc_reset(struct mt76x02_dev *dev);
 void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr);
-int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
-                          struct sk_buff *skb);
+int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, struct sk_buff *skb);
 void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
                                   struct ieee80211_vif *vif, bool enable);
 
index e7ba9bf82d98df3fc8d2c49343c0502875a8cec3..094a4228b591f9ddbbaf1ebf30f7ba73075a5c64 100644 (file)
@@ -24,10 +24,17 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
 
        mt76x02_resync_beacon_timer(dev);
 
+       /* Prevent corrupt transmissions during update */
+       mt76_set(dev, MT_BCN_BYPASS_MASK, 0xffff);
+       dev->beacon_data_count = 0;
+
        ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
                IEEE80211_IFACE_ITER_RESUME_ALL,
                mt76x02_update_beacon_iter, dev);
 
+       mt76_wr(dev, MT_BCN_BYPASS_MASK,
+               0xff00 | ~(0xff00 >> dev->beacon_data_count));
+
        mt76_csa_check(&dev->mt76);
 
        if (dev->mt76.csa_complete)
index 5cf015c1ef5d37564757fbe86c02b6233ac77963..30f119ba61c31fb1cd9bfcc6be48556dbab0bb06 100644 (file)
@@ -208,6 +208,10 @@ static void mt76x02u_pre_tbtt_work(struct work_struct *work)
 
        mt76x02_resync_beacon_timer(dev);
 
+       /* Prevent corrupt transmissions during update */
+       mt76_set(dev, MT_BCN_BYPASS_MASK, 0xffff);
+       dev->beacon_data_count = 0;
+
        ieee80211_iterate_active_interfaces(mt76_hw(dev),
                IEEE80211_IFACE_ITER_RESUME_ALL,
                mt76x02_update_beacon_iter, dev);
@@ -217,9 +221,12 @@ static void mt76x02u_pre_tbtt_work(struct work_struct *work)
 
        for (i = nbeacons; i < N_BCN_SLOTS; i++) {
                skb = __skb_dequeue(&data.q);
-               mt76x02_mac_set_beacon(dev, i, skb);
+               mt76x02_mac_set_beacon(dev, skb);
        }
 
+       mt76_wr(dev, MT_BCN_BYPASS_MASK,
+               0xff00 | ~(0xff00 >> dev->beacon_data_count));
+
        mt76x02u_restart_pre_tbtt_timer(dev);
 }
 
@@ -244,20 +251,11 @@ static void mt76x02u_pre_tbtt_enable(struct mt76x02_dev *dev, bool en)
 
 static void mt76x02u_beacon_enable(struct mt76x02_dev *dev, bool en)
 {
-       int i;
-
        if (WARN_ON_ONCE(!dev->mt76.beacon_int))
                return;
 
-       if (en) {
+       if (en)
                mt76x02u_start_pre_tbtt_timer(dev);
-       } else {
-               /* Timer is already stopped, only clean up
-                * PS buffered frames if any.
-                */
-               for (i = 0; i < N_BCN_SLOTS; i++)
-                       mt76x02_mac_set_beacon(dev, i, NULL);
-       }
 }
 
 void mt76x02u_init_beacon_config(struct mt76x02_dev *dev)