xref: /linux/drivers/net/wireless/mediatek/mt76/mt76x0/main.c (revision b7d3826c2ed6c3e626e7ae796c5df2c0d2551c6a)
1 /*
2  * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
3  * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
4  * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  */
15 
16 #include <linux/etherdevice.h>
17 #include "mt76x0.h"
18 
19 int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
20 {
21 	struct mt76x02_dev *dev = hw->priv;
22 	int ret = 0;
23 
24 	mutex_lock(&dev->mt76.mutex);
25 
26 	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
27 		ieee80211_stop_queues(hw);
28 		ret = mt76x0_phy_set_channel(dev, &hw->conf.chandef);
29 		ieee80211_wake_queues(hw);
30 	}
31 
32 	if (changed & IEEE80211_CONF_CHANGE_POWER) {
33 		dev->mt76.txpower_conf = hw->conf.power_level * 2;
34 
35 		if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
36 			mt76x0_phy_set_txpower(dev);
37 	}
38 
39 	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
40 		if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
41 			dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC;
42 		else
43 			dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC;
44 
45 		mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
46 	}
47 
48 	mutex_unlock(&dev->mt76.mutex);
49 
50 	return ret;
51 }
52 EXPORT_SYMBOL_GPL(mt76x0_config);
53 
54 static void
55 mt76x0_addr_wr(struct mt76x02_dev *dev, const u32 offset, const u8 *addr)
56 {
57 	mt76_wr(dev, offset, get_unaligned_le32(addr));
58 	mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8);
59 }
60 
61 void mt76x0_bss_info_changed(struct ieee80211_hw *hw,
62 			     struct ieee80211_vif *vif,
63 			     struct ieee80211_bss_conf *info, u32 changed)
64 {
65 	struct mt76x02_dev *dev = hw->priv;
66 
67 	mutex_lock(&dev->mt76.mutex);
68 
69 	if (changed & BSS_CHANGED_BSSID) {
70 		mt76x0_addr_wr(dev, MT_MAC_BSSID_DW0, info->bssid);
71 
72 		/* Note: this is a hack because beacon_int is not changed
73 		 *	 on leave nor is any more appropriate event generated.
74 		 *	 rt2x00 doesn't seem to be bothered though.
75 		 */
76 		if (is_zero_ether_addr(info->bssid))
77 			mt76x0_mac_config_tsf(dev, false, 0);
78 	}
79 
80 	if (changed & BSS_CHANGED_BASIC_RATES) {
81 		mt76_wr(dev, MT_LEGACY_BASIC_RATE, info->basic_rates);
82 		mt76_wr(dev, MT_VHT_HT_FBK_CFG0, 0x65432100);
83 		mt76_wr(dev, MT_VHT_HT_FBK_CFG1, 0xedcba980);
84 		mt76_wr(dev, MT_LG_FBK_CFG0, 0xedcba988);
85 		mt76_wr(dev, MT_LG_FBK_CFG1, 0x00002100);
86 	}
87 
88 	if (changed & BSS_CHANGED_BEACON_INT)
89 		mt76x0_mac_config_tsf(dev, true, info->beacon_int);
90 
91 	if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
92 		mt76x0_mac_set_protection(dev, info->use_cts_prot,
93 					   info->ht_operation_mode);
94 
95 	if (changed & BSS_CHANGED_ERP_PREAMBLE)
96 		mt76x0_mac_set_short_preamble(dev, info->use_short_preamble);
97 
98 	if (changed & BSS_CHANGED_ERP_SLOT) {
99 		int slottime = info->use_short_slot ? 9 : 20;
100 
101 		mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG,
102 			       MT_BKOFF_SLOT_CFG_SLOTTIME, slottime);
103 	}
104 
105 	if (changed & BSS_CHANGED_ASSOC)
106 		mt76x0_phy_recalibrate_after_assoc(dev);
107 
108 	mutex_unlock(&dev->mt76.mutex);
109 }
110 EXPORT_SYMBOL_GPL(mt76x0_bss_info_changed);
111 
112 void mt76x0_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
113 		    const u8 *mac_addr)
114 {
115 	struct mt76x02_dev *dev = hw->priv;
116 
117 	cancel_delayed_work_sync(&dev->cal_work);
118 	mt76x0_agc_save(dev);
119 	set_bit(MT76_SCANNING, &dev->mt76.state);
120 }
121 EXPORT_SYMBOL_GPL(mt76x0_sw_scan);
122 
123 void mt76x0_sw_scan_complete(struct ieee80211_hw *hw,
124 			     struct ieee80211_vif *vif)
125 {
126 	struct mt76x02_dev *dev = hw->priv;
127 
128 	mt76x0_agc_restore(dev);
129 	clear_bit(MT76_SCANNING, &dev->mt76.state);
130 
131 	ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
132 				     MT_CALIBRATE_INTERVAL);
133 }
134 EXPORT_SYMBOL_GPL(mt76x0_sw_scan_complete);
135 
136 int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
137 {
138 	struct mt76x02_dev *dev = hw->priv;
139 
140 	mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, value);
141 
142 	return 0;
143 }
144 EXPORT_SYMBOL_GPL(mt76x0_set_rts_threshold);
145