File Index
Files and directories
Sign in
FILE

mt792x_mac.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/mediatek/mt76/mt792x_mac.c C
  1// SPDX-License-Identifier: BSD-3-Clause-Clear
  2/* Copyright (C) 2023 MediaTek Inc. */
  3
  4#include <linux/module.h>
  5
  6#include "mt792x.h"
  7#include "mt792x_regs.h"
  8
  9void mt792x_mac_work(struct work_struct *work)
 10{
 11	struct mt792x_phy *phy;
 12	struct mt76_phy *mphy;
 13
 14	mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
 15					       mac_work.work);
 16	phy = mphy->priv;
 17
 18	mt792x_mutex_acquire(phy->dev);
 19
 20	mt76_update_survey(mphy);
 21	if (++mphy->mac_work_count == 2) {
 22		mphy->mac_work_count = 0;
 23
 24		mt792x_mac_update_mib_stats(phy);
 25	}
 26
 27	mt792x_mutex_release(phy->dev);
 28
 29	mt76_tx_status_check(mphy->dev, false);
 30	ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work,
 31				     MT792x_WATCHDOG_TIME);
 32}
 33EXPORT_SYMBOL_GPL(mt792x_mac_work);
 34
 35void mt792x_mac_set_timeing(struct mt792x_phy *phy)
 36{
 37	s16 coverage_class = phy->coverage_class;
 38	struct mt792x_dev *dev = phy->dev;
 39	u32 val, reg_offset;
 40	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
 41		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
 42	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
 43		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
 44	bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ;
 45	int sifs = is_2ghz ? 10 : 16, offset;
 46
 47	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
 48		return;
 49
 50	mt76_set(dev, MT_ARB_SCR(0),
 51		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
 52	udelay(1);
 53
 54	offset = 3 * coverage_class;
 55	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
 56		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
 57
 58	mt76_wr(dev, MT_TMAC_CDTR(0), cck + reg_offset);
 59	mt76_wr(dev, MT_TMAC_ODTR(0), ofdm + reg_offset);
 60	mt76_wr(dev, MT_TMAC_ICR0(0),
 61		FIELD_PREP(MT_IFS_EIFS, 360) |
 62		FIELD_PREP(MT_IFS_RIFS, 2) |
 63		FIELD_PREP(MT_IFS_SIFS, sifs) |
 64		FIELD_PREP(MT_IFS_SLOT, phy->slottime));
 65
 66	if (phy->slottime < 20 || !is_2ghz)
 67		val = MT792x_CFEND_RATE_DEFAULT;
 68	else
 69		val = MT792x_CFEND_RATE_11B;
 70
 71	mt76_rmw_field(dev, MT_AGG_ACR0(0), MT_AGG_ACR_CFEND_RATE, val);
 72	mt76_clear(dev, MT_ARB_SCR(0),
 73		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
 74}
 75EXPORT_SYMBOL_GPL(mt792x_mac_set_timeing);
 76
 77void mt792x_mac_update_mib_stats(struct mt792x_phy *phy)
 78{
 79	struct mt76_mib_stats *mib = &phy->mib;
 80	struct mt792x_dev *dev = phy->dev;
 81	int i, aggr0 = 0, aggr1;
 82	u32 val;
 83
 84	mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(0),
 85					   MT_MIB_SDR3_FCS_ERR_MASK);
 86	mib->ack_fail_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR3(0),
 87					    MT_MIB_ACK_FAIL_COUNT_MASK);
 88	mib->ba_miss_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR2(0),
 89					   MT_MIB_BA_FAIL_COUNT_MASK);
 90	mib->rts_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR0(0),
 91				       MT_MIB_RTS_COUNT_MASK);
 92	mib->rts_retries_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR1(0),
 93					       MT_MIB_RTS_FAIL_COUNT_MASK);
 94
 95	mib->tx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR12(0));
 96	mib->tx_mpdu_attempts_cnt += mt76_rr(dev, MT_MIB_SDR14(0));
 97	mib->tx_mpdu_success_cnt += mt76_rr(dev, MT_MIB_SDR15(0));
 98
 99	val = mt76_rr(dev, MT_MIB_SDR32(0));
