1 // SPDX-License-Identifier: ISC
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>
10 static void mt76x02_set_beacon_offsets(struct mt76x02_dev
*dev
)
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));
21 for (i
= 0; i
< 4; i
++)
22 mt76_wr(dev
, MT_BCN_OFFSET(i
), regs
[i
]);
26 mt76x02_write_beacon(struct mt76x02_dev
*dev
, int offset
, struct sk_buff
*skb
)
28 int beacon_len
= dev
->beacon_ops
->slot_size
;
29 struct mt76x02_txwi txwi
;
31 if (WARN_ON_ONCE(beacon_len
< skb
->len
+ sizeof(struct mt76x02_txwi
)))
34 mt76x02_mac_write_txwi(dev
, &txwi
, skb
, NULL
, NULL
, skb
->len
);
36 mt76_wr_copy(dev
, offset
, &txwi
, sizeof(txwi
));
37 offset
+= sizeof(txwi
);
39 mt76_wr_copy(dev
, offset
, skb
->data
, skb
->len
);
44 __mt76x02_mac_set_beacon(struct mt76x02_dev
*dev
, u8 bcn_idx
,
47 int beacon_len
= dev
->beacon_ops
->slot_size
;
48 int beacon_addr
= MT_BEACON_BASE
+ (beacon_len
* bcn_idx
);
52 /* Prevent corrupt transmissions during update */
53 mt76_set(dev
, MT_BCN_BYPASS_MASK
, BIT(bcn_idx
));
56 ret
= mt76x02_write_beacon(dev
, beacon_addr
, skb
);
58 dev
->beacon_data_mask
|= BIT(bcn_idx
);
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);
65 mt76_wr(dev
, MT_BCN_BYPASS_MASK
, 0xff00 | ~dev
->beacon_data_mask
);
70 int mt76x02_mac_set_beacon(struct mt76x02_dev
*dev
, u8 vif_idx
,
73 bool force_update
= false;
77 for (i
= 0; i
< ARRAY_SIZE(dev
->beacons
); 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
,
88 bcn_idx
+= !!dev
->beacons
[i
];
91 for (i
= bcn_idx
; i
< ARRAY_SIZE(dev
->beacons
); i
++) {
92 if (!(dev
->beacon_data_mask
& BIT(i
)))
95 __mt76x02_mac_set_beacon(dev
, i
, NULL
);
98 mt76_rmw_field(dev
, MT_MAC_BSSID_DW1
, MT_MAC_BSSID_DW1_MBEACON_N
,
102 EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon
);
104 void mt76x02_mac_set_beacon_enable(struct mt76x02_dev
*dev
,
105 struct ieee80211_vif
*vif
, bool enable
)
107 struct mt76x02_vif
*mvif
= (struct mt76x02_vif
*)vif
->drv_priv
;
108 u8 old_mask
= dev
->mt76
.beacon_mask
;
110 mt76x02_pre_tbtt_enable(dev
, false);
112 if (!dev
->mt76
.beacon_mask
)
116 dev
->mt76
.beacon_mask
|= BIT(mvif
->idx
);
118 dev
->mt76
.beacon_mask
&= ~BIT(mvif
->idx
);
119 mt76x02_mac_set_beacon(dev
, mvif
->idx
, NULL
);
122 if (!!old_mask
== !!dev
->mt76
.beacon_mask
)
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
);
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
);
138 mt76x02_pre_tbtt_enable(dev
, true);
142 mt76x02_resync_beacon_timer(struct mt76x02_dev
*dev
)
144 u32 timer_val
= dev
->mt76
.beacon_int
<< 4;
149 * Beacon timer drifts by 1us every tick, the timer is configured
150 * in 1/16 TU (64us) units.
152 if (dev
->tbtt_count
< 63)
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
160 if (dev
->tbtt_count
== 63)
163 mt76_rmw_field(dev
, MT_BEACON_TIME_CFG
,
164 MT_BEACON_TIME_CFG_INTVAL
, timer_val
);
166 if (dev
->tbtt_count
>= 64)
169 EXPORT_SYMBOL_GPL(mt76x02_resync_beacon_timer
);
172 mt76x02_update_beacon_iter(void *priv
, u8
*mac
, struct ieee80211_vif
*vif
)
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
;
178 if (!(dev
->mt76
.beacon_mask
& BIT(mvif
->idx
)))
181 skb
= ieee80211_beacon_get(mt76_hw(dev
), vif
);
185 mt76x02_mac_set_beacon(dev
, mvif
->idx
, skb
);
187 EXPORT_SYMBOL_GPL(mt76x02_update_beacon_iter
);
190 mt76x02_add_buffered_bc(void *priv
, u8
*mac
, struct ieee80211_vif
*vif
)
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
;
198 if (!(dev
->mt76
.beacon_mask
& BIT(mvif
->idx
)))
201 skb
= ieee80211_get_buffered_bc(mt76_hw(dev
), vif
);
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
;
214 mt76x02_enqueue_buffered_bc(struct mt76x02_dev
*dev
,
215 struct beacon_bc_data
*data
,
221 __skb_queue_head_init(&data
->q
);
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
);
231 if (!skb_queue_len(&data
->q
))
234 for (i
= 0; i
< ARRAY_SIZE(data
->tail
); i
++) {
237 mt76_skb_set_moredata(data
->tail
[i
], false);
240 EXPORT_SYMBOL_GPL(mt76x02_enqueue_buffered_bc
);
242 void mt76x02_init_beacon_config(struct mt76x02_dev
*dev
)
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);
252 for (i
= 0; i
< 8; i
++)
253 mt76x02_mac_set_beacon(dev
, i
, NULL
);
255 mt76x02_set_beacon_offsets(dev
);
257 EXPORT_SYMBOL_GPL(mt76x02_init_beacon_config
);