linux/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
<<
>>
Prefs
   1// SPDX-License-Identifier: ISC
   2/*
   3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
   4 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
   5 * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
   6 */
   7
   8#include "mt76x02.h"
   9
  10static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev)
  11{
  12        u32 regs[4] = {};
  13        u16 val;
  14        int i;
  15
  16        for (i = 0; i < dev->beacon_ops->nslots; i++) {
  17                val = i * dev->beacon_ops->slot_size;
  18                regs[i / 4] |= (val / 64) << (8 * (i % 4));
  19        }
  20
  21        for (i = 0; i < 4; i++)
  22                mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
  23}
  24
  25static int
  26mt76x02_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb)
  27{
  28        int beacon_len = dev->beacon_ops->slot_size;
  29
  30        if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
  31                return -ENOSPC;
  32
  33        /* USB devices already reserve enough skb headroom for txwi's. This
  34         * helps to save slow copies over USB.
  35         */
  36        if (mt76_is_usb(&dev->mt76)) {
  37                struct mt76x02_txwi *txwi;
  38
  39                txwi = (struct mt76x02_txwi *)(skb->data - sizeof(*txwi));
  40                mt76x02_mac_write_txwi(dev, txwi, skb, NULL, NULL, skb->len);
  41                skb_push(skb, sizeof(*txwi));
  42        } else {
  43                struct mt76x02_txwi txwi;
  44
  45                mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
  46                mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
  47                offset += sizeof(txwi);
  48        }
  49
  50        mt76_wr_copy(dev, offset, skb->data, skb->len);
  51        return 0;
  52}
  53
  54void mt76x02_mac_set_beacon(struct mt76x02_dev *dev,
  55                            struct sk_buff *skb)
  56{
  57        int bcn_len = dev->beacon_ops->slot_size;
  58        int bcn_addr = MT_BEACON_BASE + (bcn_len * dev->beacon_data_count);
  59
  60        if (!mt76x02_write_beacon(dev, bcn_addr, skb))
  61                dev->beacon_data_count++;
  62        dev_kfree_skb(skb);
  63}
  64EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon);
  65
  66void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
  67                                   struct ieee80211_vif *vif, bool enable)
  68{
  69        struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
  70        u8 old_mask = dev->mt76.beacon_mask;
  71
  72        mt76x02_pre_tbtt_enable(dev, false);
  73
  74        if (!dev->mt76.beacon_mask)
  75                dev->tbtt_count = 0;
  76
  77        if (enable) {
  78                dev->mt76.beacon_mask |= BIT(mvif->idx);
  79        } else {
  80                dev->mt76.beacon_mask &= ~BIT(mvif->idx);
  81        }
  82
  83        if (!!old_mask == !!dev->mt76.beacon_mask)
  84                goto out;
  85
  86        if (dev->mt76.beacon_mask)
  87                mt76_set(dev, MT_BEACON_TIME_CFG,
  88                         MT_BEACON_TIME_CFG_BEACON_TX |
  89                         MT_BEACON_TIME_CFG_TBTT_EN |
  90                         MT_BEACON_TIME_CFG_TIMER_EN);
  91        else
  92                mt76_clear(dev, MT_BEACON_TIME_CFG,
  93                           MT_BEACON_TIME_CFG_BEACON_TX |
  94                           MT_BEACON_TIME_CFG_TBTT_EN |
  95                           MT_BEACON_TIME_CFG_TIMER_EN);
  96        mt76x02_beacon_enable(dev, !!dev->mt76.beacon_mask);
  97
  98out:
  99        mt76x02_pre_tbtt_enable(dev, true);
 100}
 101
 102void
 103mt76x02_resync_beacon_timer(struct mt76x02_dev *dev)
 104{
 105        u32 timer_val = dev->mt76.beacon_int << 4;
 106
 107        dev->tbtt_count++;
 108
 109        /*
 110         * Beacon timer drifts by 1us every tick, the timer is configured
 111         * in 1/16 TU (64us) units.
 112         */
 113        if (dev->tbtt_count < 63)
 114                return;
 115
 116        /*
 117         * The updated beacon interval takes effect after two TBTT, because
 118         * at this point the original interval has already been loaded into
 119         * the next TBTT_TIMER value
 120         */
 121        if (dev->tbtt_count == 63)
 122                timer_val -= 1;
 123
 124        mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
 125                       MT_BEACON_TIME_CFG_INTVAL, timer_val);
 126
 127        if (dev->tbtt_count >= 64)
 128                dev->tbtt_count = 0;
 129}
 130EXPORT_SYMBOL_GPL(mt76x02_resync_beacon_timer);
 131
 132void
 133mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
 134{
 135        struct mt76x02_dev *dev = (struct mt76x02_dev *)priv;
 136        struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
 137        struct sk_buff *skb = NULL;
 138
 139        if (!(dev->mt76.beacon_mask & BIT(mvif->idx)))
 140                return;
 141
 142        skb = ieee80211_beacon_get(mt76_hw(dev), vif);
 143        if (!skb)
 144                return;
 145
 146        mt76x02_mac_set_beacon(dev, skb);
 147}
 148EXPORT_SYMBOL_GPL(mt76x02_update_beacon_iter);
 149
 150static void
 151mt76x02_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
 152{
 153        struct beacon_bc_data *data = priv;
 154        struct mt76x02_dev *dev = data->dev;
 155        struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
 156        struct ieee80211_tx_info *info;
 157        struct sk_buff *skb;
 158
 159        if (!(dev->mt76.beacon_mask & BIT(mvif->idx)))
 160                return;
 161
 162        skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif);
 163        if (!skb)
 164                return;
 165
 166        info = IEEE80211_SKB_CB(skb);
 167        info->control.vif = vif;
 168        info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
 169        mt76_skb_set_moredata(skb, true);
 170        __skb_queue_tail(&data->q, skb);
 171        data->tail[mvif->idx] = skb;
 172}
 173
 174void
 175mt76x02_enqueue_buffered_bc(struct mt76x02_dev *dev,
 176                            struct beacon_bc_data *data,
 177                            int max_nframes)
 178{
 179        int i, nframes;
 180
 181        data->dev = dev;
 182        __skb_queue_head_init(&data->q);
 183
 184        do {
 185                nframes = skb_queue_len(&data->q);
 186                ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
 187                        IEEE80211_IFACE_ITER_RESUME_ALL,
 188                        mt76x02_add_buffered_bc, data);
 189        } while (nframes != skb_queue_len(&data->q) &&
 190                 skb_queue_len(&data->q) < max_nframes);
 191
 192        if (!skb_queue_len(&data->q))
 193                return;
 194
 195        for (i = 0; i < ARRAY_SIZE(data->tail); i++) {
 196                if (!data->tail[i])
 197                        continue;
 198                mt76_skb_set_moredata(data->tail[i], false);
 199        }
 200}
 201EXPORT_SYMBOL_GPL(mt76x02_enqueue_buffered_bc);
 202
 203void mt76x02_init_beacon_config(struct mt76x02_dev *dev)
 204{
 205        mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
 206                                             MT_BEACON_TIME_CFG_TBTT_EN |
 207                                             MT_BEACON_TIME_CFG_BEACON_TX));
 208        mt76_set(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_SYNC_MODE);
 209        mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff);
 210        mt76x02_set_beacon_offsets(dev);
 211}
 212EXPORT_SYMBOL_GPL(mt76x02_init_beacon_config);
 213
 214