xref: /openbmc/linux/drivers/net/wireless/mediatek/mt76/mt7615/main.c (revision 26d0dfbb16fcb17d128a79dc70f3020ea6992af0)
104b8e659SRyder Lee // SPDX-License-Identifier: ISC
204b8e659SRyder Lee /* Copyright (C) 2019 MediaTek Inc.
304b8e659SRyder Lee  *
404b8e659SRyder Lee  * Author: Roy Luo <royluo@google.com>
504b8e659SRyder Lee  *         Ryder Lee <ryder.lee@mediatek.com>
604b8e659SRyder Lee  *         Felix Fietkau <nbd@nbd.name>
7e90354e0SLorenzo Bianconi  *         Lorenzo Bianconi <lorenzo@kernel.org>
804b8e659SRyder Lee  */
904b8e659SRyder Lee 
1004b8e659SRyder Lee #include <linux/etherdevice.h>
1104b8e659SRyder Lee #include <linux/module.h>
1204b8e659SRyder Lee #include "mt7615.h"
134fe9218cSRyder Lee #include "mcu.h"
1404b8e659SRyder Lee 
mt7615_dev_running(struct mt7615_dev * dev)15fdd2e570SFelix Fietkau static bool mt7615_dev_running(struct mt7615_dev *dev)
16fdd2e570SFelix Fietkau {
17fdd2e570SFelix Fietkau 	struct mt7615_phy *phy;
18fdd2e570SFelix Fietkau 
19fdd2e570SFelix Fietkau 	if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
20fdd2e570SFelix Fietkau 		return true;
21fdd2e570SFelix Fietkau 
22fdd2e570SFelix Fietkau 	phy = mt7615_ext_phy(dev);
23fdd2e570SFelix Fietkau 
24fdd2e570SFelix Fietkau 	return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
25fdd2e570SFelix Fietkau }
26fdd2e570SFelix Fietkau 
mt7615_start(struct ieee80211_hw * hw)2704b8e659SRyder Lee static int mt7615_start(struct ieee80211_hw *hw)
2804b8e659SRyder Lee {
29fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
30fdd2e570SFelix Fietkau 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
31a27238a0SLorenzo Bianconi 	unsigned long timeout;
32fdd2e570SFelix Fietkau 	bool running;
33c3800cc2SRyder Lee 	int ret;
34fdd2e570SFelix Fietkau 
35c3c25d09SFelix Fietkau 	if (!mt7615_wait_for_mcu_init(dev))
36c3c25d09SFelix Fietkau 		return -EIO;
37c3c25d09SFelix Fietkau 
38adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
39fdd2e570SFelix Fietkau 
40fdd2e570SFelix Fietkau 	running = mt7615_dev_running(dev);
41b0b5426eSFelix Fietkau 
42b0b5426eSFelix Fietkau 	if (!running) {
43c3800cc2SRyder Lee 		ret = mt7615_mcu_set_pm(dev, 0, 0);
44c3800cc2SRyder Lee 		if (ret)
45c3800cc2SRyder Lee 			goto out;
46c3800cc2SRyder Lee 
47c3800cc2SRyder Lee 		ret = mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, true, false);
48c3800cc2SRyder Lee 		if (ret)
49c3800cc2SRyder Lee 			goto out;
50c3800cc2SRyder Lee 
51e5051965SFelix Fietkau 		mt7615_mac_enable_nf(dev, 0);
52b0b5426eSFelix Fietkau 	}
53b0b5426eSFelix Fietkau 
54b0b5426eSFelix Fietkau 	if (phy != &dev->phy) {
55c3800cc2SRyder Lee 		ret = mt7615_mcu_set_pm(dev, 1, 0);
56c3800cc2SRyder Lee 		if (ret)
57c3800cc2SRyder Lee 			goto out;
58c3800cc2SRyder Lee 
59c3800cc2SRyder Lee 		ret = mt76_connac_mcu_set_mac_enable(&dev->mt76, 1, true, false);
60c3800cc2SRyder Lee 		if (ret)
61c3800cc2SRyder Lee 			goto out;
62c3800cc2SRyder Lee 
63e5051965SFelix Fietkau 		mt7615_mac_enable_nf(dev, 1);
64b0b5426eSFelix Fietkau 	}
65b0b5426eSFelix Fietkau 
66c3800cc2SRyder Lee 	if (mt7615_firmware_offload(dev)) {
67c3800cc2SRyder Lee 		ret = mt76_connac_mcu_set_channel_domain(phy->mt76);
68c3800cc2SRyder Lee 		if (ret)
69c3800cc2SRyder Lee 			goto out;
7018369a4fSLorenzo Bianconi 
7118369a4fSLorenzo Bianconi 		ret = mt76_connac_mcu_set_rate_txpower(phy->mt76);
7218369a4fSLorenzo Bianconi 		if (ret)
7318369a4fSLorenzo Bianconi 			goto out;
74c3800cc2SRyder Lee 	}
75d0e274afSLorenzo Bianconi 
76e6d2070dSLorenzo Bianconi 	ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH));
77c3800cc2SRyder Lee 	if (ret)
78c3800cc2SRyder Lee 		goto out;
794fe9218cSRyder Lee 
80fdd2e570SFelix Fietkau 	set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
81fdd2e570SFelix Fietkau 
82a27238a0SLorenzo Bianconi 	timeout = mt7615_get_macwork_timeout(dev);
83a27238a0SLorenzo Bianconi 	ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout);
8404b8e659SRyder Lee 
854fcf6e77SLorenzo Bianconi 	if (!running)
861b9ba30eSLorenzo Bianconi 		mt7615_mac_reset_counters(phy);
874fcf6e77SLorenzo Bianconi 
88c3800cc2SRyder Lee out:
89adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
90fdd2e570SFelix Fietkau 
91c3800cc2SRyder Lee 	return ret;
9204b8e659SRyder Lee }
9304b8e659SRyder Lee 
mt7615_stop(struct ieee80211_hw * hw)9404b8e659SRyder Lee static void mt7615_stop(struct ieee80211_hw *hw)
9504b8e659SRyder Lee {
96fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
97fdd2e570SFelix Fietkau 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
9804b8e659SRyder Lee 
99a782f8bfSLorenzo Bianconi 	cancel_delayed_work_sync(&phy->mt76->mac_work);
1007307f296SLorenzo Bianconi 	del_timer_sync(&phy->roc_timer);
1017307f296SLorenzo Bianconi 	cancel_work_sync(&phy->roc_work);
1024fcf6e77SLorenzo Bianconi 
103de5ff3c9SLorenzo Bianconi 	cancel_delayed_work_sync(&dev->pm.ps_work);
10408523a2aSLorenzo Bianconi 	cancel_work_sync(&dev->pm.wake_work);
10508523a2aSLorenzo Bianconi 
1061755f6adSLorenzo Bianconi 	mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
1072b8cdfb2SLorenzo Bianconi 
108adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
109fdd2e570SFelix Fietkau 
110c918c74dSShayne Chen 	mt76_testmode_reset(phy->mt76, true);
1114f0bce1cSFelix Fietkau 
112fdd2e570SFelix Fietkau 	clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
113fcdfc29eSLorenzo Bianconi 	cancel_delayed_work_sync(&phy->scan_work);
114b0b5426eSFelix Fietkau 
115b0b5426eSFelix Fietkau 	if (phy != &dev->phy) {
116062c3699SLorenzo Bianconi 		mt7615_mcu_set_pm(dev, 1, 1);
117d0e274afSLorenzo Bianconi 		mt76_connac_mcu_set_mac_enable(&dev->mt76, 1, false, false);
118b0b5426eSFelix Fietkau 	}
119b0b5426eSFelix Fietkau 
120b0b5426eSFelix Fietkau 	if (!mt7615_dev_running(dev)) {
121062c3699SLorenzo Bianconi 		mt7615_mcu_set_pm(dev, 0, 1);
122d0e274afSLorenzo Bianconi 		mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false);
123b0b5426eSFelix Fietkau 	}
124b0b5426eSFelix Fietkau 
125adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
12604b8e659SRyder Lee }
12704b8e659SRyder Lee 
get_free_idx(u32 mask,u8 start,u8 end)128d8d59f66SRyder Lee static inline int get_free_idx(u32 mask, u8 start, u8 end)
129d8d59f66SRyder Lee {
130d8d59f66SRyder Lee 	return ffs(~mask & GENMASK(end, start));
131d8d59f66SRyder Lee }
132d8d59f66SRyder Lee 
get_omac_idx(enum nl80211_iftype type,u64 mask)133d8d59f66SRyder Lee static int get_omac_idx(enum nl80211_iftype type, u64 mask)
13404b8e659SRyder Lee {
13504b8e659SRyder Lee 	int i;
13604b8e659SRyder Lee 
13704b8e659SRyder Lee 	switch (type) {
138d8d59f66SRyder Lee 	case NL80211_IFTYPE_STATION:
139d8d59f66SRyder Lee 		/* prefer hw bssid slot 1-3 */
140d8d59f66SRyder Lee 		i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3);
141d8d59f66SRyder Lee 		if (i)
142d8d59f66SRyder Lee 			return i - 1;
143d8d59f66SRyder Lee 
144d8d59f66SRyder Lee 		/* next, try to find a free repeater entry for the sta */
145d8d59f66SRyder Lee 		i = get_free_idx(mask >> REPEATER_BSSID_START, 0,
146d8d59f66SRyder Lee 				 REPEATER_BSSID_MAX - REPEATER_BSSID_START);
147d8d59f66SRyder Lee 		if (i)
148d8d59f66SRyder Lee 			return i + 32 - 1;
149d8d59f66SRyder Lee 
150d8d59f66SRyder Lee 		i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
151d8d59f66SRyder Lee 		if (i)
152d8d59f66SRyder Lee 			return i - 1;
153d8d59f66SRyder Lee 
15404b8e659SRyder Lee 		if (~mask & BIT(HW_BSSID_0))
15504b8e659SRyder Lee 			return HW_BSSID_0;
15604b8e659SRyder Lee 
15704b8e659SRyder Lee 		break;
158753453afSNick Hainke 	case NL80211_IFTYPE_ADHOC:
159753453afSNick Hainke 	case NL80211_IFTYPE_MESH_POINT:
160d8d59f66SRyder Lee 	case NL80211_IFTYPE_MONITOR:
161d8d59f66SRyder Lee 	case NL80211_IFTYPE_AP:
162d8d59f66SRyder Lee 		/* ap uses hw bssid 0 and ext bssid */
163d8d59f66SRyder Lee 		if (~mask & BIT(HW_BSSID_0))
164d8d59f66SRyder Lee 			return HW_BSSID_0;
165d8d59f66SRyder Lee 
166d8d59f66SRyder Lee 		i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
167d8d59f66SRyder Lee 		if (i)
168d8d59f66SRyder Lee 			return i - 1;
16904b8e659SRyder Lee 
17004b8e659SRyder Lee 		break;
17104b8e659SRyder Lee 	default:
17204b8e659SRyder Lee 		WARN_ON(1);
17304b8e659SRyder Lee 		break;
1745d1ad7d7SYueHaibing 	}
17504b8e659SRyder Lee 
17604b8e659SRyder Lee 	return -1;
17704b8e659SRyder Lee }
17804b8e659SRyder Lee 
mt7615_add_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)17904b8e659SRyder Lee static int mt7615_add_interface(struct ieee80211_hw *hw,
18004b8e659SRyder Lee 				struct ieee80211_vif *vif)
18104b8e659SRyder Lee {
18204b8e659SRyder Lee 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
183fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
184fdd2e570SFelix Fietkau 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
18504b8e659SRyder Lee 	struct mt76_txq *mtxq;
186fdd2e570SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
18704b8e659SRyder Lee 	int idx, ret = 0;
18804b8e659SRyder Lee 
189adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
19004b8e659SRyder Lee 
191c918c74dSShayne Chen 	mt76_testmode_reset(phy->mt76, true);
1924f0bce1cSFelix Fietkau 
1934f0bce1cSFelix Fietkau 	if (vif->type == NL80211_IFTYPE_MONITOR &&
1944f0bce1cSFelix Fietkau 	    is_zero_ether_addr(vif->addr))
1954f0bce1cSFelix Fietkau 		phy->monitor_vif = vif;
1964f0bce1cSFelix Fietkau 
197b619e013SEvelyn Tsai 	mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask);
19885d96704SLorenzo Bianconi 	if (mvif->mt76.idx >= MT7615_MAX_INTERFACES) {
19904b8e659SRyder Lee 		ret = -ENOSPC;
20004b8e659SRyder Lee 		goto out;
20104b8e659SRyder Lee 	}
20204b8e659SRyder Lee 
203b1571a0eSDan Carpenter 	idx = get_omac_idx(vif->type, dev->omac_mask);
204b1571a0eSDan Carpenter 	if (idx < 0) {
20504b8e659SRyder Lee 		ret = -ENOSPC;
20604b8e659SRyder Lee 		goto out;
20704b8e659SRyder Lee 	}
20885d96704SLorenzo Bianconi 	mvif->mt76.omac_idx = idx;
20904b8e659SRyder Lee 
21085d96704SLorenzo Bianconi 	mvif->mt76.band_idx = ext_phy;
21170fb0287SFelix Fietkau 	mvif->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP;
21270fb0287SFelix Fietkau 	if (ext_phy)
21370fb0287SFelix Fietkau 		mvif->mt76.wmm_idx += 2;
21404b8e659SRyder Lee 
215b619e013SEvelyn Tsai 	dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx);
21685d96704SLorenzo Bianconi 	dev->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
21785d96704SLorenzo Bianconi 	phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
218ac3ef85cSFelix Fietkau 
219c3800cc2SRyder Lee 	ret = mt7615_mcu_set_dbdc(dev);
220c3800cc2SRyder Lee 	if (ret)
221c3800cc2SRyder Lee 		goto out;
222ac3ef85cSFelix Fietkau 
22385d96704SLorenzo Bianconi 	idx = MT7615_WTBL_RESERVED - mvif->mt76.idx;
224b2c2f029SLorenzo Bianconi 
2259d599f2dSLorenzo Bianconi 	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
22604b8e659SRyder Lee 	mvif->sta.wcid.idx = idx;
227a1a99d7bSLorenzo Bianconi 	mvif->sta.wcid.phy_idx = mvif->mt76.band_idx;
22804b8e659SRyder Lee 	mvif->sta.wcid.hw_key_idx = -1;
229*d2defcddSFelix Fietkau 	mt76_wcid_init(&mvif->sta.wcid);
230bd1e3e7bSLorenzo Bianconi 
231b2c2f029SLorenzo Bianconi 	mt7615_mac_wtbl_update(dev, idx,
232b2c2f029SLorenzo Bianconi 			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
23304b8e659SRyder Lee 
23404b8e659SRyder Lee 	rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
2358e2ad48eSFelix Fietkau 	if (vif->txq) {
23604b8e659SRyder Lee 		mtxq = (struct mt76_txq *)vif->txq->drv_priv;
23751fb1278SFelix Fietkau 		mtxq->wcid = idx;
2388e2ad48eSFelix Fietkau 	}
23904b8e659SRyder Lee 
240d0e274afSLorenzo Bianconi 	ret = mt7615_mcu_add_dev_info(phy, vif, true);
24104b8e659SRyder Lee out:
242adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
24304b8e659SRyder Lee 
24404b8e659SRyder Lee 	return ret;
24504b8e659SRyder Lee }
24604b8e659SRyder Lee 
mt7615_remove_interface(struct ieee80211_hw * hw,struct ieee80211_vif * vif)24704b8e659SRyder Lee static void mt7615_remove_interface(struct ieee80211_hw *hw,
24804b8e659SRyder Lee 				    struct ieee80211_vif *vif)
24904b8e659SRyder Lee {
25004b8e659SRyder Lee 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
251b2c2f029SLorenzo Bianconi 	struct mt7615_sta *msta = &mvif->sta;
252fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
253ac3ef85cSFelix Fietkau 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
254b2c2f029SLorenzo Bianconi 	int idx = msta->wcid.idx;
25504b8e659SRyder Lee 
256adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
2574f0bce1cSFelix Fietkau 
258d9852ab2SRyder Lee 	mt7615_mcu_add_bss_info(phy, vif, NULL, false);
259d9852ab2SRyder Lee 	mt7615_mcu_sta_add(phy, vif, NULL, false);
260d9852ab2SRyder Lee 
261c918c74dSShayne Chen 	mt76_testmode_reset(phy->mt76, true);
2624f0bce1cSFelix Fietkau 	if (vif == phy->monitor_vif)
2634f0bce1cSFelix Fietkau 	    phy->monitor_vif = NULL;
2644f0bce1cSFelix Fietkau 
2651755f6adSLorenzo Bianconi 	mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid);
2662b8cdfb2SLorenzo Bianconi 
267d0e274afSLorenzo Bianconi 	mt7615_mcu_add_dev_info(phy, vif, false);
26804b8e659SRyder Lee 
26904b8e659SRyder Lee 	rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
27004b8e659SRyder Lee 
271b619e013SEvelyn Tsai 	dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx);
27285d96704SLorenzo Bianconi 	dev->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
27385d96704SLorenzo Bianconi 	phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
274adfd5112SLorenzo Bianconi 
275adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
276b2c2f029SLorenzo Bianconi 
27757a3fac6SLorenzo Bianconi 	spin_lock_bh(&dev->mt76.sta_poll_lock);
2789d599f2dSLorenzo Bianconi 	if (!list_empty(&msta->wcid.poll_list))
2799d599f2dSLorenzo Bianconi 		list_del_init(&msta->wcid.poll_list);
28057a3fac6SLorenzo Bianconi 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
281bd1e3e7bSLorenzo Bianconi 
282*d2defcddSFelix Fietkau 	mt76_wcid_cleanup(&dev->mt76, &mvif->sta.wcid);
28304b8e659SRyder Lee }
28404b8e659SRyder Lee 
mt7615_set_channel(struct mt7615_phy * phy)2854f0bce1cSFelix Fietkau int mt7615_set_channel(struct mt7615_phy *phy)
28604b8e659SRyder Lee {
287fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = phy->dev;
28827ae7219SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
28904b8e659SRyder Lee 	int ret;
29004b8e659SRyder Lee 
291a782f8bfSLorenzo Bianconi 	cancel_delayed_work_sync(&phy->mt76->mac_work);
2927fe96541SLorenzo Bianconi 
293adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
294adfd5112SLorenzo Bianconi 
295fdd2e570SFelix Fietkau 	set_bit(MT76_RESET, &phy->mt76->state);
29604b8e659SRyder Lee 
297fdd2e570SFelix Fietkau 	mt76_set_channel(phy->mt76);
29804b8e659SRyder Lee 
299371a59d1SFelix Fietkau 	if (is_mt7615(&dev->mt76) && dev->flash_eeprom) {
300c3800cc2SRyder Lee 		ret = mt7615_mcu_apply_rx_dcoc(phy);
301c3800cc2SRyder Lee 		if (ret)
302c3800cc2SRyder Lee 			goto out;
303c3800cc2SRyder Lee 
304c3800cc2SRyder Lee 		ret = mt7615_mcu_apply_tx_dpd(phy);
305c3800cc2SRyder Lee 		if (ret)
306c3800cc2SRyder Lee 			goto out;
307371a59d1SFelix Fietkau 	}
308ad380ad1SFelix Fietkau 
309e6d2070dSLorenzo Bianconi 	ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD(CHANNEL_SWITCH));
31004b8e659SRyder Lee 	if (ret)
3117fe96541SLorenzo Bianconi 		goto out;
31204b8e659SRyder Lee 
313183d1fcfSLorenzo Bianconi 	mt7615_mac_set_timing(phy);
3145dabdf71SFelix Fietkau 	ret = mt7615_dfs_init_radar_detector(phy);
315c3800cc2SRyder Lee 	if (ret)
316c3800cc2SRyder Lee 		goto out;
317c3800cc2SRyder Lee 
318d446a20fSFelix Fietkau 	mt7615_mac_cca_stats_reset(phy);
319c3800cc2SRyder Lee 	ret = mt7615_mcu_set_sku_en(phy, true);
320c3800cc2SRyder Lee 	if (ret)
321c3800cc2SRyder Lee 		goto out;
3226bfa6e38SLorenzo Bianconi 
3231b9ba30eSLorenzo Bianconi 	mt7615_mac_reset_counters(phy);
324e5051965SFelix Fietkau 	phy->noise = 0;
3250e544cb5SFelix Fietkau 	phy->chfreq = mt76_rr(dev, MT_CHFREQ(ext_phy));
326d67a6646SLorenzo Bianconi 
3277fe96541SLorenzo Bianconi out:
328fdd2e570SFelix Fietkau 	clear_bit(MT76_RESET, &phy->mt76->state);
329adfd5112SLorenzo Bianconi 
330adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
33104b8e659SRyder Lee 
332310718baSLorenzo Bianconi 	mt76_worker_schedule(&dev->mt76.tx_worker);
333a27238a0SLorenzo Bianconi 	if (!mt76_testmode_enabled(phy->mt76)) {
334a27238a0SLorenzo Bianconi 		unsigned long timeout = mt7615_get_macwork_timeout(dev);
335a27238a0SLorenzo Bianconi 
336a782f8bfSLorenzo Bianconi 		ieee80211_queue_delayed_work(phy->mt76->hw,
337a27238a0SLorenzo Bianconi 					     &phy->mt76->mac_work, timeout);
338a27238a0SLorenzo Bianconi 	}
3394f0bce1cSFelix Fietkau 
3407fe96541SLorenzo Bianconi 	return ret;
34104b8e659SRyder Lee }
34204b8e659SRyder Lee 
mt7615_set_key(struct ieee80211_hw * hw,enum set_key_cmd cmd,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key)34304b8e659SRyder Lee static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
34404b8e659SRyder Lee 			  struct ieee80211_vif *vif, struct ieee80211_sta *sta,
34504b8e659SRyder Lee 			  struct ieee80211_key_conf *key)
34604b8e659SRyder Lee {
347fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
348e814a68aSFelix Fietkau 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
34904b8e659SRyder Lee 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
35004b8e659SRyder Lee 	struct mt7615_sta *msta = sta ? (struct mt7615_sta *)sta->drv_priv :
35104b8e659SRyder Lee 				  &mvif->sta;
35204b8e659SRyder Lee 	struct mt76_wcid *wcid = &msta->wcid;
353730d6d0dSFelix Fietkau 	int idx = key->keyidx, err = 0;
354730d6d0dSFelix Fietkau 	u8 *wcid_keyidx = &wcid->hw_key_idx;
35504b8e659SRyder Lee 
35604b8e659SRyder Lee 	/* The hardware does not support per-STA RX GTK, fallback
35704b8e659SRyder Lee 	 * to software mode for these.
35804b8e659SRyder Lee 	 */
35904b8e659SRyder Lee 	if ((vif->type == NL80211_IFTYPE_ADHOC ||
36004b8e659SRyder Lee 	     vif->type == NL80211_IFTYPE_MESH_POINT) &&
36104b8e659SRyder Lee 	    (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
36204b8e659SRyder Lee 	     key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
36304b8e659SRyder Lee 	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
36404b8e659SRyder Lee 		return -EOPNOTSUPP;
36504b8e659SRyder Lee 
3664a926e30SLorenzo Bianconi 	/* fall back to sw encryption for unsupported ciphers */
3674a926e30SLorenzo Bianconi 	switch (key->cipher) {
36801cfc1b4SLorenzo Bianconi 	case WLAN_CIPHER_SUITE_AES_CMAC:
369730d6d0dSFelix Fietkau 		wcid_keyidx = &wcid->hw_key_idx2;
37001cfc1b4SLorenzo Bianconi 		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
37101cfc1b4SLorenzo Bianconi 		break;
3724a926e30SLorenzo Bianconi 	case WLAN_CIPHER_SUITE_TKIP:
3734a926e30SLorenzo Bianconi 	case WLAN_CIPHER_SUITE_CCMP:
3744a926e30SLorenzo Bianconi 	case WLAN_CIPHER_SUITE_CCMP_256:
3754a926e30SLorenzo Bianconi 	case WLAN_CIPHER_SUITE_GCMP:
3764a926e30SLorenzo Bianconi 	case WLAN_CIPHER_SUITE_GCMP_256:
3774a926e30SLorenzo Bianconi 	case WLAN_CIPHER_SUITE_SMS4:
3784a926e30SLorenzo Bianconi 		break;
379d3a5d89eSLorenzo Bianconi 	case WLAN_CIPHER_SUITE_WEP40:
380d3a5d89eSLorenzo Bianconi 	case WLAN_CIPHER_SUITE_WEP104:
3814a926e30SLorenzo Bianconi 	default:
3824a926e30SLorenzo Bianconi 		return -EOPNOTSUPP;
3834a926e30SLorenzo Bianconi 	}
3844a926e30SLorenzo Bianconi 
385940a0c63SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
386940a0c63SLorenzo Bianconi 
387e814a68aSFelix Fietkau 	if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) {
388e814a68aSFelix Fietkau 		mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher);
389e814a68aSFelix Fietkau 		mt7615_mcu_add_bss_info(phy, vif, NULL, true);
390e814a68aSFelix Fietkau 	}
391e814a68aSFelix Fietkau 
392730d6d0dSFelix Fietkau 	if (cmd == SET_KEY)
393730d6d0dSFelix Fietkau 		*wcid_keyidx = idx;
394e6db67faSFelix Fietkau 	else {
395e6db67faSFelix Fietkau 		if (idx == *wcid_keyidx)
396730d6d0dSFelix Fietkau 			*wcid_keyidx = -1;
397730d6d0dSFelix Fietkau 		goto out;
398e6db67faSFelix Fietkau 	}
399730d6d0dSFelix Fietkau 
400e6db67faSFelix Fietkau 	mt76_wcid_key_setup(&dev->mt76, wcid, key);
4010fa407c3SLorenzo Bianconi 	if (mt76_is_mmio(&dev->mt76))
402e6db67faSFelix Fietkau 		err = mt7615_mac_wtbl_set_key(dev, wcid, key);
4030fa407c3SLorenzo Bianconi 	else
404e6db67faSFelix Fietkau 		err = __mt7615_mac_wtbl_set_key(dev, wcid, key);
405eb99cc95SLorenzo Bianconi 
406730d6d0dSFelix Fietkau out:
407940a0c63SLorenzo Bianconi 	mt7615_mutex_release(dev);
408940a0c63SLorenzo Bianconi 
409940a0c63SLorenzo Bianconi 	return err;
41004b8e659SRyder Lee }
41104b8e659SRyder Lee 
mt7615_set_sar_specs(struct ieee80211_hw * hw,const struct cfg80211_sar_specs * sar)412148950e5SLorenzo Bianconi static int mt7615_set_sar_specs(struct ieee80211_hw *hw,
413148950e5SLorenzo Bianconi 				const struct cfg80211_sar_specs *sar)
414148950e5SLorenzo Bianconi {
415148950e5SLorenzo Bianconi 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
416148950e5SLorenzo Bianconi 	int err;
417148950e5SLorenzo Bianconi 
418148950e5SLorenzo Bianconi 	if (!cfg80211_chandef_valid(&phy->mt76->chandef))
419148950e5SLorenzo Bianconi 		return -EINVAL;
420148950e5SLorenzo Bianconi 
421148950e5SLorenzo Bianconi 	err = mt76_init_sar_power(hw, sar);
422148950e5SLorenzo Bianconi 	if (err)
423148950e5SLorenzo Bianconi 		return err;
424148950e5SLorenzo Bianconi 
425148950e5SLorenzo Bianconi 	if (mt7615_firmware_offload(phy->dev))
426148950e5SLorenzo Bianconi 		return mt76_connac_mcu_set_rate_txpower(phy->mt76);
427148950e5SLorenzo Bianconi 
428148950e5SLorenzo Bianconi 	ieee80211_stop_queues(hw);
429148950e5SLorenzo Bianconi 	err = mt7615_set_channel(phy);
430148950e5SLorenzo Bianconi 	ieee80211_wake_queues(hw);
431148950e5SLorenzo Bianconi 
432148950e5SLorenzo Bianconi 	return err;
433148950e5SLorenzo Bianconi }
434148950e5SLorenzo Bianconi 
mt7615_config(struct ieee80211_hw * hw,u32 changed)43504b8e659SRyder Lee static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
43604b8e659SRyder Lee {
437fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
438fdd2e570SFelix Fietkau 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
439fdd2e570SFelix Fietkau 	bool band = phy != &dev->phy;
44004b8e659SRyder Lee 	int ret = 0;
44104b8e659SRyder Lee 
44215d9a5d7SFelix Fietkau 	if (changed & (IEEE80211_CONF_CHANGE_CHANNEL |
44315d9a5d7SFelix Fietkau 		       IEEE80211_CONF_CHANGE_POWER)) {
4444f0bce1cSFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
445c918c74dSShayne Chen 		if (phy->mt76->test.state != MT76_TM_STATE_OFF) {
446adfd5112SLorenzo Bianconi 			mt7615_mutex_acquire(dev);
447c918c74dSShayne Chen 			mt76_testmode_reset(phy->mt76, false);
448adfd5112SLorenzo Bianconi 			mt7615_mutex_release(dev);
4494f0bce1cSFelix Fietkau 		}
4504f0bce1cSFelix Fietkau #endif
45104b8e659SRyder Lee 		ieee80211_stop_queues(hw);
452fdd2e570SFelix Fietkau 		ret = mt7615_set_channel(phy);
45304b8e659SRyder Lee 		ieee80211_wake_queues(hw);
45404b8e659SRyder Lee 	}
45504b8e659SRyder Lee 
456adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
4577fe96541SLorenzo Bianconi 
45804b8e659SRyder Lee 	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
459c918c74dSShayne Chen 		mt76_testmode_reset(phy->mt76, true);
4604f0bce1cSFelix Fietkau 
46104b8e659SRyder Lee 		if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
462fdd2e570SFelix Fietkau 			phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC;
46304b8e659SRyder Lee 		else
464fdd2e570SFelix Fietkau 			phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC;
46504b8e659SRyder Lee 
466fdd2e570SFelix Fietkau 		mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter);
467892fe32bSLorenzo Bianconi 	}
46804b8e659SRyder Lee 
469adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
470892fe32bSLorenzo Bianconi 
47104b8e659SRyder Lee 	return ret;
47204b8e659SRyder Lee }
47304b8e659SRyder Lee 
47404b8e659SRyder Lee static int
mt7615_conf_tx(struct ieee80211_hw * hw,struct ieee80211_vif * vif,unsigned int link_id,u16 queue,const struct ieee80211_tx_queue_params * params)475b3e2130bSJohannes Berg mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
476b3e2130bSJohannes Berg 	       unsigned int link_id, u16 queue,
47704b8e659SRyder Lee 	       const struct ieee80211_tx_queue_params *params)
47804b8e659SRyder Lee {
47985d96704SLorenzo Bianconi 	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
480fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
481de1f66baSLorenzo Bianconi 	int err;
482de1f66baSLorenzo Bianconi 
483de1f66baSLorenzo Bianconi 	mt7615_mutex_acquire(dev);
48404b8e659SRyder Lee 
4851fec635bSLorenzo Bianconi 	queue = mt7615_lmac_mapping(dev, queue);
48649f1132cSRyder Lee 	queue += mvif->wmm_idx * MT7615_MAX_WMM_SETS;
487de1f66baSLorenzo Bianconi 	err = mt7615_mcu_set_wmm(dev, queue, params);
48849f1132cSRyder Lee 
489de1f66baSLorenzo Bianconi 	mt7615_mutex_release(dev);
490de1f66baSLorenzo Bianconi 
491de1f66baSLorenzo Bianconi 	return err;
49204b8e659SRyder Lee }
49304b8e659SRyder Lee 
mt7615_configure_filter(struct ieee80211_hw * hw,unsigned int changed_flags,unsigned int * total_flags,u64 multicast)49404b8e659SRyder Lee static void mt7615_configure_filter(struct ieee80211_hw *hw,
49504b8e659SRyder Lee 				    unsigned int changed_flags,
49604b8e659SRyder Lee 				    unsigned int *total_flags,
49704b8e659SRyder Lee 				    u64 multicast)
49804b8e659SRyder Lee {
499fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
500fdd2e570SFelix Fietkau 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
501fdd2e570SFelix Fietkau 	bool band = phy != &dev->phy;
502fdd2e570SFelix Fietkau 
503b4124a5bSFelix Fietkau 	u32 ctl_flags = MT_WF_RFCR1_DROP_ACK |
504b4124a5bSFelix Fietkau 			MT_WF_RFCR1_DROP_BF_POLL |
505b4124a5bSFelix Fietkau 			MT_WF_RFCR1_DROP_BA |
506b4124a5bSFelix Fietkau 			MT_WF_RFCR1_DROP_CFEND |
507b4124a5bSFelix Fietkau 			MT_WF_RFCR1_DROP_CFACK;
50804b8e659SRyder Lee 	u32 flags = 0;
50904b8e659SRyder Lee 
510adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
5114f0bce1cSFelix Fietkau 
51204b8e659SRyder Lee #define MT76_FILTER(_flag, _hw) do { \
51304b8e659SRyder Lee 		flags |= *total_flags & FIF_##_flag;			\
514fdd2e570SFelix Fietkau 		phy->rxfilter &= ~(_hw);				\
515c918c74dSShayne Chen 		if (!mt76_testmode_enabled(phy->mt76))			\
516fdd2e570SFelix Fietkau 			phy->rxfilter |= !(flags & FIF_##_flag) * (_hw);\
51704b8e659SRyder Lee 	} while (0)
51804b8e659SRyder Lee 
519fdd2e570SFelix Fietkau 	phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS |
52004b8e659SRyder Lee 			   MT_WF_RFCR_DROP_FRAME_REPORT |
52104b8e659SRyder Lee 			   MT_WF_RFCR_DROP_PROBEREQ |
52204b8e659SRyder Lee 			   MT_WF_RFCR_DROP_MCAST_FILTERED |
52304b8e659SRyder Lee 			   MT_WF_RFCR_DROP_MCAST |
52404b8e659SRyder Lee 			   MT_WF_RFCR_DROP_BCAST |
52504b8e659SRyder Lee 			   MT_WF_RFCR_DROP_DUPLICATE |
52604b8e659SRyder Lee 			   MT_WF_RFCR_DROP_A2_BSSID |
52704b8e659SRyder Lee 			   MT_WF_RFCR_DROP_UNWANTED_CTL |
52804b8e659SRyder Lee 			   MT_WF_RFCR_DROP_STBC_MULTI);
52904b8e659SRyder Lee 
5307124198aSLorenzo Bianconi 	if (phy->n_beacon_vif || !mt7615_firmware_offload(dev))
5317124198aSLorenzo Bianconi 		phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_BEACON;
5327124198aSLorenzo Bianconi 
53304b8e659SRyder Lee 	MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM |
53404b8e659SRyder Lee 			       MT_WF_RFCR_DROP_A3_MAC |
53504b8e659SRyder Lee 			       MT_WF_RFCR_DROP_A3_BSSID);
53604b8e659SRyder Lee 
53704b8e659SRyder Lee 	MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL);
53804b8e659SRyder Lee 
53904b8e659SRyder Lee 	MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS |
54004b8e659SRyder Lee 			     MT_WF_RFCR_DROP_RTS |
54104b8e659SRyder Lee 			     MT_WF_RFCR_DROP_CTL_RSV |
54204b8e659SRyder Lee 			     MT_WF_RFCR_DROP_NDPA);
54304b8e659SRyder Lee 
54404b8e659SRyder Lee 	*total_flags = flags;
545fdd2e570SFelix Fietkau 	mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter);
546b4124a5bSFelix Fietkau 
547b4124a5bSFelix Fietkau 	if (*total_flags & FIF_CONTROL)
548fdd2e570SFelix Fietkau 		mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags);
549b4124a5bSFelix Fietkau 	else
550fdd2e570SFelix Fietkau 		mt76_set(dev, MT_WF_RFCR1(band), ctl_flags);
5514f0bce1cSFelix Fietkau 
552adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
55304b8e659SRyder Lee }
55404b8e659SRyder Lee 
555905a0a6aSRyder Lee static void
mt7615_update_mu_group(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * info)556905a0a6aSRyder Lee mt7615_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
557905a0a6aSRyder Lee 		       struct ieee80211_bss_conf *info)
558905a0a6aSRyder Lee {
559905a0a6aSRyder Lee 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
560905a0a6aSRyder Lee 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
561905a0a6aSRyder Lee 	u8 i, band = mvif->mt76.band_idx;
562905a0a6aSRyder Lee 	u32 *mu;
563905a0a6aSRyder Lee 
564905a0a6aSRyder Lee 	mu = (u32 *)info->mu_group.membership;
565905a0a6aSRyder Lee 	for (i = 0; i < WLAN_MEMBERSHIP_LEN / sizeof(*mu); i++) {
566905a0a6aSRyder Lee 		if (is_mt7663(&dev->mt76))
567905a0a6aSRyder Lee 			mt76_wr(dev, MT7663_WF_PHY_GID_TAB_VLD(band, i), mu[i]);
568905a0a6aSRyder Lee 		else
569905a0a6aSRyder Lee 			mt76_wr(dev, MT_WF_PHY_GID_TAB_VLD(band, i), mu[i]);
570905a0a6aSRyder Lee 	}
571905a0a6aSRyder Lee 
572905a0a6aSRyder Lee 	mu = (u32 *)info->mu_group.position;
573905a0a6aSRyder Lee 	for (i = 0; i < WLAN_USER_POSITION_LEN / sizeof(*mu); i++) {
574905a0a6aSRyder Lee 		if (is_mt7663(&dev->mt76))
575905a0a6aSRyder Lee 			mt76_wr(dev, MT7663_WF_PHY_GID_TAB_POS(band, i), mu[i]);
576905a0a6aSRyder Lee 		else
577905a0a6aSRyder Lee 			mt76_wr(dev, MT_WF_PHY_GID_TAB_POS(band, i), mu[i]);
578905a0a6aSRyder Lee 	}
579905a0a6aSRyder Lee }
580905a0a6aSRyder Lee 
mt7615_bss_info_changed(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * info,u64 changed)58104b8e659SRyder Lee static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
58204b8e659SRyder Lee 				    struct ieee80211_vif *vif,
58304b8e659SRyder Lee 				    struct ieee80211_bss_conf *info,
5847b7090b4SJohannes Berg 				    u64 changed)
58504b8e659SRyder Lee {
586fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
5875d3a4a4bSLorenzo Bianconi 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
58804b8e659SRyder Lee 
589adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
59004b8e659SRyder Lee 
591183d1fcfSLorenzo Bianconi 	if (changed & BSS_CHANGED_ERP_SLOT) {
592183d1fcfSLorenzo Bianconi 		int slottime = info->use_short_slot ? 9 : 20;
593183d1fcfSLorenzo Bianconi 
594183d1fcfSLorenzo Bianconi 		if (slottime != phy->slottime) {
595183d1fcfSLorenzo Bianconi 			phy->slottime = slottime;
596183d1fcfSLorenzo Bianconi 			mt7615_mac_set_timing(phy);
597183d1fcfSLorenzo Bianconi 		}
598183d1fcfSLorenzo Bianconi 	}
599183d1fcfSLorenzo Bianconi 
600e34235ccSRyder Lee 	if (changed & BSS_CHANGED_ERP_CTS_PROT)
601e34235ccSRyder Lee 		mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot);
602e34235ccSRyder Lee 
603d9852ab2SRyder Lee 	if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) {
604d9852ab2SRyder Lee 		mt7615_mcu_add_bss_info(phy, vif, NULL, true);
605d9852ab2SRyder Lee 		mt7615_mcu_sta_add(phy, vif, NULL, true);
60650eb0a88SLorenzo Bianconi 
6071f832887SLorenzo Bianconi 		if (mt7615_firmware_offload(dev) && vif->p2p)
6081f832887SLorenzo Bianconi 			mt76_connac_mcu_set_p2p_oppps(hw, vif);
60904b8e659SRyder Lee 	}
61004b8e659SRyder Lee 
611f0305d18SFelix Fietkau 	if (changed & (BSS_CHANGED_BEACON |
612f0305d18SFelix Fietkau 		       BSS_CHANGED_BEACON_ENABLED))
613062c3699SLorenzo Bianconi 		mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon);
614f0305d18SFelix Fietkau 
615a5e0aa78SLorenzo Bianconi 	if (changed & BSS_CHANGED_PS)
616d0e274afSLorenzo Bianconi 		mt76_connac_mcu_set_vif_ps(&dev->mt76, vif);
617a5e0aa78SLorenzo Bianconi 
618f4f4089eSLorenzo Bianconi 	if ((changed & BSS_CHANGED_ARP_FILTER) &&
619f4f4089eSLorenzo Bianconi 	    mt7615_firmware_offload(dev)) {
620f4f4089eSLorenzo Bianconi 		struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
621f4f4089eSLorenzo Bianconi 
622f4f4089eSLorenzo Bianconi 		mt76_connac_mcu_update_arp_filter(&dev->mt76, &mvif->mt76,
623f4f4089eSLorenzo Bianconi 						  info);
624f4f4089eSLorenzo Bianconi 	}
62573741b9bSSean Wang 
6264bec61d9SSean Wang 	if (changed & BSS_CHANGED_ASSOC)
627f276e20bSJohannes Berg 		mt7615_mac_set_beacon_filter(phy, vif, vif->cfg.assoc);
6284bec61d9SSean Wang 
629905a0a6aSRyder Lee 	if (changed & BSS_CHANGED_MU_GROUPS)
630905a0a6aSRyder Lee 		 mt7615_update_mu_group(hw, vif, info);
631905a0a6aSRyder Lee 
632adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
63304b8e659SRyder Lee }
63404b8e659SRyder Lee 
6355ec87dc8SLorenzo Bianconi static void
mt7615_channel_switch_beacon(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct cfg80211_chan_def * chandef)6365ec87dc8SLorenzo Bianconi mt7615_channel_switch_beacon(struct ieee80211_hw *hw,
6375ec87dc8SLorenzo Bianconi 			     struct ieee80211_vif *vif,
6385ec87dc8SLorenzo Bianconi 			     struct cfg80211_chan_def *chandef)
6395ec87dc8SLorenzo Bianconi {
640fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
6415ec87dc8SLorenzo Bianconi 
642adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
643062c3699SLorenzo Bianconi 	mt7615_mcu_add_beacon(dev, hw, vif, true);
644adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
6455ec87dc8SLorenzo Bianconi }
6465ec87dc8SLorenzo Bianconi 
mt7615_mac_sta_add(struct mt76_dev * mdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)6473e384828SFelix Fietkau int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
64804b8e659SRyder Lee 		       struct ieee80211_sta *sta)
64904b8e659SRyder Lee {
65004b8e659SRyder Lee 	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
65104b8e659SRyder Lee 	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
65204b8e659SRyder Lee 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
6531755f6adSLorenzo Bianconi 	struct mt7615_phy *phy;
6541eae3fb9SLorenzo Bianconi 	int idx, err;
65504b8e659SRyder Lee 
65604b8e659SRyder Lee 	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1);
65704b8e659SRyder Lee 	if (idx < 0)
65804b8e659SRyder Lee 		return -ENOSPC;
65904b8e659SRyder Lee 
6609d599f2dSLorenzo Bianconi 	INIT_LIST_HEAD(&msta->wcid.poll_list);
66104b8e659SRyder Lee 	msta->vif = mvif;
66204b8e659SRyder Lee 	msta->wcid.sta = 1;
66304b8e659SRyder Lee 	msta->wcid.idx = idx;
664a1a99d7bSLorenzo Bianconi 	msta->wcid.phy_idx = mvif->mt76.band_idx;
665fdd2e570SFelix Fietkau 
6661755f6adSLorenzo Bianconi 	phy = mvif->mt76.band_idx ? mt7615_ext_phy(dev) : &dev->phy;
6671755f6adSLorenzo Bianconi 	err = mt76_connac_pm_wake(phy->mt76, &dev->pm);
6681eae3fb9SLorenzo Bianconi 	if (err)
6691eae3fb9SLorenzo Bianconi 		return err;
6701eae3fb9SLorenzo Bianconi 
671c3800cc2SRyder Lee 	if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
672c3800cc2SRyder Lee 		err = mt7615_mcu_add_bss_info(phy, vif, sta, true);
673c3800cc2SRyder Lee 		if (err)
674c3800cc2SRyder Lee 			return err;
675c3800cc2SRyder Lee 	}
676c3800cc2SRyder Lee 
677b2c2f029SLorenzo Bianconi 	mt7615_mac_wtbl_update(dev, idx,
678b2c2f029SLorenzo Bianconi 			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
679c3800cc2SRyder Lee 	err = mt7615_mcu_sta_add(&dev->phy, vif, sta, true);
680c3800cc2SRyder Lee 	if (err)
681c3800cc2SRyder Lee 		return err;
68204b8e659SRyder Lee 
6831755f6adSLorenzo Bianconi 	mt76_connac_power_save_sched(phy->mt76, &dev->pm);
6841eae3fb9SLorenzo Bianconi 
685c3800cc2SRyder Lee 	return err;
68604b8e659SRyder Lee }
687e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mac_sta_add);
68804b8e659SRyder Lee 
mt7615_mac_sta_remove(struct mt76_dev * mdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)6893e384828SFelix Fietkau void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
69004b8e659SRyder Lee 			   struct ieee80211_sta *sta)
69104b8e659SRyder Lee {
69204b8e659SRyder Lee 	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
693b2c2f029SLorenzo Bianconi 	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
6941755f6adSLorenzo Bianconi 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
6951755f6adSLorenzo Bianconi 	struct mt7615_phy *phy;
69604b8e659SRyder Lee 
6971755f6adSLorenzo Bianconi 	mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid);
6981755f6adSLorenzo Bianconi 
6991755f6adSLorenzo Bianconi 	phy = mvif->mt76.band_idx ? mt7615_ext_phy(dev) : &dev->phy;
7001755f6adSLorenzo Bianconi 	mt76_connac_pm_wake(phy->mt76, &dev->pm);
7012b8cdfb2SLorenzo Bianconi 
702d0e274afSLorenzo Bianconi 	mt7615_mcu_sta_add(&dev->phy, vif, sta, false);
703b2c2f029SLorenzo Bianconi 	mt7615_mac_wtbl_update(dev, msta->wcid.idx,
704b2c2f029SLorenzo Bianconi 			       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
7051755f6adSLorenzo Bianconi 	if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
706f5596850SLorenzo Bianconi 		mt7615_mcu_add_bss_info(phy, vif, sta, false);
707b2c2f029SLorenzo Bianconi 
70857a3fac6SLorenzo Bianconi 	spin_lock_bh(&mdev->sta_poll_lock);
7099d599f2dSLorenzo Bianconi 	if (!list_empty(&msta->wcid.poll_list))
7109d599f2dSLorenzo Bianconi 		list_del_init(&msta->wcid.poll_list);
71157a3fac6SLorenzo Bianconi 	spin_unlock_bh(&mdev->sta_poll_lock);
7121eae3fb9SLorenzo Bianconi 
7131755f6adSLorenzo Bianconi 	mt76_connac_power_save_sched(phy->mt76, &dev->pm);
71404b8e659SRyder Lee }
715e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_mac_sta_remove);
71604b8e659SRyder Lee 
mt7615_sta_rate_tbl_update(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)71704b8e659SRyder Lee static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
71804b8e659SRyder Lee 				       struct ieee80211_vif *vif,
71904b8e659SRyder Lee 				       struct ieee80211_sta *sta)
72004b8e659SRyder Lee {
721fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
722fdd2e570SFelix Fietkau 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
72304b8e659SRyder Lee 	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
72404b8e659SRyder Lee 	struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates);
72504b8e659SRyder Lee 	int i;
72604b8e659SRyder Lee 
7276a6f457eSLorenzo Bianconi 	if (!sta_rates)
7286a6f457eSLorenzo Bianconi 		return;
7296a6f457eSLorenzo Bianconi 
73004b8e659SRyder Lee 	spin_lock_bh(&dev->mt76.lock);
73104b8e659SRyder Lee 	for (i = 0; i < ARRAY_SIZE(msta->rates); i++) {
73204b8e659SRyder Lee 		msta->rates[i].idx = sta_rates->rate[i].idx;
73304b8e659SRyder Lee 		msta->rates[i].count = sta_rates->rate[i].count;
73404b8e659SRyder Lee 		msta->rates[i].flags = sta_rates->rate[i].flags;
73504b8e659SRyder Lee 
73604b8e659SRyder Lee 		if (msta->rates[i].idx < 0 || !msta->rates[i].count)
73704b8e659SRyder Lee 			break;
73804b8e659SRyder Lee 	}
73904b8e659SRyder Lee 	msta->n_rates = i;
740335e97acSLorenzo Bianconi 	if (mt76_connac_pm_ref(phy->mt76, &dev->pm)) {
741fdd2e570SFelix Fietkau 		mt7615_mac_set_rates(phy, msta, NULL, msta->rates);
7426ab079e2SLorenzo Bianconi 		mt76_connac_pm_unref(phy->mt76, &dev->pm);
743335e97acSLorenzo Bianconi 	}
74404b8e659SRyder Lee 	spin_unlock_bh(&dev->mt76.lock);
74504b8e659SRyder Lee }
74604b8e659SRyder Lee 
mt7615_tx_worker(struct mt76_worker * w)747335e97acSLorenzo Bianconi void mt7615_tx_worker(struct mt76_worker *w)
7485cf8f779SLorenzo Bianconi {
749335e97acSLorenzo Bianconi 	struct mt7615_dev *dev = container_of(w, struct mt7615_dev,
750335e97acSLorenzo Bianconi 					      mt76.tx_worker);
7515cf8f779SLorenzo Bianconi 
752335e97acSLorenzo Bianconi 	if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
7535cf8f779SLorenzo Bianconi 		queue_work(dev->mt76.wq, &dev->pm.wake_work);
7545cf8f779SLorenzo Bianconi 		return;
7555cf8f779SLorenzo Bianconi 	}
7565cf8f779SLorenzo Bianconi 
757335e97acSLorenzo Bianconi 	mt76_tx_worker_run(&dev->mt76);
7586ab079e2SLorenzo Bianconi 	mt76_connac_pm_unref(&dev->mphy, &dev->pm);
7595cf8f779SLorenzo Bianconi }
7605cf8f779SLorenzo Bianconi 
mt7615_tx(struct ieee80211_hw * hw,struct ieee80211_tx_control * control,struct sk_buff * skb)76104b8e659SRyder Lee static void mt7615_tx(struct ieee80211_hw *hw,
76204b8e659SRyder Lee 		      struct ieee80211_tx_control *control,
76304b8e659SRyder Lee 		      struct sk_buff *skb)
76404b8e659SRyder Lee {
765fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
766fdd2e570SFelix Fietkau 	struct mt76_phy *mphy = hw->priv;
76704b8e659SRyder Lee 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
76804b8e659SRyder Lee 	struct ieee80211_vif *vif = info->control.vif;
76904b8e659SRyder Lee 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
7702b8cdfb2SLorenzo Bianconi 	struct mt7615_sta *msta = NULL;
7712b8cdfb2SLorenzo Bianconi 	int qid;
77204b8e659SRyder Lee 
77304b8e659SRyder Lee 	if (control->sta) {
7742b8cdfb2SLorenzo Bianconi 		msta = (struct mt7615_sta *)control->sta->drv_priv;
7752b8cdfb2SLorenzo Bianconi 		wcid = &msta->wcid;
77604b8e659SRyder Lee 	}
77704b8e659SRyder Lee 
77804b8e659SRyder Lee 	if (vif && !control->sta) {
77904b8e659SRyder Lee 		struct mt7615_vif *mvif;
78004b8e659SRyder Lee 
78104b8e659SRyder Lee 		mvif = (struct mt7615_vif *)vif->drv_priv;
7822b8cdfb2SLorenzo Bianconi 		msta = &mvif->sta;
7832b8cdfb2SLorenzo Bianconi 		wcid = &msta->wcid;
78404b8e659SRyder Lee 	}
78504b8e659SRyder Lee 
786335e97acSLorenzo Bianconi 	if (mt76_connac_pm_ref(mphy, &dev->pm)) {
787fdd2e570SFelix Fietkau 		mt76_tx(mphy, control->sta, wcid, skb);
7886ab079e2SLorenzo Bianconi 		mt76_connac_pm_unref(mphy, &dev->pm);
7892b8cdfb2SLorenzo Bianconi 		return;
7902b8cdfb2SLorenzo Bianconi 	}
7912b8cdfb2SLorenzo Bianconi 
7922b8cdfb2SLorenzo Bianconi 	qid = skb_get_queue_mapping(skb);
7932b8cdfb2SLorenzo Bianconi 	if (qid >= MT_TXQ_PSD) {
7942b8cdfb2SLorenzo Bianconi 		qid = IEEE80211_AC_BE;
7952b8cdfb2SLorenzo Bianconi 		skb_set_queue_mapping(skb, qid);
7962b8cdfb2SLorenzo Bianconi 	}
7972b8cdfb2SLorenzo Bianconi 
7981755f6adSLorenzo Bianconi 	mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb);
79904b8e659SRyder Lee }
80004b8e659SRyder Lee 
mt7615_set_rts_threshold(struct ieee80211_hw * hw,u32 val)80104b8e659SRyder Lee static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
80204b8e659SRyder Lee {
803fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
804fdd2e570SFelix Fietkau 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
805c3800cc2SRyder Lee 	int err, band = phy != &dev->phy;
80604b8e659SRyder Lee 
807adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
808c3800cc2SRyder Lee 	err = mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, band);
809adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
81004b8e659SRyder Lee 
811c3800cc2SRyder Lee 	return err;
81204b8e659SRyder Lee }
81304b8e659SRyder Lee 
81404b8e659SRyder Lee static int
mt7615_ampdu_action(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_ampdu_params * params)81504b8e659SRyder Lee mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
81604b8e659SRyder Lee 		    struct ieee80211_ampdu_params *params)
81704b8e659SRyder Lee {
81804b8e659SRyder Lee 	enum ieee80211_ampdu_mlme_action action = params->action;
819fdd2e570SFelix Fietkau 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
82004b8e659SRyder Lee 	struct ieee80211_sta *sta = params->sta;
82104b8e659SRyder Lee 	struct ieee80211_txq *txq = sta->txq[params->tid];
82204b8e659SRyder Lee 	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
82304b8e659SRyder Lee 	u16 tid = params->tid;
8243d1e5cddSStanislaw Gruszka 	u16 ssn = params->ssn;
82504b8e659SRyder Lee 	struct mt76_txq *mtxq;
82605d6c8cfSMarkus Theil 	int ret = 0;
82704b8e659SRyder Lee 
82804b8e659SRyder Lee 	if (!txq)
82904b8e659SRyder Lee 		return -EINVAL;
83004b8e659SRyder Lee 
83104b8e659SRyder Lee 	mtxq = (struct mt76_txq *)txq->drv_priv;
83204b8e659SRyder Lee 
833adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
834adfd5112SLorenzo Bianconi 
83504b8e659SRyder Lee 	switch (action) {
83604b8e659SRyder Lee 	case IEEE80211_AMPDU_RX_START:
8373d1e5cddSStanislaw Gruszka 		mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
83804b8e659SRyder Lee 				   params->buf_size);
839c3800cc2SRyder Lee 		ret = mt7615_mcu_add_rx_ba(dev, params, true);
84004b8e659SRyder Lee 		break;
84104b8e659SRyder Lee 	case IEEE80211_AMPDU_RX_STOP:
84204b8e659SRyder Lee 		mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
843c3800cc2SRyder Lee 		ret = mt7615_mcu_add_rx_ba(dev, params, false);
84404b8e659SRyder Lee 		break;
84504b8e659SRyder Lee 	case IEEE80211_AMPDU_TX_OPERATIONAL:
84604b8e659SRyder Lee 		mtxq->aggr = true;
84704b8e659SRyder Lee 		mtxq->send_bar = false;
848c3800cc2SRyder Lee 		ret = mt7615_mcu_add_tx_ba(dev, params, true);
849a28bef56SFelix Fietkau 		ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid);
850a28bef56SFelix Fietkau 		ieee80211_send_bar(vif, sta->addr, tid,
851a28bef56SFelix Fietkau 				   IEEE80211_SN_TO_SEQ(ssn));
85204b8e659SRyder Lee 		break;
85304b8e659SRyder Lee 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
85404b8e659SRyder Lee 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
85504b8e659SRyder Lee 		mtxq->aggr = false;
856c3800cc2SRyder Lee 		ret = mt7615_mcu_add_tx_ba(dev, params, false);
85704b8e659SRyder Lee 		break;
85804b8e659SRyder Lee 	case IEEE80211_AMPDU_TX_START:
859a28bef56SFelix Fietkau 		ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid);
860a28bef56SFelix Fietkau 		params->ssn = ssn;
86105d6c8cfSMarkus Theil 		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
86205d6c8cfSMarkus Theil 		break;
86304b8e659SRyder Lee 	case IEEE80211_AMPDU_TX_STOP_CONT:
86404b8e659SRyder Lee 		mtxq->aggr = false;
865c3800cc2SRyder Lee 		ret = mt7615_mcu_add_tx_ba(dev, params, false);
86604b8e659SRyder Lee 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
86704b8e659SRyder Lee 		break;
86804b8e659SRyder Lee 	}
869adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
87004b8e659SRyder Lee 
87105d6c8cfSMarkus Theil 	return ret;
87204b8e659SRyder Lee }
87304b8e659SRyder Lee 
8743e384828SFelix Fietkau static int
mt7615_sta_add(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)8753e384828SFelix Fietkau mt7615_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
8763e384828SFelix Fietkau 	       struct ieee80211_sta *sta)
8773e384828SFelix Fietkau {
8783e384828SFelix Fietkau     return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST,
8793e384828SFelix Fietkau 			  IEEE80211_STA_NONE);
8803e384828SFelix Fietkau }
8813e384828SFelix Fietkau 
8823e384828SFelix Fietkau static int
mt7615_sta_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)8833e384828SFelix Fietkau mt7615_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
8843e384828SFelix Fietkau 		  struct ieee80211_sta *sta)
8853e384828SFelix Fietkau {
8863e384828SFelix Fietkau     return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE,
8873e384828SFelix Fietkau 			  IEEE80211_STA_NOTEXIST);
8883e384828SFelix Fietkau }
8893e384828SFelix Fietkau 
890c388d858SRyder Lee static int
mt7615_get_stats(struct ieee80211_hw * hw,struct ieee80211_low_level_stats * stats)891c388d858SRyder Lee mt7615_get_stats(struct ieee80211_hw *hw,
892c388d858SRyder Lee 		 struct ieee80211_low_level_stats *stats)
893c388d858SRyder Lee {
894c388d858SRyder Lee 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
895c388d858SRyder Lee 	struct mib_stats *mib = &phy->mib;
896c388d858SRyder Lee 
8972eb6f6c4SLorenzo Bianconi 	mt7615_mutex_acquire(phy->dev);
8982eb6f6c4SLorenzo Bianconi 
899c388d858SRyder Lee 	stats->dot11RTSSuccessCount = mib->rts_cnt;
900c388d858SRyder Lee 	stats->dot11RTSFailureCount = mib->rts_retries_cnt;
901c388d858SRyder Lee 	stats->dot11FCSErrorCount = mib->fcs_err_cnt;
902c388d858SRyder Lee 	stats->dot11ACKFailureCount = mib->ack_fail_cnt;
903c388d858SRyder Lee 
9042eb6f6c4SLorenzo Bianconi 	mt7615_mutex_release(phy->dev);
9052eb6f6c4SLorenzo Bianconi 
906c388d858SRyder Lee 	return 0;
907c388d858SRyder Lee }
908c388d858SRyder Lee 
90931affc96SRyder Lee static u64
mt7615_get_tsf(struct ieee80211_hw * hw,struct ieee80211_vif * vif)91031affc96SRyder Lee mt7615_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
91131affc96SRyder Lee {
912a4a5a430SRyder Lee 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
91331affc96SRyder Lee 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
91431affc96SRyder Lee 	union {
91531affc96SRyder Lee 		u64 t64;
91631affc96SRyder Lee 		u32 t32[2];
91731affc96SRyder Lee 	} tsf;
918a4a5a430SRyder Lee 	u16 idx = mvif->mt76.omac_idx;
919a4a5a430SRyder Lee 	u32 reg;
920a4a5a430SRyder Lee 
921a4a5a430SRyder Lee 	idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx;
922a4a5a430SRyder Lee 	reg = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx);
92331affc96SRyder Lee 
924adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
92531affc96SRyder Lee 
926accbcea4SRyder Lee 	/* TSF read */
927accbcea4SRyder Lee 	mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_READ);
92831affc96SRyder Lee 	tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0);
92931affc96SRyder Lee 	tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1);
93031affc96SRyder Lee 
931adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
93231affc96SRyder Lee 
93331affc96SRyder Lee 	return tsf.t64;
93431affc96SRyder Lee }
93531affc96SRyder Lee 
936183d1fcfSLorenzo Bianconi static void
mt7615_set_tsf(struct ieee80211_hw * hw,struct ieee80211_vif * vif,u64 timestamp)937b876658bSRyder Lee mt7615_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
938b876658bSRyder Lee 	       u64 timestamp)
939b876658bSRyder Lee {
940a4a5a430SRyder Lee 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
941b876658bSRyder Lee 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
942b876658bSRyder Lee 	union {
943b876658bSRyder Lee 		u64 t64;
944b876658bSRyder Lee 		u32 t32[2];
945b876658bSRyder Lee 	} tsf = { .t64 = timestamp, };
946a4a5a430SRyder Lee 	u16 idx = mvif->mt76.omac_idx;
947a4a5a430SRyder Lee 	u32 reg;
948a4a5a430SRyder Lee 
949a4a5a430SRyder Lee 	idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx;
950a4a5a430SRyder Lee 	reg = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx);
951b876658bSRyder Lee 
952adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
953b876658bSRyder Lee 
954b876658bSRyder Lee 	mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]);
955b876658bSRyder Lee 	mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]);
956b876658bSRyder Lee 	/* TSF software overwrite */
957accbcea4SRyder Lee 	mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_WRITE);
958accbcea4SRyder Lee 
959accbcea4SRyder Lee 	mt7615_mutex_release(dev);
960accbcea4SRyder Lee }
961accbcea4SRyder Lee 
962accbcea4SRyder Lee static void
mt7615_offset_tsf(struct ieee80211_hw * hw,struct ieee80211_vif * vif,s64 timestamp)963accbcea4SRyder Lee mt7615_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
964accbcea4SRyder Lee 		  s64 timestamp)
965accbcea4SRyder Lee {
966accbcea4SRyder Lee 	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
967accbcea4SRyder Lee 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
968accbcea4SRyder Lee 	union {
969accbcea4SRyder Lee 		u64 t64;
970accbcea4SRyder Lee 		u32 t32[2];
971accbcea4SRyder Lee 	} tsf = { .t64 = timestamp, };
972accbcea4SRyder Lee 	u16 idx = mvif->mt76.omac_idx;
973accbcea4SRyder Lee 	u32 reg;
974accbcea4SRyder Lee 
975accbcea4SRyder Lee 	idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx;
976accbcea4SRyder Lee 	reg = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx);
977accbcea4SRyder Lee 
978accbcea4SRyder Lee 	mt7615_mutex_acquire(dev);
979accbcea4SRyder Lee 
980accbcea4SRyder Lee 	mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]);
981accbcea4SRyder Lee 	mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]);
982accbcea4SRyder Lee 	/* TSF software adjust*/
983accbcea4SRyder Lee 	mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_ADJUST);
984b876658bSRyder Lee 
985adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
986b876658bSRyder Lee }
987b876658bSRyder Lee 
988b876658bSRyder Lee static void
mt7615_set_coverage_class(struct ieee80211_hw * hw,s16 coverage_class)989183d1fcfSLorenzo Bianconi mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
990183d1fcfSLorenzo Bianconi {
991183d1fcfSLorenzo Bianconi 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
9922cb002e3SLorenzo Bianconi 	struct mt7615_dev *dev = phy->dev;
993183d1fcfSLorenzo Bianconi 
994adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
995183d1fcfSLorenzo Bianconi 	phy->coverage_class = max_t(s16, coverage_class, 0);
996183d1fcfSLorenzo Bianconi 	mt7615_mac_set_timing(phy);
997adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
998183d1fcfSLorenzo Bianconi }
999183d1fcfSLorenzo Bianconi 
10000d88aea8SRyder Lee static int
mt7615_set_antenna(struct ieee80211_hw * hw,u32 tx_ant,u32 rx_ant)10010d88aea8SRyder Lee mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
10020d88aea8SRyder Lee {
10030d88aea8SRyder Lee 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
10040d88aea8SRyder Lee 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
10050d88aea8SRyder Lee 	int max_nss = hweight8(hw->wiphy->available_antennas_tx);
10060d88aea8SRyder Lee 	bool ext_phy = phy != &dev->phy;
10070d88aea8SRyder Lee 
10080d88aea8SRyder Lee 	if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss)
10090d88aea8SRyder Lee 		return -EINVAL;
10100d88aea8SRyder Lee 
10110d88aea8SRyder Lee 	if ((BIT(hweight8(tx_ant)) - 1) != tx_ant)
10120d88aea8SRyder Lee 		tx_ant = BIT(ffs(tx_ant) - 1) - 1;
10130d88aea8SRyder Lee 
1014adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
10150d88aea8SRyder Lee 
10160d88aea8SRyder Lee 	phy->mt76->antenna_mask = tx_ant;
10171a7d3f47SFelix Fietkau 	if (ext_phy) {
10181a7d3f47SFelix Fietkau 		if (dev->chainmask == 0xf)
10191a7d3f47SFelix Fietkau 			tx_ant <<= 2;
10201a7d3f47SFelix Fietkau 		else
10211a7d3f47SFelix Fietkau 			tx_ant <<= 1;
10221a7d3f47SFelix Fietkau 	}
1023b9027e08SLorenzo Bianconi 	phy->mt76->chainmask = tx_ant;
10240d88aea8SRyder Lee 
1025bb3e3fecSRyder Lee 	mt76_set_stream_caps(phy->mt76, true);
10260d88aea8SRyder Lee 
1027adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
10280d88aea8SRyder Lee 
10290d88aea8SRyder Lee 	return 0;
10300d88aea8SRyder Lee }
10310d88aea8SRyder Lee 
mt7615_roc_iter(void * priv,u8 * mac,struct ieee80211_vif * vif)10327307f296SLorenzo Bianconi static void mt7615_roc_iter(void *priv, u8 *mac,
10337307f296SLorenzo Bianconi 			    struct ieee80211_vif *vif)
10347307f296SLorenzo Bianconi {
10357307f296SLorenzo Bianconi 	struct mt7615_phy *phy = priv;
10367307f296SLorenzo Bianconi 
10377307f296SLorenzo Bianconi 	mt7615_mcu_set_roc(phy, vif, NULL, 0);
10387307f296SLorenzo Bianconi }
10397307f296SLorenzo Bianconi 
mt7615_roc_work(struct work_struct * work)10407307f296SLorenzo Bianconi void mt7615_roc_work(struct work_struct *work)
10417307f296SLorenzo Bianconi {
10427307f296SLorenzo Bianconi 	struct mt7615_phy *phy;
10437307f296SLorenzo Bianconi 
10447307f296SLorenzo Bianconi 	phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy,
10457307f296SLorenzo Bianconi 						roc_work);
10467307f296SLorenzo Bianconi 
10477307f296SLorenzo Bianconi 	if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
10487307f296SLorenzo Bianconi 		return;
10497307f296SLorenzo Bianconi 
105046dadc31SLorenzo Bianconi 	mt7615_mutex_acquire(phy->dev);
10517307f296SLorenzo Bianconi 	ieee80211_iterate_active_interfaces(phy->mt76->hw,
10527307f296SLorenzo Bianconi 					    IEEE80211_IFACE_ITER_RESUME_ALL,
10537307f296SLorenzo Bianconi 					    mt7615_roc_iter, phy);
105446dadc31SLorenzo Bianconi 	mt7615_mutex_release(phy->dev);
10557307f296SLorenzo Bianconi 	ieee80211_remain_on_channel_expired(phy->mt76->hw);
10567307f296SLorenzo Bianconi }
10577307f296SLorenzo Bianconi 
mt7615_roc_timer(struct timer_list * timer)10587307f296SLorenzo Bianconi void mt7615_roc_timer(struct timer_list *timer)
10597307f296SLorenzo Bianconi {
10607307f296SLorenzo Bianconi 	struct mt7615_phy *phy = from_timer(phy, timer, roc_timer);
10617307f296SLorenzo Bianconi 
10627307f296SLorenzo Bianconi 	ieee80211_queue_work(phy->mt76->hw, &phy->roc_work);
10637307f296SLorenzo Bianconi }
10647307f296SLorenzo Bianconi 
mt7615_scan_work(struct work_struct * work)1065fcdfc29eSLorenzo Bianconi void mt7615_scan_work(struct work_struct *work)
1066fcdfc29eSLorenzo Bianconi {
1067fcdfc29eSLorenzo Bianconi 	struct mt7615_phy *phy;
1068fcdfc29eSLorenzo Bianconi 
1069fcdfc29eSLorenzo Bianconi 	phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy,
1070fcdfc29eSLorenzo Bianconi 						scan_work.work);
1071fcdfc29eSLorenzo Bianconi 
107220305f98SLorenzo Bianconi 	while (true) {
107320305f98SLorenzo Bianconi 		struct mt7615_mcu_rxd *rxd;
107420305f98SLorenzo Bianconi 		struct sk_buff *skb;
107520305f98SLorenzo Bianconi 
107620305f98SLorenzo Bianconi 		spin_lock_bh(&phy->dev->mt76.lock);
107720305f98SLorenzo Bianconi 		skb = __skb_dequeue(&phy->scan_event_list);
107820305f98SLorenzo Bianconi 		spin_unlock_bh(&phy->dev->mt76.lock);
107920305f98SLorenzo Bianconi 
108020305f98SLorenzo Bianconi 		if (!skb)
108120305f98SLorenzo Bianconi 			break;
108220305f98SLorenzo Bianconi 
108320305f98SLorenzo Bianconi 		rxd = (struct mt7615_mcu_rxd *)skb->data;
10847cba8c30SLorenzo Bianconi 		if (rxd->eid == MCU_EVENT_SCHED_SCAN_DONE) {
10857cba8c30SLorenzo Bianconi 			ieee80211_sched_scan_results(phy->mt76->hw);
10867cba8c30SLorenzo Bianconi 		} else if (test_and_clear_bit(MT76_HW_SCANNING,
10877cba8c30SLorenzo Bianconi 					      &phy->mt76->state)) {
108820305f98SLorenzo Bianconi 			struct cfg80211_scan_info info = {
108920305f98SLorenzo Bianconi 				.aborted = false,
109020305f98SLorenzo Bianconi 			};
109120305f98SLorenzo Bianconi 
1092fcdfc29eSLorenzo Bianconi 			ieee80211_scan_completed(phy->mt76->hw, &info);
109320305f98SLorenzo Bianconi 		}
109420305f98SLorenzo Bianconi 		dev_kfree_skb(skb);
109520305f98SLorenzo Bianconi 	}
1096fcdfc29eSLorenzo Bianconi }
1097fcdfc29eSLorenzo Bianconi 
1098fcdfc29eSLorenzo Bianconi static int
mt7615_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_scan_request * req)1099fcdfc29eSLorenzo Bianconi mt7615_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1100fcdfc29eSLorenzo Bianconi 	       struct ieee80211_scan_request *req)
1101fcdfc29eSLorenzo Bianconi {
1102888a678aSLorenzo Bianconi 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
1103fcdfc29eSLorenzo Bianconi 	struct mt76_phy *mphy = hw->priv;
1104888a678aSLorenzo Bianconi 	int err;
1105fcdfc29eSLorenzo Bianconi 
1106399090efSLorenzo Bianconi 	/* fall-back to sw-scan */
1107399090efSLorenzo Bianconi 	if (!mt7615_firmware_offload(dev))
1108399090efSLorenzo Bianconi 		return 1;
1109399090efSLorenzo Bianconi 
1110888a678aSLorenzo Bianconi 	mt7615_mutex_acquire(dev);
1111399090efSLorenzo Bianconi 	err = mt76_connac_mcu_hw_scan(mphy, vif, req);
1112888a678aSLorenzo Bianconi 	mt7615_mutex_release(dev);
1113888a678aSLorenzo Bianconi 
1114888a678aSLorenzo Bianconi 	return err;
1115fcdfc29eSLorenzo Bianconi }
1116fcdfc29eSLorenzo Bianconi 
1117fcdfc29eSLorenzo Bianconi static void
mt7615_cancel_hw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif)1118fcdfc29eSLorenzo Bianconi mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
1119fcdfc29eSLorenzo Bianconi {
1120888a678aSLorenzo Bianconi 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
1121fcdfc29eSLorenzo Bianconi 	struct mt76_phy *mphy = hw->priv;
1122fcdfc29eSLorenzo Bianconi 
1123888a678aSLorenzo Bianconi 	mt7615_mutex_acquire(dev);
1124399090efSLorenzo Bianconi 	mt76_connac_mcu_cancel_hw_scan(mphy, vif);
1125888a678aSLorenzo Bianconi 	mt7615_mutex_release(dev);
1126fcdfc29eSLorenzo Bianconi }
1127fcdfc29eSLorenzo Bianconi 
112820305f98SLorenzo Bianconi static int
mt7615_start_sched_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct cfg80211_sched_scan_request * req,struct ieee80211_scan_ies * ies)112920305f98SLorenzo Bianconi mt7615_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
113020305f98SLorenzo Bianconi 			struct cfg80211_sched_scan_request *req,
113120305f98SLorenzo Bianconi 			struct ieee80211_scan_ies *ies)
113220305f98SLorenzo Bianconi {
1133888a678aSLorenzo Bianconi 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
113420305f98SLorenzo Bianconi 	struct mt76_phy *mphy = hw->priv;
113520305f98SLorenzo Bianconi 	int err;
113620305f98SLorenzo Bianconi 
1137399090efSLorenzo Bianconi 	if (!mt7615_firmware_offload(dev))
1138399090efSLorenzo Bianconi 		return -EOPNOTSUPP;
1139399090efSLorenzo Bianconi 
1140888a678aSLorenzo Bianconi 	mt7615_mutex_acquire(dev);
1141888a678aSLorenzo Bianconi 
1142399090efSLorenzo Bianconi 	err = mt76_connac_mcu_sched_scan_req(mphy, vif, req);
114320305f98SLorenzo Bianconi 	if (err < 0)
1144888a678aSLorenzo Bianconi 		goto out;
114520305f98SLorenzo Bianconi 
1146399090efSLorenzo Bianconi 	err = mt76_connac_mcu_sched_scan_enable(mphy, vif, true);
1147888a678aSLorenzo Bianconi out:
1148888a678aSLorenzo Bianconi 	mt7615_mutex_release(dev);
1149888a678aSLorenzo Bianconi 
1150888a678aSLorenzo Bianconi 	return err;
115120305f98SLorenzo Bianconi }
115220305f98SLorenzo Bianconi 
115320305f98SLorenzo Bianconi static int
mt7615_stop_sched_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif)115420305f98SLorenzo Bianconi mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
115520305f98SLorenzo Bianconi {
1156888a678aSLorenzo Bianconi 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
115720305f98SLorenzo Bianconi 	struct mt76_phy *mphy = hw->priv;
1158888a678aSLorenzo Bianconi 	int err;
115920305f98SLorenzo Bianconi 
1160399090efSLorenzo Bianconi 	if (!mt7615_firmware_offload(dev))
1161399090efSLorenzo Bianconi 		return -EOPNOTSUPP;
1162399090efSLorenzo Bianconi 
1163888a678aSLorenzo Bianconi 	mt7615_mutex_acquire(dev);
1164399090efSLorenzo Bianconi 	err = mt76_connac_mcu_sched_scan_enable(mphy, vif, false);
1165888a678aSLorenzo Bianconi 	mt7615_mutex_release(dev);
1166888a678aSLorenzo Bianconi 
1167888a678aSLorenzo Bianconi 	return err;
116820305f98SLorenzo Bianconi }
116920305f98SLorenzo Bianconi 
mt7615_remain_on_channel(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_channel * chan,int duration,enum ieee80211_roc_type type)11707307f296SLorenzo Bianconi static int mt7615_remain_on_channel(struct ieee80211_hw *hw,
11717307f296SLorenzo Bianconi 				    struct ieee80211_vif *vif,
11727307f296SLorenzo Bianconi 				    struct ieee80211_channel *chan,
11737307f296SLorenzo Bianconi 				    int duration,
11747307f296SLorenzo Bianconi 				    enum ieee80211_roc_type type)
11757307f296SLorenzo Bianconi {
11767307f296SLorenzo Bianconi 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
11777307f296SLorenzo Bianconi 	int err;
11787307f296SLorenzo Bianconi 
11797307f296SLorenzo Bianconi 	if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))
11807307f296SLorenzo Bianconi 		return 0;
11817307f296SLorenzo Bianconi 
118246dadc31SLorenzo Bianconi 	mt7615_mutex_acquire(phy->dev);
118346dadc31SLorenzo Bianconi 
11847307f296SLorenzo Bianconi 	err = mt7615_mcu_set_roc(phy, vif, chan, duration);
11857307f296SLorenzo Bianconi 	if (err < 0) {
11867307f296SLorenzo Bianconi 		clear_bit(MT76_STATE_ROC, &phy->mt76->state);
118746dadc31SLorenzo Bianconi 		goto out;
11887307f296SLorenzo Bianconi 	}
11897307f296SLorenzo Bianconi 
11907307f296SLorenzo Bianconi 	if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, HZ)) {
11917307f296SLorenzo Bianconi 		mt7615_mcu_set_roc(phy, vif, NULL, 0);
11927307f296SLorenzo Bianconi 		clear_bit(MT76_STATE_ROC, &phy->mt76->state);
119346dadc31SLorenzo Bianconi 		err = -ETIMEDOUT;
11947307f296SLorenzo Bianconi 	}
11957307f296SLorenzo Bianconi 
119646dadc31SLorenzo Bianconi out:
119746dadc31SLorenzo Bianconi 	mt7615_mutex_release(phy->dev);
119846dadc31SLorenzo Bianconi 
119946dadc31SLorenzo Bianconi 	return err;
12007307f296SLorenzo Bianconi }
12017307f296SLorenzo Bianconi 
mt7615_cancel_remain_on_channel(struct ieee80211_hw * hw,struct ieee80211_vif * vif)12027307f296SLorenzo Bianconi static int mt7615_cancel_remain_on_channel(struct ieee80211_hw *hw,
12037307f296SLorenzo Bianconi 					   struct ieee80211_vif *vif)
12047307f296SLorenzo Bianconi {
12057307f296SLorenzo Bianconi 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
1206c3800cc2SRyder Lee 	int err;
12077307f296SLorenzo Bianconi 
12087307f296SLorenzo Bianconi 	if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
12097307f296SLorenzo Bianconi 		return 0;
12107307f296SLorenzo Bianconi 
12117307f296SLorenzo Bianconi 	del_timer_sync(&phy->roc_timer);
12127307f296SLorenzo Bianconi 	cancel_work_sync(&phy->roc_work);
12137307f296SLorenzo Bianconi 
121446dadc31SLorenzo Bianconi 	mt7615_mutex_acquire(phy->dev);
1215c3800cc2SRyder Lee 	err = mt7615_mcu_set_roc(phy, vif, NULL, 0);
121646dadc31SLorenzo Bianconi 	mt7615_mutex_release(phy->dev);
12177307f296SLorenzo Bianconi 
1218c3800cc2SRyder Lee 	return err;
12197307f296SLorenzo Bianconi }
12207307f296SLorenzo Bianconi 
mt7615_sta_set_decap_offload(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enabled)1221d4b98c63SRyder Lee static void mt7615_sta_set_decap_offload(struct ieee80211_hw *hw,
1222d4b98c63SRyder Lee 				 struct ieee80211_vif *vif,
1223d4b98c63SRyder Lee 				 struct ieee80211_sta *sta,
1224d4b98c63SRyder Lee 				 bool enabled)
1225d4b98c63SRyder Lee {
1226d4b98c63SRyder Lee 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
1227d4b98c63SRyder Lee 	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
1228d4b98c63SRyder Lee 
1229765c69d4SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
1230765c69d4SLorenzo Bianconi 
1231d4b98c63SRyder Lee 	if (enabled)
1232d4b98c63SRyder Lee 		set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
1233d4b98c63SRyder Lee 	else
1234d4b98c63SRyder Lee 		clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
1235d4b98c63SRyder Lee 
123654c31b9eSLorenzo Bianconi 	mt7615_mcu_set_sta_decap_offload(dev, vif, sta);
1237765c69d4SLorenzo Bianconi 
1238765c69d4SLorenzo Bianconi 	mt7615_mutex_release(dev);
1239d4b98c63SRyder Lee }
1240d4b98c63SRyder Lee 
1241c6bf2010SLorenzo Bianconi #ifdef CONFIG_PM
mt7615_suspend(struct ieee80211_hw * hw,struct cfg80211_wowlan * wowlan)1242c6bf2010SLorenzo Bianconi static int mt7615_suspend(struct ieee80211_hw *hw,
1243c6bf2010SLorenzo Bianconi 			  struct cfg80211_wowlan *wowlan)
1244c6bf2010SLorenzo Bianconi {
1245c6bf2010SLorenzo Bianconi 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
124655d4c19cSLorenzo Bianconi 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
1247c6bf2010SLorenzo Bianconi 	int err = 0;
1248c6bf2010SLorenzo Bianconi 
1249de5ff3c9SLorenzo Bianconi 	cancel_delayed_work_sync(&dev->pm.ps_work);
12501755f6adSLorenzo Bianconi 	mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
1251de5ff3c9SLorenzo Bianconi 
1252adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
1253c6bf2010SLorenzo Bianconi 
1254c6bf2010SLorenzo Bianconi 	clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
1255c6bf2010SLorenzo Bianconi 	cancel_delayed_work_sync(&phy->scan_work);
1256a782f8bfSLorenzo Bianconi 	cancel_delayed_work_sync(&phy->mt76->mac_work);
1257c6bf2010SLorenzo Bianconi 
1258c6bf2010SLorenzo Bianconi 	set_bit(MT76_STATE_SUSPEND, &phy->mt76->state);
1259c6bf2010SLorenzo Bianconi 	ieee80211_iterate_active_interfaces(hw,
1260c6bf2010SLorenzo Bianconi 					    IEEE80211_IFACE_ITER_RESUME_ALL,
126155d4c19cSLorenzo Bianconi 					    mt76_connac_mcu_set_suspend_iter,
126255d4c19cSLorenzo Bianconi 					    phy->mt76);
1263c6bf2010SLorenzo Bianconi 
1264c6bf2010SLorenzo Bianconi 	if (!mt7615_dev_running(dev))
126555d4c19cSLorenzo Bianconi 		err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true);
1266c6bf2010SLorenzo Bianconi 
1267adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
1268c6bf2010SLorenzo Bianconi 
1269c6bf2010SLorenzo Bianconi 	return err;
1270c6bf2010SLorenzo Bianconi }
1271c6bf2010SLorenzo Bianconi 
mt7615_resume(struct ieee80211_hw * hw)1272c6bf2010SLorenzo Bianconi static int mt7615_resume(struct ieee80211_hw *hw)
1273c6bf2010SLorenzo Bianconi {
1274c6bf2010SLorenzo Bianconi 	struct mt7615_phy *phy = mt7615_hw_phy(hw);
127555d4c19cSLorenzo Bianconi 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
1276a27238a0SLorenzo Bianconi 	unsigned long timeout;
12777124198aSLorenzo Bianconi 	bool running;
1278c6bf2010SLorenzo Bianconi 
1279adfd5112SLorenzo Bianconi 	mt7615_mutex_acquire(dev);
1280c6bf2010SLorenzo Bianconi 
1281c6bf2010SLorenzo Bianconi 	running = mt7615_dev_running(dev);
1282c6bf2010SLorenzo Bianconi 	set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
1283c6bf2010SLorenzo Bianconi 
1284c6bf2010SLorenzo Bianconi 	if (!running) {
1285c6bf2010SLorenzo Bianconi 		int err;
1286c6bf2010SLorenzo Bianconi 
128755d4c19cSLorenzo Bianconi 		err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false);
1288c6bf2010SLorenzo Bianconi 		if (err < 0) {
1289adfd5112SLorenzo Bianconi 			mt7615_mutex_release(dev);
1290c6bf2010SLorenzo Bianconi 			return err;
1291c6bf2010SLorenzo Bianconi 		}
1292c6bf2010SLorenzo Bianconi 	}
1293c6bf2010SLorenzo Bianconi 
1294c6bf2010SLorenzo Bianconi 	clear_bit(MT76_STATE_SUSPEND, &phy->mt76->state);
1295c6bf2010SLorenzo Bianconi 	ieee80211_iterate_active_interfaces(hw,
1296c6bf2010SLorenzo Bianconi 					    IEEE80211_IFACE_ITER_RESUME_ALL,
129755d4c19cSLorenzo Bianconi 					    mt76_connac_mcu_set_suspend_iter,
129855d4c19cSLorenzo Bianconi 					    phy->mt76);
1299c6bf2010SLorenzo Bianconi 
1300a27238a0SLorenzo Bianconi 	timeout = mt7615_get_macwork_timeout(dev);
1301a27238a0SLorenzo Bianconi 	ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout);
1302c6bf2010SLorenzo Bianconi 
1303adfd5112SLorenzo Bianconi 	mt7615_mutex_release(dev);
1304c6bf2010SLorenzo Bianconi 
1305c6bf2010SLorenzo Bianconi 	return 0;
1306c6bf2010SLorenzo Bianconi }
1307c6bf2010SLorenzo Bianconi 
mt7615_set_wakeup(struct ieee80211_hw * hw,bool enabled)1308c6bf2010SLorenzo Bianconi static void mt7615_set_wakeup(struct ieee80211_hw *hw, bool enabled)
1309c6bf2010SLorenzo Bianconi {
1310c6bf2010SLorenzo Bianconi 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
1311c6bf2010SLorenzo Bianconi 	struct mt76_dev *mdev = &dev->mt76;
1312c6bf2010SLorenzo Bianconi 
1313c6bf2010SLorenzo Bianconi 	device_set_wakeup_enable(mdev->dev, enabled);
1314c6bf2010SLorenzo Bianconi }
1315b47e21e7SLorenzo Bianconi 
mt7615_set_rekey_data(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct cfg80211_gtk_rekey_data * data)1316b47e21e7SLorenzo Bianconi static void mt7615_set_rekey_data(struct ieee80211_hw *hw,
1317b47e21e7SLorenzo Bianconi 				  struct ieee80211_vif *vif,
1318b47e21e7SLorenzo Bianconi 				  struct cfg80211_gtk_rekey_data *data)
1319b47e21e7SLorenzo Bianconi {
1320888a678aSLorenzo Bianconi 	struct mt7615_dev *dev = mt7615_hw_dev(hw);
1321888a678aSLorenzo Bianconi 
1322888a678aSLorenzo Bianconi 	mt7615_mutex_acquire(dev);
132355d4c19cSLorenzo Bianconi 	mt76_connac_mcu_update_gtk_rekey(hw, vif, data);
1324888a678aSLorenzo Bianconi 	mt7615_mutex_release(dev);
1325b47e21e7SLorenzo Bianconi }
1326c6bf2010SLorenzo Bianconi #endif /* CONFIG_PM */
1327c6bf2010SLorenzo Bianconi 
132804b8e659SRyder Lee const struct ieee80211_ops mt7615_ops = {
132904b8e659SRyder Lee 	.tx = mt7615_tx,
133004b8e659SRyder Lee 	.start = mt7615_start,
133104b8e659SRyder Lee 	.stop = mt7615_stop,
133204b8e659SRyder Lee 	.add_interface = mt7615_add_interface,
133304b8e659SRyder Lee 	.remove_interface = mt7615_remove_interface,
133404b8e659SRyder Lee 	.config = mt7615_config,
133504b8e659SRyder Lee 	.conf_tx = mt7615_conf_tx,
133604b8e659SRyder Lee 	.configure_filter = mt7615_configure_filter,
133704b8e659SRyder Lee 	.bss_info_changed = mt7615_bss_info_changed,
13383e384828SFelix Fietkau 	.sta_add = mt7615_sta_add,
13393e384828SFelix Fietkau 	.sta_remove = mt7615_sta_remove,
134043ba1922SFelix Fietkau 	.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
134104b8e659SRyder Lee 	.set_key = mt7615_set_key,
1342d4b98c63SRyder Lee 	.sta_set_decap_offload = mt7615_sta_set_decap_offload,
134304b8e659SRyder Lee 	.ampdu_action = mt7615_ampdu_action,
134404b8e659SRyder Lee 	.set_rts_threshold = mt7615_set_rts_threshold,
1345335e97acSLorenzo Bianconi 	.wake_tx_queue = mt76_wake_tx_queue,
134604b8e659SRyder Lee 	.sta_rate_tbl_update = mt7615_sta_rate_tbl_update,
13478b8ab5c2SLorenzo Bianconi 	.sw_scan_start = mt76_sw_scan,
13488b8ab5c2SLorenzo Bianconi 	.sw_scan_complete = mt76_sw_scan_complete,
134904b8e659SRyder Lee 	.release_buffered_frames = mt76_release_buffered_frames,
13502fccf4f0SLorenzo Bianconi 	.get_txpower = mt76_get_txpower,
13515ec87dc8SLorenzo Bianconi 	.channel_switch_beacon = mt7615_channel_switch_beacon,
1352c388d858SRyder Lee 	.get_stats = mt7615_get_stats,
135331affc96SRyder Lee 	.get_tsf = mt7615_get_tsf,
1354b876658bSRyder Lee 	.set_tsf = mt7615_set_tsf,
1355accbcea4SRyder Lee 	.offset_tsf = mt7615_offset_tsf,
1356863c15a1SLorenzo Bianconi 	.get_survey = mt76_get_survey,
1357e49c76d4SLorenzo Bianconi 	.get_antenna = mt76_get_antenna,
13580d88aea8SRyder Lee 	.set_antenna = mt7615_set_antenna,
1359183d1fcfSLorenzo Bianconi 	.set_coverage_class = mt7615_set_coverage_class,
1360fcdfc29eSLorenzo Bianconi 	.hw_scan = mt7615_hw_scan,
1361fcdfc29eSLorenzo Bianconi 	.cancel_hw_scan = mt7615_cancel_hw_scan,
136220305f98SLorenzo Bianconi 	.sched_scan_start = mt7615_start_sched_scan,
136320305f98SLorenzo Bianconi 	.sched_scan_stop = mt7615_stop_sched_scan,
13647307f296SLorenzo Bianconi 	.remain_on_channel = mt7615_remain_on_channel,
13657307f296SLorenzo Bianconi 	.cancel_remain_on_channel = mt7615_cancel_remain_on_channel,
13664f0bce1cSFelix Fietkau 	CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
13674f0bce1cSFelix Fietkau 	CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
1368c6bf2010SLorenzo Bianconi #ifdef CONFIG_PM
1369c6bf2010SLorenzo Bianconi 	.suspend = mt7615_suspend,
1370c6bf2010SLorenzo Bianconi 	.resume = mt7615_resume,
1371c6bf2010SLorenzo Bianconi 	.set_wakeup = mt7615_set_wakeup,
1372b47e21e7SLorenzo Bianconi 	.set_rekey_data = mt7615_set_rekey_data,
1373c6bf2010SLorenzo Bianconi #endif /* CONFIG_PM */
1374148950e5SLorenzo Bianconi 	.set_sar_specs = mt7615_set_sar_specs,
137504b8e659SRyder Lee };
1376e90354e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt7615_ops);
137735da599fSFelix Fietkau 
137835da599fSFelix Fietkau MODULE_LICENSE("Dual BSD/GPL");
1379