1 | // SPDX-License-Identifier: ISC |
2 | /* Copyright (C) 2023 MediaTek Inc. */ |
3 | |
4 | #include <linux/module.h> |
5 | #include <linux/firmware.h> |
6 | |
7 | #include "mt792x.h" |
8 | #include "dma.h" |
9 | |
10 | static const struct ieee80211_iface_limit if_limits[] = { |
11 | { |
12 | .max = MT792x_MAX_INTERFACES, |
13 | .types = BIT(NL80211_IFTYPE_STATION) |
14 | }, |
15 | { |
16 | .max = 1, |
17 | .types = BIT(NL80211_IFTYPE_AP) |
18 | } |
19 | }; |
20 | |
21 | static const struct ieee80211_iface_combination if_comb[] = { |
22 | { |
23 | .limits = if_limits, |
24 | .n_limits = ARRAY_SIZE(if_limits), |
25 | .max_interfaces = MT792x_MAX_INTERFACES, |
26 | .num_different_channels = 1, |
27 | .beacon_int_infra_match = true, |
28 | }, |
29 | }; |
30 | |
31 | static const struct ieee80211_iface_limit if_limits_chanctx[] = { |
32 | { |
33 | .max = 2, |
34 | .types = BIT(NL80211_IFTYPE_STATION) | |
35 | BIT(NL80211_IFTYPE_P2P_CLIENT) |
36 | }, |
37 | { |
38 | .max = 1, |
39 | .types = BIT(NL80211_IFTYPE_AP) | |
40 | BIT(NL80211_IFTYPE_P2P_GO) |
41 | } |
42 | }; |
43 | |
44 | static const struct ieee80211_iface_combination if_comb_chanctx[] = { |
45 | { |
46 | .limits = if_limits_chanctx, |
47 | .n_limits = ARRAY_SIZE(if_limits_chanctx), |
48 | .max_interfaces = 2, |
49 | .num_different_channels = 2, |
50 | .beacon_int_infra_match = false, |
51 | } |
52 | }; |
53 | |
54 | void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, |
55 | struct sk_buff *skb) |
56 | { |
57 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
58 | struct mt76_phy *mphy = hw->priv; |
59 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
60 | struct ieee80211_vif *vif = info->control.vif; |
61 | struct mt76_wcid *wcid = &dev->mt76.global_wcid; |
62 | int qid; |
63 | |
64 | if (control->sta) { |
65 | struct mt792x_sta *sta; |
66 | |
67 | sta = (struct mt792x_sta *)control->sta->drv_priv; |
68 | wcid = &sta->wcid; |
69 | } |
70 | |
71 | if (vif && !control->sta) { |
72 | struct mt792x_vif *mvif; |
73 | |
74 | mvif = (struct mt792x_vif *)vif->drv_priv; |
75 | wcid = &mvif->sta.wcid; |
76 | } |
77 | |
78 | if (mt76_connac_pm_ref(phy: mphy, pm: &dev->pm)) { |
79 | mt76_tx(dev: mphy, sta: control->sta, wcid, skb); |
80 | mt76_connac_pm_unref(phy: mphy, pm: &dev->pm); |
81 | return; |
82 | } |
83 | |
84 | qid = skb_get_queue_mapping(skb); |
85 | if (qid >= MT_TXQ_PSD) { |
86 | qid = IEEE80211_AC_BE; |
87 | skb_set_queue_mapping(skb, queue_mapping: qid); |
88 | } |
89 | |
90 | mt76_connac_pm_queue_skb(hw, pm: &dev->pm, wcid, skb); |
91 | } |
92 | EXPORT_SYMBOL_GPL(mt792x_tx); |
93 | |
94 | void mt792x_stop(struct ieee80211_hw *hw) |
95 | { |
96 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
97 | struct mt792x_phy *phy = mt792x_hw_phy(hw); |
98 | |
99 | cancel_delayed_work_sync(dwork: &phy->mt76->mac_work); |
100 | |
101 | cancel_delayed_work_sync(dwork: &dev->pm.ps_work); |
102 | cancel_work_sync(work: &dev->pm.wake_work); |
103 | cancel_work_sync(work: &dev->reset_work); |
104 | mt76_connac_free_pending_tx_skbs(pm: &dev->pm, NULL); |
105 | |
106 | if (is_mt7921(dev: &dev->mt76)) { |
107 | mt792x_mutex_acquire(dev); |
108 | mt76_connac_mcu_set_mac_enable(dev: &dev->mt76, band: 0, enable: false, hdr_trans: false); |
109 | mt792x_mutex_release(dev); |
110 | } |
111 | |
112 | clear_bit(nr: MT76_STATE_RUNNING, addr: &phy->mt76->state); |
113 | } |
114 | EXPORT_SYMBOL_GPL(mt792x_stop); |
115 | |
116 | void mt792x_remove_interface(struct ieee80211_hw *hw, |
117 | struct ieee80211_vif *vif) |
118 | { |
119 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
120 | struct mt792x_sta *msta = &mvif->sta; |
121 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
122 | struct mt792x_phy *phy = mt792x_hw_phy(hw); |
123 | int idx = msta->wcid.idx; |
124 | |
125 | mt792x_mutex_acquire(dev); |
126 | mt76_connac_free_pending_tx_skbs(pm: &dev->pm, wcid: &msta->wcid); |
127 | mt76_connac_mcu_uni_add_dev(phy: &dev->mphy, vif, wcid: &mvif->sta.wcid, enable: false); |
128 | |
129 | rcu_assign_pointer(dev->mt76.wcid[idx], NULL); |
130 | |
131 | dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); |
132 | phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); |
133 | mt792x_mutex_release(dev); |
134 | |
135 | spin_lock_bh(lock: &dev->mt76.sta_poll_lock); |
136 | if (!list_empty(head: &msta->wcid.poll_list)) |
137 | list_del_init(entry: &msta->wcid.poll_list); |
138 | spin_unlock_bh(lock: &dev->mt76.sta_poll_lock); |
139 | |
140 | mt76_wcid_cleanup(dev: &dev->mt76, wcid: &msta->wcid); |
141 | } |
142 | EXPORT_SYMBOL_GPL(mt792x_remove_interface); |
143 | |
144 | int mt792x_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
145 | unsigned int link_id, u16 queue, |
146 | const struct ieee80211_tx_queue_params *params) |
147 | { |
148 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
149 | |
150 | /* no need to update right away, we'll get BSS_CHANGED_QOS */ |
151 | queue = mt76_connac_lmac_mapping(ac: queue); |
152 | mvif->queue_params[queue] = *params; |
153 | |
154 | return 0; |
155 | } |
156 | EXPORT_SYMBOL_GPL(mt792x_conf_tx); |
157 | |
158 | int mt792x_get_stats(struct ieee80211_hw *hw, |
159 | struct ieee80211_low_level_stats *stats) |
160 | { |
161 | struct mt792x_phy *phy = mt792x_hw_phy(hw); |
162 | struct mt76_mib_stats *mib = &phy->mib; |
163 | |
164 | mt792x_mutex_acquire(phy->dev); |
165 | |
166 | stats->dot11RTSSuccessCount = mib->rts_cnt; |
167 | stats->dot11RTSFailureCount = mib->rts_retries_cnt; |
168 | stats->dot11FCSErrorCount = mib->fcs_err_cnt; |
169 | stats->dot11ACKFailureCount = mib->ack_fail_cnt; |
170 | |
171 | mt792x_mutex_release(phy->dev); |
172 | |
173 | return 0; |
174 | } |
175 | EXPORT_SYMBOL_GPL(mt792x_get_stats); |
176 | |
177 | u64 mt792x_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
178 | { |
179 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
180 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
181 | u8 omac_idx = mvif->mt76.omac_idx; |
182 | union { |
183 | u64 t64; |
184 | u32 t32[2]; |
185 | } tsf; |
186 | u16 n; |
187 | |
188 | mt792x_mutex_acquire(dev); |
189 | |
190 | n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx; |
191 | /* TSF software read */ |
192 | mt76_set(dev, MT_LPON_TCR(0, n), MT_LPON_TCR_SW_MODE); |
193 | tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(0)); |
194 | tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(0)); |
195 | |
196 | mt792x_mutex_release(dev); |
197 | |
198 | return tsf.t64; |
199 | } |
200 | EXPORT_SYMBOL_GPL(mt792x_get_tsf); |
201 | |
202 | void mt792x_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
203 | u64 timestamp) |
204 | { |
205 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
206 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
207 | u8 omac_idx = mvif->mt76.omac_idx; |
208 | union { |
209 | u64 t64; |
210 | u32 t32[2]; |
211 | } tsf = { .t64 = timestamp, }; |
212 | u16 n; |
213 | |
214 | mt792x_mutex_acquire(dev); |
215 | |
216 | n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx; |
217 | mt76_wr(dev, MT_LPON_UTTR0(0), tsf.t32[0]); |
218 | mt76_wr(dev, MT_LPON_UTTR1(0), tsf.t32[1]); |
219 | /* TSF software overwrite */ |
220 | mt76_set(dev, MT_LPON_TCR(0, n), MT_LPON_TCR_SW_WRITE); |
221 | |
222 | mt792x_mutex_release(dev); |
223 | } |
224 | EXPORT_SYMBOL_GPL(mt792x_set_tsf); |
225 | |
226 | void mt792x_tx_worker(struct mt76_worker *w) |
227 | { |
228 | struct mt792x_dev *dev = container_of(w, struct mt792x_dev, |
229 | mt76.tx_worker); |
230 | |
231 | if (!mt76_connac_pm_ref(phy: &dev->mphy, pm: &dev->pm)) { |
232 | queue_work(wq: dev->mt76.wq, work: &dev->pm.wake_work); |
233 | return; |
234 | } |
235 | |
236 | mt76_txq_schedule_all(phy: &dev->mphy); |
237 | mt76_connac_pm_unref(phy: &dev->mphy, pm: &dev->pm); |
238 | } |
239 | EXPORT_SYMBOL_GPL(mt792x_tx_worker); |
240 | |
241 | void mt792x_roc_timer(struct timer_list *timer) |
242 | { |
243 | struct mt792x_phy *phy = from_timer(phy, timer, roc_timer); |
244 | |
245 | ieee80211_queue_work(hw: phy->mt76->hw, work: &phy->roc_work); |
246 | } |
247 | EXPORT_SYMBOL_GPL(mt792x_roc_timer); |
248 | |
249 | void mt792x_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
250 | u32 queues, bool drop) |
251 | { |
252 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
253 | |
254 | wait_event_timeout(dev->mt76.tx_wait, |
255 | !mt76_has_tx_pending(&dev->mphy), HZ / 2); |
256 | } |
257 | EXPORT_SYMBOL_GPL(mt792x_flush); |
258 | |
259 | int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw, |
260 | struct ieee80211_vif *vif, |
261 | struct ieee80211_bss_conf *link_conf, |
262 | struct ieee80211_chanctx_conf *ctx) |
263 | { |
264 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
265 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
266 | |
267 | mutex_lock(&dev->mt76.mutex); |
268 | mvif->mt76.ctx = ctx; |
269 | mutex_unlock(lock: &dev->mt76.mutex); |
270 | |
271 | return 0; |
272 | } |
273 | EXPORT_SYMBOL_GPL(mt792x_assign_vif_chanctx); |
274 | |
275 | void mt792x_unassign_vif_chanctx(struct ieee80211_hw *hw, |
276 | struct ieee80211_vif *vif, |
277 | struct ieee80211_bss_conf *link_conf, |
278 | struct ieee80211_chanctx_conf *ctx) |
279 | { |
280 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
281 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
282 | |
283 | mutex_lock(&dev->mt76.mutex); |
284 | mvif->mt76.ctx = NULL; |
285 | mutex_unlock(lock: &dev->mt76.mutex); |
286 | } |
287 | EXPORT_SYMBOL_GPL(mt792x_unassign_vif_chanctx); |
288 | |
289 | void mt792x_set_wakeup(struct ieee80211_hw *hw, bool enabled) |
290 | { |
291 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
292 | struct mt76_dev *mdev = &dev->mt76; |
293 | |
294 | device_set_wakeup_enable(dev: mdev->dev, enable: enabled); |
295 | } |
296 | EXPORT_SYMBOL_GPL(mt792x_set_wakeup); |
297 | |
298 | static const char mt792x_gstrings_stats[][ETH_GSTRING_LEN] = { |
299 | /* tx counters */ |
300 | "tx_ampdu_cnt" , |
301 | "tx_mpdu_attempts" , |
302 | "tx_mpdu_success" , |
303 | "tx_pkt_ebf_cnt" , |
304 | "tx_pkt_ibf_cnt" , |
305 | "tx_ampdu_len:0-1" , |
306 | "tx_ampdu_len:2-10" , |
307 | "tx_ampdu_len:11-19" , |
308 | "tx_ampdu_len:20-28" , |
309 | "tx_ampdu_len:29-37" , |
310 | "tx_ampdu_len:38-46" , |
311 | "tx_ampdu_len:47-55" , |
312 | "tx_ampdu_len:56-79" , |
313 | "tx_ampdu_len:80-103" , |
314 | "tx_ampdu_len:104-127" , |
315 | "tx_ampdu_len:128-151" , |
316 | "tx_ampdu_len:152-175" , |
317 | "tx_ampdu_len:176-199" , |
318 | "tx_ampdu_len:200-223" , |
319 | "tx_ampdu_len:224-247" , |
320 | "ba_miss_count" , |
321 | "tx_beamformer_ppdu_iBF" , |
322 | "tx_beamformer_ppdu_eBF" , |
323 | "tx_beamformer_rx_feedback_all" , |
324 | "tx_beamformer_rx_feedback_he" , |
325 | "tx_beamformer_rx_feedback_vht" , |
326 | "tx_beamformer_rx_feedback_ht" , |
327 | "tx_msdu_pack_1" , |
328 | "tx_msdu_pack_2" , |
329 | "tx_msdu_pack_3" , |
330 | "tx_msdu_pack_4" , |
331 | "tx_msdu_pack_5" , |
332 | "tx_msdu_pack_6" , |
333 | "tx_msdu_pack_7" , |
334 | "tx_msdu_pack_8" , |
335 | /* rx counters */ |
336 | "rx_mpdu_cnt" , |
337 | "rx_ampdu_cnt" , |
338 | "rx_ampdu_bytes_cnt" , |
339 | "rx_ba_cnt" , |
340 | /* per vif counters */ |
341 | "v_tx_mode_cck" , |
342 | "v_tx_mode_ofdm" , |
343 | "v_tx_mode_ht" , |
344 | "v_tx_mode_ht_gf" , |
345 | "v_tx_mode_vht" , |
346 | "v_tx_mode_he_su" , |
347 | "v_tx_mode_he_ext_su" , |
348 | "v_tx_mode_he_tb" , |
349 | "v_tx_mode_he_mu" , |
350 | "v_tx_mode_eht_su" , |
351 | "v_tx_mode_eht_trig" , |
352 | "v_tx_mode_eht_mu" , |
353 | "v_tx_bw_20" , |
354 | "v_tx_bw_40" , |
355 | "v_tx_bw_80" , |
356 | "v_tx_bw_160" , |
357 | "v_tx_bw_320" , |
358 | "v_tx_mcs_0" , |
359 | "v_tx_mcs_1" , |
360 | "v_tx_mcs_2" , |
361 | "v_tx_mcs_3" , |
362 | "v_tx_mcs_4" , |
363 | "v_tx_mcs_5" , |
364 | "v_tx_mcs_6" , |
365 | "v_tx_mcs_7" , |
366 | "v_tx_mcs_8" , |
367 | "v_tx_mcs_9" , |
368 | "v_tx_mcs_10" , |
369 | "v_tx_mcs_11" , |
370 | "v_tx_mcs_12" , |
371 | "v_tx_mcs_13" , |
372 | "v_tx_nss_1" , |
373 | "v_tx_nss_2" , |
374 | "v_tx_nss_3" , |
375 | "v_tx_nss_4" , |
376 | }; |
377 | |
378 | void mt792x_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
379 | u32 sset, u8 *data) |
380 | { |
381 | if (sset != ETH_SS_STATS) |
382 | return; |
383 | |
384 | memcpy(data, mt792x_gstrings_stats, sizeof(mt792x_gstrings_stats)); |
385 | |
386 | data += sizeof(mt792x_gstrings_stats); |
387 | page_pool_ethtool_stats_get_strings(data); |
388 | } |
389 | EXPORT_SYMBOL_GPL(mt792x_get_et_strings); |
390 | |
391 | int mt792x_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
392 | int sset) |
393 | { |
394 | if (sset != ETH_SS_STATS) |
395 | return 0; |
396 | |
397 | return ARRAY_SIZE(mt792x_gstrings_stats) + |
398 | page_pool_ethtool_stats_get_count(); |
399 | } |
400 | EXPORT_SYMBOL_GPL(mt792x_get_et_sset_count); |
401 | |
402 | static void |
403 | mt792x_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) |
404 | { |
405 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
406 | struct mt76_ethtool_worker_info *wi = wi_data; |
407 | |
408 | if (msta->vif->mt76.idx != wi->idx) |
409 | return; |
410 | |
411 | mt76_ethtool_worker(wi, stats: &msta->wcid.stats, eht: true); |
412 | } |
413 | |
414 | void mt792x_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
415 | struct ethtool_stats *stats, u64 *data) |
416 | { |
417 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
418 | int stats_size = ARRAY_SIZE(mt792x_gstrings_stats); |
419 | struct mt792x_phy *phy = mt792x_hw_phy(hw); |
420 | struct mt792x_dev *dev = phy->dev; |
421 | struct mt76_mib_stats *mib = &phy->mib; |
422 | struct mt76_ethtool_worker_info wi = { |
423 | .data = data, |
424 | .idx = mvif->mt76.idx, |
425 | }; |
426 | int i, ei = 0; |
427 | |
428 | mt792x_mutex_acquire(dev); |
429 | |
430 | mt792x_mac_update_mib_stats(phy); |
431 | |
432 | data[ei++] = mib->tx_ampdu_cnt; |
433 | data[ei++] = mib->tx_mpdu_attempts_cnt; |
434 | data[ei++] = mib->tx_mpdu_success_cnt; |
435 | data[ei++] = mib->tx_pkt_ebf_cnt; |
436 | data[ei++] = mib->tx_pkt_ibf_cnt; |
437 | |
438 | /* Tx ampdu stat */ |
439 | for (i = 0; i < 15; i++) |
440 | data[ei++] = phy->mt76->aggr_stats[i]; |
441 | |
442 | data[ei++] = phy->mib.ba_miss_cnt; |
443 | |
444 | /* Tx Beamformer monitor */ |
445 | data[ei++] = mib->tx_bf_ibf_ppdu_cnt; |
446 | data[ei++] = mib->tx_bf_ebf_ppdu_cnt; |
447 | |
448 | /* Tx Beamformer Rx feedback monitor */ |
449 | data[ei++] = mib->tx_bf_rx_fb_all_cnt; |
450 | data[ei++] = mib->tx_bf_rx_fb_he_cnt; |
451 | data[ei++] = mib->tx_bf_rx_fb_vht_cnt; |
452 | data[ei++] = mib->tx_bf_rx_fb_ht_cnt; |
453 | |
454 | /* Tx amsdu info (pack-count histogram) */ |
455 | for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) |
456 | data[ei++] = mib->tx_amsdu[i]; |
457 | |
458 | /* rx counters */ |
459 | data[ei++] = mib->rx_mpdu_cnt; |
460 | data[ei++] = mib->rx_ampdu_cnt; |
461 | data[ei++] = mib->rx_ampdu_bytes_cnt; |
462 | data[ei++] = mib->rx_ba_cnt; |
463 | |
464 | /* Add values for all stations owned by this vif */ |
465 | wi.initial_stat_idx = ei; |
466 | ieee80211_iterate_stations_atomic(hw, iterator: mt792x_ethtool_worker, data: &wi); |
467 | |
468 | mt792x_mutex_release(dev); |
469 | |
470 | if (!wi.sta_count) |
471 | return; |
472 | |
473 | ei += wi.worker_stat_count; |
474 | |
475 | mt76_ethtool_page_pool_stats(dev: &dev->mt76, data: &data[ei], index: &ei); |
476 | stats_size += page_pool_ethtool_stats_get_count(); |
477 | |
478 | if (ei != stats_size) |
479 | dev_err(dev->mt76.dev, "ei: %d SSTATS_LEN: %d" , ei, |
480 | stats_size); |
481 | } |
482 | EXPORT_SYMBOL_GPL(mt792x_get_et_stats); |
483 | |
484 | void mt792x_sta_statistics(struct ieee80211_hw *hw, |
485 | struct ieee80211_vif *vif, |
486 | struct ieee80211_sta *sta, |
487 | struct station_info *sinfo) |
488 | { |
489 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
490 | struct rate_info *txrate = &msta->wcid.rate; |
491 | |
492 | if (!txrate->legacy && !txrate->flags) |
493 | return; |
494 | |
495 | if (txrate->legacy) { |
496 | sinfo->txrate.legacy = txrate->legacy; |
497 | } else { |
498 | sinfo->txrate.mcs = txrate->mcs; |
499 | sinfo->txrate.nss = txrate->nss; |
500 | sinfo->txrate.bw = txrate->bw; |
501 | sinfo->txrate.he_gi = txrate->he_gi; |
502 | sinfo->txrate.he_dcm = txrate->he_dcm; |
503 | sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; |
504 | } |
505 | sinfo->tx_failed = msta->wcid.stats.tx_failed; |
506 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); |
507 | |
508 | sinfo->tx_retries = msta->wcid.stats.tx_retries; |
509 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); |
510 | |
511 | sinfo->txrate.flags = txrate->flags; |
512 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); |
513 | |
514 | sinfo->ack_signal = (s8)msta->ack_signal; |
515 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); |
516 | |
517 | sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(e: &msta->avg_ack_signal); |
518 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); |
519 | } |
520 | EXPORT_SYMBOL_GPL(mt792x_sta_statistics); |
521 | |
522 | void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) |
523 | { |
524 | struct mt792x_phy *phy = mt792x_hw_phy(hw); |
525 | struct mt792x_dev *dev = phy->dev; |
526 | |
527 | mt792x_mutex_acquire(dev); |
528 | |
529 | phy->coverage_class = max_t(s16, coverage_class, 0); |
530 | mt792x_mac_set_timeing(phy); |
531 | |
532 | mt792x_mutex_release(dev); |
533 | } |
534 | EXPORT_SYMBOL_GPL(mt792x_set_coverage_class); |
535 | |
536 | int mt792x_init_wiphy(struct ieee80211_hw *hw) |
537 | { |
538 | struct mt792x_phy *phy = mt792x_hw_phy(hw); |
539 | struct mt792x_dev *dev = phy->dev; |
540 | struct wiphy *wiphy = hw->wiphy; |
541 | |
542 | hw->queues = 4; |
543 | if (dev->has_eht) { |
544 | hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT; |
545 | hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT; |
546 | } else { |
547 | hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; |
548 | hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; |
549 | } |
550 | hw->netdev_features = NETIF_F_RXCSUM; |
551 | |
552 | hw->radiotap_timestamp.units_pos = |
553 | IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; |
554 | |
555 | phy->slottime = 9; |
556 | |
557 | hw->sta_data_size = sizeof(struct mt792x_sta); |
558 | hw->vif_data_size = sizeof(struct mt792x_vif); |
559 | |
560 | if (dev->fw_features & MT792x_FW_CAP_CNM) { |
561 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
562 | wiphy->iface_combinations = if_comb_chanctx; |
563 | wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_chanctx); |
564 | } else { |
565 | wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
566 | wiphy->iface_combinations = if_comb; |
567 | wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); |
568 | } |
569 | wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP | |
570 | WIPHY_FLAG_4ADDR_STATION); |
571 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
572 | BIT(NL80211_IFTYPE_AP) | |
573 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
574 | BIT(NL80211_IFTYPE_P2P_GO); |
575 | wiphy->max_remain_on_channel_duration = 5000; |
576 | wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; |
577 | wiphy->max_scan_ssids = 4; |
578 | wiphy->max_sched_scan_plan_interval = |
579 | MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL; |
580 | wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; |
581 | wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; |
582 | wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH; |
583 | wiphy->max_sched_scan_reqs = 1; |
584 | wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | |
585 | WIPHY_FLAG_SPLIT_SCAN_6GHZ; |
586 | |
587 | wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | |
588 | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; |
589 | wiphy_ext_feature_set(wiphy, ftidx: NL80211_EXT_FEATURE_SET_SCAN_DWELL); |
590 | wiphy_ext_feature_set(wiphy, ftidx: NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); |
591 | wiphy_ext_feature_set(wiphy, ftidx: NL80211_EXT_FEATURE_BEACON_RATE_HT); |
592 | wiphy_ext_feature_set(wiphy, ftidx: NL80211_EXT_FEATURE_BEACON_RATE_VHT); |
593 | wiphy_ext_feature_set(wiphy, ftidx: NL80211_EXT_FEATURE_BEACON_RATE_HE); |
594 | wiphy_ext_feature_set(wiphy, ftidx: NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); |
595 | wiphy_ext_feature_set(wiphy, ftidx: NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); |
596 | |
597 | ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); |
598 | ieee80211_hw_set(hw, HAS_RATE_CONTROL); |
599 | ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); |
600 | ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); |
601 | ieee80211_hw_set(hw, WANT_MONITOR_VIF); |
602 | ieee80211_hw_set(hw, SUPPORTS_PS); |
603 | ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); |
604 | ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); |
605 | ieee80211_hw_set(hw, CONNECTION_MONITOR); |
606 | |
607 | if (dev->pm.enable) |
608 | ieee80211_hw_set(hw, CONNECTION_MONITOR); |
609 | |
610 | hw->max_tx_fragments = 4; |
611 | |
612 | return 0; |
613 | } |
614 | EXPORT_SYMBOL_GPL(mt792x_init_wiphy); |
615 | |
616 | static u8 |
617 | mt792x_get_offload_capability(struct device *dev, const char *fw_wm) |
618 | { |
619 | const struct mt76_connac2_fw_trailer *hdr; |
620 | struct mt792x_realease_info *rel_info; |
621 | const struct firmware *fw; |
622 | int ret, i, offset = 0; |
623 | const u8 *data, *end; |
624 | u8 offload_caps = 0; |
625 | |
626 | ret = request_firmware(fw: &fw, name: fw_wm, device: dev); |
627 | if (ret) |
628 | return ret; |
629 | |
630 | if (!fw || !fw->data || fw->size < sizeof(*hdr)) { |
631 | dev_err(dev, "Invalid firmware\n" ); |
632 | goto out; |
633 | } |
634 | |
635 | data = fw->data; |
636 | hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); |
637 | |
638 | for (i = 0; i < hdr->n_region; i++) { |
639 | const struct mt76_connac2_fw_region *region; |
640 | |
641 | region = (const void *)((const u8 *)hdr - |
642 | (hdr->n_region - i) * sizeof(*region)); |
643 | offset += le32_to_cpu(region->len); |
644 | } |
645 | |
646 | data += offset + 16; |
647 | rel_info = (struct mt792x_realease_info *)data; |
648 | data += sizeof(*rel_info); |
649 | end = data + le16_to_cpu(rel_info->len); |
650 | |
651 | while (data < end) { |
652 | rel_info = (struct mt792x_realease_info *)data; |
653 | data += sizeof(*rel_info); |
654 | |
655 | if (rel_info->tag == MT792x_FW_TAG_FEATURE) { |
656 | struct mt792x_fw_features *features; |
657 | |
658 | features = (struct mt792x_fw_features *)data; |
659 | offload_caps = features->data; |
660 | break; |
661 | } |
662 | |
663 | data += le16_to_cpu(rel_info->len) + rel_info->pad_len; |
664 | } |
665 | |
666 | out: |
667 | release_firmware(fw); |
668 | |
669 | return offload_caps; |
670 | } |
671 | |
672 | struct ieee80211_ops * |
673 | mt792x_get_mac80211_ops(struct device *dev, |
674 | const struct ieee80211_ops *mac80211_ops, |
675 | void *drv_data, u8 *fw_features) |
676 | { |
677 | struct ieee80211_ops *ops; |
678 | |
679 | ops = devm_kmemdup(dev, src: mac80211_ops, len: sizeof(struct ieee80211_ops), |
680 | GFP_KERNEL); |
681 | if (!ops) |
682 | return NULL; |
683 | |
684 | *fw_features = mt792x_get_offload_capability(dev, fw_wm: drv_data); |
685 | if (!(*fw_features & MT792x_FW_CAP_CNM)) { |
686 | ops->remain_on_channel = NULL; |
687 | ops->cancel_remain_on_channel = NULL; |
688 | ops->add_chanctx = ieee80211_emulate_add_chanctx; |
689 | ops->remove_chanctx = ieee80211_emulate_remove_chanctx; |
690 | ops->change_chanctx = ieee80211_emulate_change_chanctx; |
691 | ops->switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx; |
692 | ops->assign_vif_chanctx = NULL; |
693 | ops->unassign_vif_chanctx = NULL; |
694 | ops->mgd_prepare_tx = NULL; |
695 | ops->mgd_complete_tx = NULL; |
696 | } |
697 | return ops; |
698 | } |
699 | EXPORT_SYMBOL_GPL(mt792x_get_mac80211_ops); |
700 | |
701 | int mt792x_init_wcid(struct mt792x_dev *dev) |
702 | { |
703 | int idx; |
704 | |
705 | /* Beacon and mgmt frames should occupy wcid 0 */ |
706 | idx = mt76_wcid_alloc(mask: dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); |
707 | if (idx) |
708 | return -ENOSPC; |
709 | |
710 | dev->mt76.global_wcid.idx = idx; |
711 | dev->mt76.global_wcid.hw_key_idx = -1; |
712 | dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; |
713 | rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); |
714 | |
715 | return 0; |
716 | } |
717 | EXPORT_SYMBOL_GPL(mt792x_init_wcid); |
718 | |
719 | int mt792x_mcu_drv_pmctrl(struct mt792x_dev *dev) |
720 | { |
721 | struct mt76_phy *mphy = &dev->mt76.phy; |
722 | struct mt76_connac_pm *pm = &dev->pm; |
723 | int err = 0; |
724 | |
725 | mutex_lock(&pm->mutex); |
726 | |
727 | if (!test_bit(MT76_STATE_PM, &mphy->state)) |
728 | goto out; |
729 | |
730 | err = __mt792x_mcu_drv_pmctrl(dev); |
731 | out: |
732 | mutex_unlock(lock: &pm->mutex); |
733 | |
734 | if (err) |
735 | mt792x_reset(mdev: &dev->mt76); |
736 | |
737 | return err; |
738 | } |
739 | EXPORT_SYMBOL_GPL(mt792x_mcu_drv_pmctrl); |
740 | |
741 | int mt792x_mcu_fw_pmctrl(struct mt792x_dev *dev) |
742 | { |
743 | struct mt76_phy *mphy = &dev->mt76.phy; |
744 | struct mt76_connac_pm *pm = &dev->pm; |
745 | int err = 0; |
746 | |
747 | mutex_lock(&pm->mutex); |
748 | |
749 | if (mt76_connac_skip_fw_pmctrl(phy: mphy, pm)) |
750 | goto out; |
751 | |
752 | err = __mt792x_mcu_fw_pmctrl(dev); |
753 | out: |
754 | mutex_unlock(lock: &pm->mutex); |
755 | |
756 | if (err) |
757 | mt792x_reset(mdev: &dev->mt76); |
758 | |
759 | return err; |
760 | } |
761 | EXPORT_SYMBOL_GPL(mt792x_mcu_fw_pmctrl); |
762 | |
763 | int __mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev) |
764 | { |
765 | int i, err = 0; |
766 | |
767 | for (i = 0; i < MT792x_DRV_OWN_RETRY_COUNT; i++) { |
768 | mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); |
769 | if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL, |
770 | PCIE_LPCR_HOST_OWN_SYNC, 0, 50, 1)) |
771 | break; |
772 | } |
773 | |
774 | if (i == MT792x_DRV_OWN_RETRY_COUNT) { |
775 | dev_err(dev->mt76.dev, "driver own failed\n" ); |
776 | err = -EIO; |
777 | } |
778 | |
779 | return err; |
780 | } |
781 | EXPORT_SYMBOL_GPL(__mt792xe_mcu_drv_pmctrl); |
782 | |
783 | int mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev) |
784 | { |
785 | struct mt76_phy *mphy = &dev->mt76.phy; |
786 | struct mt76_connac_pm *pm = &dev->pm; |
787 | int err; |
788 | |
789 | err = __mt792xe_mcu_drv_pmctrl(dev); |
790 | if (err < 0) |
791 | goto out; |
792 | |
793 | mt792x_wpdma_reinit_cond(dev); |
794 | clear_bit(nr: MT76_STATE_PM, addr: &mphy->state); |
795 | |
796 | pm->stats.last_wake_event = jiffies; |
797 | pm->stats.doze_time += pm->stats.last_wake_event - |
798 | pm->stats.last_doze_event; |
799 | out: |
800 | return err; |
801 | } |
802 | EXPORT_SYMBOL_GPL(mt792xe_mcu_drv_pmctrl); |
803 | |
804 | int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev) |
805 | { |
806 | struct mt76_phy *mphy = &dev->mt76.phy; |
807 | struct mt76_connac_pm *pm = &dev->pm; |
808 | int i; |
809 | |
810 | for (i = 0; i < MT792x_DRV_OWN_RETRY_COUNT; i++) { |
811 | mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN); |
812 | if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL, |
813 | PCIE_LPCR_HOST_OWN_SYNC, 4, 50, 1)) |
814 | break; |
815 | } |
816 | |
817 | if (i == MT792x_DRV_OWN_RETRY_COUNT) { |
818 | dev_err(dev->mt76.dev, "firmware own failed\n" ); |
819 | clear_bit(nr: MT76_STATE_PM, addr: &mphy->state); |
820 | return -EIO; |
821 | } |
822 | |
823 | pm->stats.last_doze_event = jiffies; |
824 | pm->stats.awake_time += pm->stats.last_doze_event - |
825 | pm->stats.last_wake_event; |
826 | |
827 | return 0; |
828 | } |
829 | EXPORT_SYMBOL_GPL(mt792xe_mcu_fw_pmctrl); |
830 | |
831 | int mt792x_load_firmware(struct mt792x_dev *dev) |
832 | { |
833 | int ret; |
834 | |
835 | ret = mt76_connac2_load_patch(dev: &dev->mt76, fw_name: mt792x_patch_name(dev)); |
836 | if (ret) |
837 | return ret; |
838 | |
839 | if (mt76_is_sdio(&dev->mt76)) { |
840 | /* activate again */ |
841 | ret = __mt792x_mcu_fw_pmctrl(dev); |
842 | if (!ret) |
843 | ret = __mt792x_mcu_drv_pmctrl(dev); |
844 | } |
845 | |
846 | ret = mt76_connac2_load_ram(dev: &dev->mt76, fw_wm: mt792x_ram_name(dev), NULL); |
847 | if (ret) |
848 | return ret; |
849 | |
850 | if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, |
851 | MT_TOP_MISC2_FW_N9_RDY, 1500)) { |
852 | dev_err(dev->mt76.dev, "Timeout for initializing firmware\n" ); |
853 | |
854 | return -EIO; |
855 | } |
856 | |
857 | #ifdef CONFIG_PM |
858 | dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; |
859 | #endif /* CONFIG_PM */ |
860 | |
861 | dev_dbg(dev->mt76.dev, "Firmware init done\n" ); |
862 | |
863 | return 0; |
864 | } |
865 | EXPORT_SYMBOL_GPL(mt792x_load_firmware); |
866 | |
867 | MODULE_DESCRIPTION("MediaTek MT792x core driver" ); |
868 | MODULE_LICENSE("Dual BSD/GPL" ); |
869 | MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>" ); |
870 | |