root/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mt76x02_set_beacon_offsets
  2. mt76x02_write_beacon
  3. __mt76x02_mac_set_beacon
  4. mt76x02_mac_set_beacon
  5. mt76x02_mac_set_beacon_enable
  6. mt76x02_resync_beacon_timer
  7. mt76x02_update_beacon_iter
  8. mt76x02_add_buffered_bc
  9. mt76x02_enqueue_buffered_bc
  10. mt76x02_init_beacon_config

   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 
  10 static 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 
  25 static int
  26 mt76x02_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb)
  27 {
  28         int beacon_len = dev->beacon_ops->slot_size;
  29         struct mt76x02_txwi txwi;
  30 
  31         if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
  32                 return -ENOSPC;
  33 
  34         mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
  35 
  36         mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
  37         offset += sizeof(txwi);
  38 
  39         mt76_wr_copy(dev, offset, skb->data, skb->len);
  40         return 0;
  41 }
  42 
  43 static int
  44 __mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx,
  45                          struct sk_buff *skb)
  46 {
  47         int beacon_len = dev->beacon_ops->slot_size;
  48         int beacon_addr = MT_BEACON_BASE + (beacon_len * bcn_idx);
  49         int ret = 0;
  50         int i;
  51 
  52         /* Prevent corrupt transmissions during update */
  53         mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx));
  54 
  55         if (skb) {
  56                 ret = mt76x02_write_beacon(dev, beacon_addr, skb);
  57                 if (!ret)
  58                         dev->beacon_data_mask |= BIT(bcn_idx);
  59         } else {
  60                 dev->beacon_data_mask &= ~BIT(bcn_idx);
  61                 for (i = 0; i < beacon_len; i += 4)
  62                         mt76_wr(dev, beacon_addr + i, 0);
  63         }
  64 
  65         mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask);
  66 
  67         return ret;
  68 }
  69 
  70 int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
  71                            struct sk_buff *skb)
  72 {
  73         bool force_update = false;
  74         int bcn_idx = 0;
  75         int i;
  76 
  77         for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) {
  78                 if (vif_idx == i) {
  79                         force_update = !!dev->beacons[i] ^ !!skb;
  80 
  81                         if (dev->beacons[i])
  82                                 dev_kfree_skb(dev->beacons[i]);
  83 
  84                         dev->beacons[i] = skb;
  85                         __mt76x02_mac_set_beacon(dev, bcn_idx, skb);
  86                 } else if (force_update && dev->beacons[i]) {
  87                         __mt76x02_mac_set_beacon(dev, bcn_idx,
  88                                                  dev->beacons[i]);
  89                 }
  90 
  91                 bcn_idx += !!dev->beacons[i];
  92         }
  93 
  94         for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) {
  95                 if (!(dev->beacon_data_mask & BIT(i)))
  96                         break;
  97 
  98                 __mt76x02_mac_set_beacon(dev, i, NULL);
  99         }
 100 
 101         mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N,
 102                        bcn_idx - 1);
 103         return 0;
 104 }
 105 EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon);
 106 
 107 void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
 108                                    struct ieee80211_vif *vif, bool enable)
 109 {
 110         struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
 111         u8 old_mask = dev->mt76.beacon_mask;
 112 
 113         mt76x02_pre_tbtt_enable(dev, false);
 114 
 115         if (!dev->mt76.beacon_mask)
 116                 dev->tbtt_count = 0;
 117 
 118         if (enable) {
 119                 dev->mt76.beacon_mask |= BIT(mvif->idx);
 120         } else {
 121                 dev->mt76.beacon_mask &= ~BIT(mvif->idx);
 122                 mt76x02_mac_set_beacon(dev, mvif->idx, NULL);
 123         }
 124 
 125         if (!!old_mask == !!dev->mt76.beacon_mask)
 126                 goto out;
 127 
 128         if (dev->mt76.beacon_mask)
 129                 mt76_set(dev, MT_BEACON_TIME_CFG,
 130                          MT_BEACON_TIME_CFG_BEACON_TX |
 131                          MT_BEACON_TIME_CFG_TBTT_EN |
 132                          MT_BEACON_TIME_CFG_TIMER_EN);
 133         else
 134                 mt76_clear(dev, MT_BEACON_TIME_CFG,
 135                            MT_BEACON_TIME_CFG_BEACON_TX |
 136                            MT_BEACON_TIME_CFG_TBTT_EN |
 137                            MT_BEACON_TIME_CFG_TIMER_EN);
 138         mt76x02_beacon_enable(dev, !!dev->mt76.beacon_mask);
 139 
 140 out:
 141         mt76x02_pre_tbtt_enable(dev, true);
 142 }
 143 
 144 void
 145 mt76x02_resync_beacon_timer(struct mt76x02_dev *dev)
 146 {
 147         u32 timer_val = dev->mt76.beacon_int << 4;
 148 
 149         dev->tbtt_count++;
 150 
 151         /*
 152          * Beacon timer drifts by 1us every tick, the timer is configured
 153          * in 1/16 TU (64us) units.
 154          */
 155         if (dev->tbtt_count < 63)
 156                 return;
 157 
 158         /*
 159          * The updated beacon interval takes effect after two TBTT, because
 160          * at this point the original interval has already been loaded into
 161          * the next TBTT_TIMER value
 162          */
 163         if (dev->tbtt_count == 63)
 164                 timer_val -= 1;
 165 
 166         mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
 167                        MT_BEACON_TIME_CFG_INTVAL, timer_val);
 168 
 169         if (dev->tbtt_count >= 64)
 170                 dev->tbtt_count = 0;
 171 }
 172 EXPORT_SYMBOL_GPL(mt76x02_resync_beacon_timer);
 173 
 174 void
 175 mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
 176 {
 177         struct mt76x02_dev *dev = (struct mt76x02_dev *)priv;
 178         struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
 179         struct sk_buff *skb = NULL;
 180 
 181         if (!(dev->mt76.beacon_mask & BIT(mvif->idx)))
 182                 return;
 183 
 184         skb = ieee80211_beacon_get(mt76_hw(dev), vif);
 185         if (!skb)
 186                 return;
 187 
 188         mt76x02_mac_set_beacon(dev, mvif->idx, skb);
 189 }
 190 EXPORT_SYMBOL_GPL(mt76x02_update_beacon_iter);
 191 
 192 static void
 193 mt76x02_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
 194 {
 195         struct beacon_bc_data *data = priv;
 196         struct mt76x02_dev *dev = data->dev;
 197         struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
 198         struct ieee80211_tx_info *info;
 199         struct sk_buff *skb;
 200 
 201         if (!(dev->mt76.beacon_mask & BIT(mvif->idx)))
 202                 return;
 203 
 204         skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif);
 205         if (!skb)
 206                 return;
 207 
 208         info = IEEE80211_SKB_CB(skb);
 209         info->control.vif = vif;
 210         info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
 211         mt76_skb_set_moredata(skb, true);
 212         __skb_queue_tail(&data->q, skb);
 213         data->tail[mvif->idx] = skb;
 214 }
 215 
 216 void
 217 mt76x02_enqueue_buffered_bc(struct mt76x02_dev *dev,
 218                             struct beacon_bc_data *data,
 219                             int max_nframes)
 220 {
 221         int i, nframes;
 222 
 223         data->dev = dev;
 224         __skb_queue_head_init(&data->q);
 225 
 226         do {
 227                 nframes = skb_queue_len(&data->q);
 228                 ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
 229                         IEEE80211_IFACE_ITER_RESUME_ALL,
 230                         mt76x02_add_buffered_bc, data);
 231         } while (nframes != skb_queue_len(&data->q) &&
 232                  skb_queue_len(&data->q) < max_nframes);
 233 
 234         if (!skb_queue_len(&data->q))
 235                 return;
 236 
 237         for (i = 0; i < ARRAY_SIZE(data->tail); i++) {
 238                 if (!data->tail[i])
 239                         continue;
 240                 mt76_skb_set_moredata(data->tail[i], false);
 241         }
 242 }
 243 EXPORT_SYMBOL_GPL(mt76x02_enqueue_buffered_bc);
 244 
 245 void mt76x02_init_beacon_config(struct mt76x02_dev *dev)
 246 {
 247         int i;
 248 
 249         mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
 250                                              MT_BEACON_TIME_CFG_TBTT_EN |
 251                                              MT_BEACON_TIME_CFG_BEACON_TX));
 252         mt76_set(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_SYNC_MODE);
 253         mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff);
 254 
 255         for (i = 0; i < 8; i++)
 256                 mt76x02_mac_set_beacon(dev, i, NULL);
 257 
 258         mt76x02_set_beacon_offsets(dev);
 259 }
 260 EXPORT_SYMBOL_GPL(mt76x02_init_beacon_config);
 261 

/* [<][>][^][v][top][bottom][index][help] */