100	mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR9_EBF_CNT_MASK, val);
101	mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR9_IBF_CNT_MASK, val);
102
103	val = mt76_rr(dev, MT_ETBF_TX_APP_CNT(0));
104	mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, val);
105	mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, val);
106
107	val = mt76_rr(dev, MT_ETBF_RX_FB_CNT(0));
108	mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, val);
109	mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, val);
110	mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, val);
111	mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, val);
112
113	mib->rx_mpdu_cnt += mt76_rr(dev, MT_MIB_SDR5(0));
114	mib->rx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR22(0));
115	mib->rx_ampdu_bytes_cnt += mt76_rr(dev, MT_MIB_SDR23(0));
116	mib->rx_ba_cnt += mt76_rr(dev, MT_MIB_SDR31(0));
117
118	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
119		val = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
120		mib->tx_amsdu[i] += val;
121		mib->tx_amsdu_cnt += val;
122	}
123
124	for (i = 0, aggr1 = aggr0 + 8; i < 4; i++) {
125		u32 val2;
126
127		val = mt76_rr(dev, MT_TX_AGG_CNT(0, i));
128		val2 = mt76_rr(dev, MT_TX_AGG_CNT2(0, i));
129
130		phy->mt76->aggr_stats[aggr0++] += val & 0xffff;
131		phy->mt76->aggr_stats[aggr0++] += val >> 16;
132		phy->mt76->aggr_stats[aggr1++] += val2 & 0xffff;
133		phy->mt76->aggr_stats[aggr1++] += val2 >> 16;
134	}
135}
136EXPORT_SYMBOL_GPL(mt792x_mac_update_mib_stats);
137
138struct mt76_wcid *mt792x_rx_get_wcid(struct mt792x_dev *dev, u16 idx,
139				     bool unicast)
140{
141	struct mt792x_link_sta *link;
142	struct mt792x_sta *sta;
143	struct mt76_wcid *wcid;
144
145	wcid = mt76_wcid_ptr(dev, idx);
146	if (unicast || !wcid)
147		return wcid;
148
149	if (!wcid->sta)
150		return NULL;
151
152	link = container_of(wcid, struct mt792x_link_sta, wcid);
153	sta = link->sta;
154	if (!sta->vif)
155		return NULL;
156
157	return &sta->vif->sta.deflink.wcid;
158}
159EXPORT_SYMBOL_GPL(mt792x_rx_get_wcid);
160
161static void
162mt792x_mac_rssi_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
163{
164	struct sk_buff *skb = priv;
165	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
166	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
167	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
168
169	if (status->signal > 0)
170		return;
171
172	if (!ether_addr_equal(vif->addr, hdr->addr1))
173		return;
174
175	ewma_rssi_add(&mvif->bss_conf.rssi, -status->signal);
176}
177
178void mt792x_mac_assoc_rssi(struct mt792x_dev *dev, struct sk_buff *skb)
179{
180	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
181
182	if (!ieee80211_is_assoc_resp(hdr->frame_control) &&
183	    !ieee80211_is_auth(hdr->frame_control))
184		return;
185
186	ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
187		IEEE80211_IFACE_ITER_RESUME_ALL,
188		mt792x_mac_rssi_iter, skb);
189}
190EXPORT_SYMBOL_GPL(mt792x_mac_assoc_rssi);
191
192void mt792x_mac_reset_counters(struct mt792x_phy *phy)
193{
194	struct mt792x_dev *dev = phy->dev;
195	int i;
196
197	for (i = 0; i < 4; i++) {
198		mt76_rr(dev, MT_TX_AGG_CNT(0, i));
199		mt76_rr(dev, MT_TX_AGG_CNT2(0, i));
200	}
201
202	dev->mt76.phy.survey_time = ktime_get_boottime();
203	memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
204
205	/* reset airtime counters */
206	mt76_rr(dev, MT_MIB_SDR9(0));
207	mt76_rr(dev, MT_MIB_SDR36(0));
208	mt76_rr(dev, MT_MIB_SDR37(0));
209
210	mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
211	mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
212}
213EXPORT_SYMBOL_GPL(mt792x_mac_reset_counters);
214
215static u8
216mt792x_phy_get_nf(struct mt792x_phy *phy, int idx)
217{
218	return 0;
219}
220
221static void
222mt792x_phy_update_channel(struct mt76_phy *mphy, int idx)
223{
224	struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76);
225	struct mt792x_phy *phy = mphy->priv;
226	struct mt76_channel_state *state;
227	u64 busy_time, tx_time, rx_time, obss_time;
228	int nf;
229
230	busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx),
231				   MT_MIB_SDR9_BUSY_MASK);
232	tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx),
233				 MT_MIB_SDR36_TXTIME_MASK);
234	rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx),
235				 MT_MIB_SDR37_RXTIME_MASK);
236	obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx),
237				   MT_MIB_OBSSTIME_MASK);
238
239	nf = mt792x_phy_get_nf(phy, idx);
240	if (!phy->noise)
241		phy->noise = nf << 4;
242	else if (nf)
243		phy->noise += nf - (phy->noise >> 4);
244
245	state = mphy->chan_state;
246	state->cc_busy += busy_time;
247	state->cc_tx += tx_time;
248	state->cc_rx += rx_time + obss_time;
249	state->cc_bss_rx += rx_time;
250	state->noise = -(phy->noise >> 4);
251}
252
253void mt792x_update_channel(struct mt76_phy *mphy)
254{
255	struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76);
256
257	if (mt76_connac_pm_wake(mphy, &dev->pm))
258		return;
259
260	mt792x_phy_update_channel(mphy, 0);
261	/* reset obss airtime */
262	mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR);
263	mt76_connac_power_save_sched(mphy, &dev->pm);
264}
265EXPORT_SYMBOL_GPL(mt792x_update_channel);
266
267void mt792x_reset(struct mt76_dev *mdev)
268{
269	struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
270	struct mt76_connac_pm *pm = &dev->pm;
271
272	if (!dev->hw_init_done)
273		return;
274
275	if (dev->hw_full_reset)
276		return;
277
278	if (pm->suspended)
279		return;
280
281	queue_work(dev->mt76.wq, &dev->reset_work);
282}
283EXPORT_SYMBOL_GPL(mt792x_reset);
284
285void mt792x_mac_init_band(struct mt792x_dev *dev, u8 band)
286{
287	u32 mask, set;
288
289	mt76_rmw_field(dev, MT_TMAC_CTCR0(band),
290		       MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
291	mt76_set(dev, MT_TMAC_CTCR0(band),
292		 MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN |
293		 MT_TMAC_CTCR0_INS_DDLMT_EN);
294
295	mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
296	mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
297
298	/* enable MIB tx-rx time reporting */
299	mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_TXDUR_EN);
300	mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_RXDUR_EN);
301
302	mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
303	/* disable rx rate report by default due to hw issues */
304	mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
305
306	/* filter out non-resp frames and get instantaneous signal reporting */
307	mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM;
308	set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) |
309	      FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3);
310	mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
311}
312EXPORT_SYMBOL_GPL(mt792x_mac_init_band);
313
314void mt792x_pm_wake_work(struct work_struct *work)
315{
316	struct mt792x_dev *dev;
317	struct mt76_phy *mphy;
318
319	dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev,
320						pm.wake_work);
321	mphy = dev->phy.mt76;
322
323	if (!mt792x_mcu_drv_pmctrl(dev)) {
324		struct mt76_dev *mdev = &dev->mt76;
325		int i;
326
327		if (mt76_is_sdio(mdev)) {
328			mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
329			mt76_worker_schedule(&mdev->sdio.txrx_worker);
330		} else {
331			local_bh_disable();
332			mt76_for_each_q_rx(mdev, i)
333				napi_schedule(&mdev->napi[i]);
334			local_bh_enable();
335			mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
336			mt76_connac_tx_cleanup(mdev);
337		}
338		if (test_bit(MT76_STATE_RUNNING, &mphy->state))
339			ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
340						     MT792x_WATCHDOG_TIME);
341	}
342
343	ieee80211_wake_queues(mphy->hw);
344	wake_up(&dev->pm.wait);
345}
346EXPORT_SYMBOL_GPL(mt792x_pm_wake_work);
347
348void mt792x_pm_power_save_work(struct work_struct *work)
349{
350	struct mt792x_dev *dev;
351	unsigned long delta;
352	struct mt76_phy *mphy;
353
354	dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev,
355						pm.ps_work.work);
356	mphy = dev->phy.mt76;
357
358	delta = dev->pm.idle_timeout;
359	if (test_bit(MT76_HW_SCANNING, &mphy->state) ||
360	    test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) ||
361	    dev->fw_assert)
362		goto out;
363
364	if (mutex_is_locked(&dev->mt76.mutex))
365		/* if mt76 mutex is held we should not put the device
366		 * to sleep since we are currently accessing device
367		 * register map. We need to wait for the next power_save
368		 * trigger.
369		 */
370		goto out;
371
372	if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
373		delta = dev->pm.last_activity + delta - jiffies;
374		goto out;
375	}
376
377	if (!mt792x_mcu_fw_pmctrl(dev)) {
378		cancel_delayed_work_sync(&mphy->mac_work);
379		return;
380	}
381out:
382	queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
383}
384EXPORT_SYMBOL_GPL(mt792x_pm_power_save_work);
~/ Read-only file preview.