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