2 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
3 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
4 * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 static void mt76x02_set_beacon_offsets(struct mt76x02_dev
*dev
)
27 for (i
= 0; i
< dev
->beacon_ops
->nslots
; i
++) {
28 val
= i
* dev
->beacon_ops
->slot_size
;
29 regs
[i
/ 4] |= (val
/ 64) << (8 * (i
% 4));
32 for (i
= 0; i
< 4; i
++)
33 mt76_wr(dev
, MT_BCN_OFFSET(i
), regs
[i
]);
37 mt76x02_write_beacon(struct mt76x02_dev
*dev
, int offset
, struct sk_buff
*skb
)
39 int beacon_len
= dev
->beacon_ops
->slot_size
;
40 struct mt76x02_txwi txwi
;
42 if (WARN_ON_ONCE(beacon_len
< skb
->len
+ sizeof(struct mt76x02_txwi
)))
45 mt76x02_mac_write_txwi(dev
, &txwi
, skb
, NULL
, NULL
, skb
->len
);
47 mt76_wr_copy(dev
, offset
, &txwi
, sizeof(txwi
));
48 offset
+= sizeof(txwi
);
50 mt76_wr_copy(dev
, offset
, skb
->data
, skb
->len
);
55 __mt76x02_mac_set_beacon(struct mt76x02_dev
*dev
, u8 bcn_idx
,
58 int beacon_len
= dev
->beacon_ops
->slot_size
;
59 int beacon_addr
= MT_BEACON_BASE
+ (beacon_len
* bcn_idx
);
63 /* Prevent corrupt transmissions during update */
64 mt76_set(dev
, MT_BCN_BYPASS_MASK
, BIT(bcn_idx
));
67 ret
= mt76x02_write_beacon(dev
, beacon_addr
, skb
);
69 dev
->beacon_data_mask
|= BIT(bcn_idx
);
71 dev
->beacon_data_mask
&= ~BIT(bcn_idx
);
72 for (i
= 0; i
< beacon_len
; i
+= 4)
73 mt76_wr(dev
, beacon_addr
+ i
, 0);
76 mt76_wr(dev
, MT_BCN_BYPASS_MASK
, 0xff00 | ~dev
->beacon_data_mask
);
81 int mt76x02_mac_set_beacon(struct mt76x02_dev
*dev
, u8 vif_idx
,
84 bool force_update
= false;
88 for (i
= 0; i
< ARRAY_SIZE(dev
->beacons
); i
++) {
90 force_update
= !!dev
->beacons
[i
] ^ !!skb
;
93 dev_kfree_skb(dev
->beacons
[i
]);
95 dev
->beacons
[i
] = skb
;
96 __mt76x02_mac_set_beacon(dev
, bcn_idx
, skb
);
97 } else if (force_update
&& dev
->beacons
[i
]) {
98 __mt76x02_mac_set_beacon(dev
, bcn_idx
,
102 bcn_idx
+= !!dev
->beacons
[i
];
105 for (i
= bcn_idx
; i
< ARRAY_SIZE(dev
->beacons
); i
++) {
106 if (!(dev
->beacon_data_mask
& BIT(i
)))
109 __mt76x02_mac_set_beacon(dev
, i
, NULL
);
112 mt76_rmw_field(dev
, MT_MAC_BSSID_DW1
, MT_MAC_BSSID_DW1_MBEACON_N
,
116 EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon
);
119 __mt76x02_mac_set_beacon_enable(struct mt76x02_dev
*dev
, u8 vif_idx
,
120 bool val
, struct sk_buff
*skb
)
122 u8 old_mask
= dev
->mt76
.beacon_mask
;
127 dev
->mt76
.beacon_mask
|= BIT(vif_idx
);
129 mt76x02_mac_set_beacon(dev
, vif_idx
, skb
);
131 dev
->mt76
.beacon_mask
&= ~BIT(vif_idx
);
132 mt76x02_mac_set_beacon(dev
, vif_idx
, NULL
);
135 if (!!old_mask
== !!dev
->mt76
.beacon_mask
)
138 en
= dev
->mt76
.beacon_mask
;
140 reg
= MT_BEACON_TIME_CFG_BEACON_TX
|
141 MT_BEACON_TIME_CFG_TBTT_EN
|
142 MT_BEACON_TIME_CFG_TIMER_EN
;
143 mt76_rmw(dev
, MT_BEACON_TIME_CFG
, reg
, reg
* en
);
145 dev
->beacon_ops
->beacon_enable(dev
, en
);
148 void mt76x02_mac_set_beacon_enable(struct mt76x02_dev
*dev
,
149 struct ieee80211_vif
*vif
, bool val
)
151 u8 vif_idx
= ((struct mt76x02_vif
*)vif
->drv_priv
)->idx
;
152 struct sk_buff
*skb
= NULL
;
154 dev
->beacon_ops
->pre_tbtt_enable(dev
, false);
156 if (mt76_is_usb(dev
))
157 skb
= ieee80211_beacon_get(mt76_hw(dev
), vif
);
159 if (!dev
->mt76
.beacon_mask
)
162 __mt76x02_mac_set_beacon_enable(dev
, vif_idx
, val
, skb
);
164 dev
->beacon_ops
->pre_tbtt_enable(dev
, true);
168 mt76x02_resync_beacon_timer(struct mt76x02_dev
*dev
)
170 u32 timer_val
= dev
->mt76
.beacon_int
<< 4;
175 * Beacon timer drifts by 1us every tick, the timer is configured
176 * in 1/16 TU (64us) units.
178 if (dev
->tbtt_count
< 63)
182 * The updated beacon interval takes effect after two TBTT, because
183 * at this point the original interval has already been loaded into
184 * the next TBTT_TIMER value
186 if (dev
->tbtt_count
== 63)
189 mt76_rmw_field(dev
, MT_BEACON_TIME_CFG
,
190 MT_BEACON_TIME_CFG_INTVAL
, timer_val
);
192 if (dev
->tbtt_count
>= 64) {
197 EXPORT_SYMBOL_GPL(mt76x02_resync_beacon_timer
);
200 mt76x02_update_beacon_iter(void *priv
, u8
*mac
, struct ieee80211_vif
*vif
)
202 struct mt76x02_dev
*dev
= (struct mt76x02_dev
*)priv
;
203 struct mt76x02_vif
*mvif
= (struct mt76x02_vif
*)vif
->drv_priv
;
204 struct sk_buff
*skb
= NULL
;
206 if (!(dev
->mt76
.beacon_mask
& BIT(mvif
->idx
)))
209 skb
= ieee80211_beacon_get(mt76_hw(dev
), vif
);
213 mt76x02_mac_set_beacon(dev
, mvif
->idx
, skb
);
215 EXPORT_SYMBOL_GPL(mt76x02_update_beacon_iter
);
218 mt76x02_add_buffered_bc(void *priv
, u8
*mac
, struct ieee80211_vif
*vif
)
220 struct beacon_bc_data
*data
= priv
;
221 struct mt76x02_dev
*dev
= data
->dev
;
222 struct mt76x02_vif
*mvif
= (struct mt76x02_vif
*)vif
->drv_priv
;
223 struct ieee80211_tx_info
*info
;
226 if (!(dev
->mt76
.beacon_mask
& BIT(mvif
->idx
)))
229 skb
= ieee80211_get_buffered_bc(mt76_hw(dev
), vif
);
233 info
= IEEE80211_SKB_CB(skb
);
234 info
->control
.vif
= vif
;
235 info
->flags
|= IEEE80211_TX_CTL_ASSIGN_SEQ
;
236 mt76_skb_set_moredata(skb
, true);
237 __skb_queue_tail(&data
->q
, skb
);
238 data
->tail
[mvif
->idx
] = skb
;
242 mt76x02_enqueue_buffered_bc(struct mt76x02_dev
*dev
, struct beacon_bc_data
*data
,
248 __skb_queue_head_init(&data
->q
);
251 nframes
= skb_queue_len(&data
->q
);
252 ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev
),
253 IEEE80211_IFACE_ITER_RESUME_ALL
,
254 mt76x02_add_buffered_bc
, data
);
255 } while (nframes
!= skb_queue_len(&data
->q
) &&
256 skb_queue_len(&data
->q
) < max_nframes
);
258 if (!skb_queue_len(&data
->q
))
261 for (i
= 0; i
< ARRAY_SIZE(data
->tail
); i
++) {
264 mt76_skb_set_moredata(data
->tail
[i
], false);
267 EXPORT_SYMBOL_GPL(mt76x02_enqueue_buffered_bc
);
269 void mt76x02_init_beacon_config(struct mt76x02_dev
*dev
)
273 mt76_clear(dev
, MT_BEACON_TIME_CFG
, (MT_BEACON_TIME_CFG_TIMER_EN
|
274 MT_BEACON_TIME_CFG_TBTT_EN
|
275 MT_BEACON_TIME_CFG_BEACON_TX
));
276 mt76_set(dev
, MT_BEACON_TIME_CFG
, MT_BEACON_TIME_CFG_SYNC_MODE
);
277 mt76_wr(dev
, MT_BCN_BYPASS_MASK
, 0xffff);
279 for (i
= 0; i
< 8; i
++)
280 mt76x02_mac_set_beacon(dev
, i
, NULL
);
282 mt76x02_set_beacon_offsets(dev
);
284 EXPORT_SYMBOL_GPL(mt76x02_init_beacon_config
);