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 262