]>
Commit | Line | Data |
---|---|---|
7bc04215 FF |
1 | /* |
2 | * Copyright (C) 2016 Felix Fietkau <[email protected]> | |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include "mt76x2.h" | |
18 | ||
19 | static int | |
20 | mt76x2_start(struct ieee80211_hw *hw) | |
21 | { | |
e40803f2 | 22 | struct mt76x02_dev *dev = hw->priv; |
7bc04215 FF |
23 | int ret; |
24 | ||
108a4861 | 25 | mutex_lock(&dev->mt76.mutex); |
7bc04215 FF |
26 | |
27 | ret = mt76x2_mac_start(dev); | |
28 | if (ret) | |
29 | goto out; | |
30 | ||
31 | ret = mt76x2_phy_start(dev); | |
32 | if (ret) | |
33 | goto out; | |
34 | ||
35 | ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, | |
36 | MT_CALIBRATE_INTERVAL); | |
37 | ||
38 | set_bit(MT76_STATE_RUNNING, &dev->mt76.state); | |
39 | ||
40 | out: | |
108a4861 | 41 | mutex_unlock(&dev->mt76.mutex); |
7bc04215 FF |
42 | return ret; |
43 | } | |
44 | ||
45 | static void | |
46 | mt76x2_stop(struct ieee80211_hw *hw) | |
47 | { | |
e40803f2 | 48 | struct mt76x02_dev *dev = hw->priv; |
7bc04215 | 49 | |
108a4861 | 50 | mutex_lock(&dev->mt76.mutex); |
7bc04215 FF |
51 | clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); |
52 | mt76x2_stop_hardware(dev); | |
108a4861 | 53 | mutex_unlock(&dev->mt76.mutex); |
7bc04215 FF |
54 | } |
55 | ||
7bc04215 | 56 | static int |
e40803f2 | 57 | mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) |
7bc04215 FF |
58 | { |
59 | int ret; | |
60 | ||
a164a942 FF |
61 | cancel_delayed_work_sync(&dev->cal_work); |
62 | ||
63 | set_bit(MT76_RESET, &dev->mt76.state); | |
64 | ||
7bc04215 FF |
65 | mt76_set_channel(&dev->mt76); |
66 | ||
67 | tasklet_disable(&dev->pre_tbtt_tasklet); | |
8c9f6491 | 68 | tasklet_disable(&dev->dfs_pd.dfs_tasklet); |
7bc04215 FF |
69 | |
70 | mt76x2_mac_stop(dev, true); | |
71 | ret = mt76x2_phy_set_channel(dev, chandef); | |
72 | ||
73 | /* channel cycle counters read-and-clear */ | |
74 | mt76_rr(dev, MT_CH_IDLE); | |
75 | mt76_rr(dev, MT_CH_BUSY); | |
76 | ||
77 | mt76x2_dfs_init_params(dev); | |
78 | ||
79 | mt76x2_mac_resume(dev); | |
8c9f6491 | 80 | tasklet_enable(&dev->dfs_pd.dfs_tasklet); |
7bc04215 FF |
81 | tasklet_enable(&dev->pre_tbtt_tasklet); |
82 | ||
a164a942 FF |
83 | clear_bit(MT76_RESET, &dev->mt76.state); |
84 | ||
85 | mt76_txq_schedule_all(&dev->mt76); | |
86 | ||
7bc04215 FF |
87 | return ret; |
88 | } | |
89 | ||
90 | static int | |
91 | mt76x2_config(struct ieee80211_hw *hw, u32 changed) | |
92 | { | |
e40803f2 | 93 | struct mt76x02_dev *dev = hw->priv; |
7bc04215 FF |
94 | int ret = 0; |
95 | ||
108a4861 | 96 | mutex_lock(&dev->mt76.mutex); |
7bc04215 | 97 | |
e8be626d FF |
98 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { |
99 | if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) | |
108a4861 | 100 | dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC; |
e8be626d | 101 | else |
108a4861 | 102 | dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; |
e8be626d | 103 | |
108a4861 | 104 | mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); |
e8be626d FF |
105 | } |
106 | ||
7bc04215 | 107 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
b6862eff | 108 | dev->mt76.txpower_conf = hw->conf.power_level * 2; |
7bc04215 | 109 | |
53aa29b2 | 110 | /* convert to per-chain power for 2x2 devices */ |
b6862eff | 111 | dev->mt76.txpower_conf -= 6; |
53aa29b2 | 112 | |
7bc04215 FF |
113 | if (test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) { |
114 | mt76x2_phy_set_txpower(dev); | |
1ea0a1b1 | 115 | mt76x02_tx_set_txpwr_auto(dev, dev->mt76.txpower_conf); |
7bc04215 FF |
116 | } |
117 | } | |
118 | ||
119 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | |
120 | ieee80211_stop_queues(hw); | |
121 | ret = mt76x2_set_channel(dev, &hw->conf.chandef); | |
122 | ieee80211_wake_queues(hw); | |
123 | } | |
124 | ||
108a4861 | 125 | mutex_unlock(&dev->mt76.mutex); |
7bc04215 FF |
126 | |
127 | return ret; | |
128 | } | |
129 | ||
7bc04215 FF |
130 | static void |
131 | mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |
132 | struct ieee80211_bss_conf *info, u32 changed) | |
133 | { | |
e40803f2 | 134 | struct mt76x02_dev *dev = hw->priv; |
98ff26e5 | 135 | struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv; |
7bc04215 | 136 | |
108a4861 | 137 | mutex_lock(&dev->mt76.mutex); |
7bc04215 FF |
138 | |
139 | if (changed & BSS_CHANGED_BSSID) | |
140 | mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid); | |
141 | ||
aea38272 | 142 | if (changed & BSS_CHANGED_BEACON_INT) { |
7bc04215 FF |
143 | mt76_rmw_field(dev, MT_BEACON_TIME_CFG, |
144 | MT_BEACON_TIME_CFG_INTVAL, | |
145 | info->beacon_int << 4); | |
aea38272 FF |
146 | dev->beacon_int = info->beacon_int; |
147 | dev->tbtt_count = 0; | |
148 | } | |
7bc04215 FF |
149 | |
150 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | |
151 | tasklet_disable(&dev->pre_tbtt_tasklet); | |
152 | mt76x2_mac_set_beacon_enable(dev, mvif->idx, | |
153 | info->enable_beacon); | |
154 | tasklet_enable(&dev->pre_tbtt_tasklet); | |
155 | } | |
156 | ||
157 | if (changed & BSS_CHANGED_ERP_SLOT) { | |
158 | int slottime = info->use_short_slot ? 9 : 20; | |
159 | ||
160 | dev->slottime = slottime; | |
0d45d3fe | 161 | mt76x2_set_tx_ackto(dev); |
7bc04215 FF |
162 | } |
163 | ||
108a4861 | 164 | mutex_unlock(&dev->mt76.mutex); |
7bc04215 FF |
165 | } |
166 | ||
d71ef286 FF |
167 | void |
168 | mt76x2_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) | |
7bc04215 | 169 | { |
b2d91fb3 | 170 | struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; |
e40803f2 | 171 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); |
7bc04215 FF |
172 | int idx = msta->wcid.idx; |
173 | ||
11b2a25f | 174 | mt76_stop_tx_queues(&dev->mt76, sta, true); |
8d66af49 | 175 | mt76x02_mac_wcid_set_drop(dev, idx, ps); |
7bc04215 FF |
176 | } |
177 | ||
7bc04215 FF |
178 | static void |
179 | mt76x2_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |
180 | const u8 *mac) | |
181 | { | |
e40803f2 | 182 | struct mt76x02_dev *dev = hw->priv; |
7bc04215 FF |
183 | |
184 | tasklet_disable(&dev->pre_tbtt_tasklet); | |
185 | set_bit(MT76_SCANNING, &dev->mt76.state); | |
186 | } | |
187 | ||
188 | static void | |
189 | mt76x2_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |
190 | { | |
e40803f2 | 191 | struct mt76x02_dev *dev = hw->priv; |
7bc04215 FF |
192 | |
193 | clear_bit(MT76_SCANNING, &dev->mt76.state); | |
194 | tasklet_enable(&dev->pre_tbtt_tasklet); | |
7bc04215 FF |
195 | } |
196 | ||
197 | static void | |
198 | mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |
199 | u32 queues, bool drop) | |
200 | { | |
201 | } | |
202 | ||
203 | static int | |
204 | mt76x2_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) | |
205 | { | |
e40803f2 | 206 | struct mt76x02_dev *dev = hw->priv; |
7bc04215 | 207 | |
b6862eff | 208 | *dbm = dev->mt76.txpower_cur / 2; |
53aa29b2 FF |
209 | |
210 | /* convert from per-chain power to combined output on 2x2 devices */ | |
211 | *dbm += 3; | |
212 | ||
7bc04215 FF |
213 | return 0; |
214 | } | |
215 | ||
7bc04215 FF |
216 | static void mt76x2_set_coverage_class(struct ieee80211_hw *hw, |
217 | s16 coverage_class) | |
218 | { | |
e40803f2 | 219 | struct mt76x02_dev *dev = hw->priv; |
7bc04215 | 220 | |
108a4861 | 221 | mutex_lock(&dev->mt76.mutex); |
7bc04215 FF |
222 | dev->coverage_class = coverage_class; |
223 | mt76x2_set_tx_ackto(dev); | |
108a4861 | 224 | mutex_unlock(&dev->mt76.mutex); |
7bc04215 FF |
225 | } |
226 | ||
d71ef286 FF |
227 | static int |
228 | mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) | |
229 | { | |
230 | return 0; | |
231 | } | |
232 | ||
5ebdc3e0 LB |
233 | static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, |
234 | u32 rx_ant) | |
235 | { | |
e40803f2 | 236 | struct mt76x02_dev *dev = hw->priv; |
5ebdc3e0 LB |
237 | |
238 | if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant) | |
239 | return -EINVAL; | |
240 | ||
108a4861 | 241 | mutex_lock(&dev->mt76.mutex); |
5ebdc3e0 | 242 | |
6034b2b0 | 243 | dev->mt76.chainmask = (tx_ant == 3) ? 0x202 : 0x101; |
5ebdc3e0 LB |
244 | dev->mt76.antenna_mask = tx_ant; |
245 | ||
246 | mt76_set_stream_caps(&dev->mt76, true); | |
247 | mt76x2_phy_set_antenna(dev); | |
248 | ||
108a4861 | 249 | mutex_unlock(&dev->mt76.mutex); |
5ebdc3e0 LB |
250 | |
251 | return 0; | |
252 | } | |
253 | ||
254 | static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, | |
255 | u32 *rx_ant) | |
256 | { | |
e40803f2 | 257 | struct mt76x02_dev *dev = hw->priv; |
5ebdc3e0 | 258 | |
108a4861 | 259 | mutex_lock(&dev->mt76.mutex); |
5ebdc3e0 LB |
260 | *tx_ant = dev->mt76.antenna_mask; |
261 | *rx_ant = dev->mt76.antenna_mask; | |
108a4861 | 262 | mutex_unlock(&dev->mt76.mutex); |
5ebdc3e0 LB |
263 | |
264 | return 0; | |
265 | } | |
266 | ||
f24909ab LB |
267 | static int |
268 | mt76x2_set_rts_threshold(struct ieee80211_hw *hw, u32 val) | |
269 | { | |
e40803f2 | 270 | struct mt76x02_dev *dev = hw->priv; |
f24909ab LB |
271 | |
272 | if (val != ~0 && val > 0xffff) | |
273 | return -EINVAL; | |
274 | ||
1770f0fa | 275 | mutex_lock(&dev->mt76.mutex); |
f24909ab | 276 | mt76x2_mac_set_tx_protection(dev, val); |
1770f0fa | 277 | mutex_unlock(&dev->mt76.mutex); |
f24909ab LB |
278 | |
279 | return 0; | |
280 | } | |
281 | ||
7bc04215 | 282 | const struct ieee80211_ops mt76x2_ops = { |
2f0308d0 | 283 | .tx = mt76x02_tx, |
7bc04215 FF |
284 | .start = mt76x2_start, |
285 | .stop = mt76x2_stop, | |
212926eb | 286 | .add_interface = mt76x02_add_interface, |
0cd47bae | 287 | .remove_interface = mt76x02_remove_interface, |
7bc04215 | 288 | .config = mt76x2_config, |
108a4861 | 289 | .configure_filter = mt76x02_configure_filter, |
7bc04215 | 290 | .bss_info_changed = mt76x2_bss_info_changed, |
624400e4 SG |
291 | .sta_add = mt76x02_sta_add, |
292 | .sta_remove = mt76x02_sta_remove, | |
60c26859 | 293 | .set_key = mt76x02_set_key, |
10337263 | 294 | .conf_tx = mt76x02_conf_tx, |
7bc04215 FF |
295 | .sw_scan_start = mt76x2_sw_scan, |
296 | .sw_scan_complete = mt76x2_sw_scan_complete, | |
297 | .flush = mt76x2_flush, | |
22c575c4 | 298 | .ampdu_action = mt76x02_ampdu_action, |
7bc04215 FF |
299 | .get_txpower = mt76x2_get_txpower, |
300 | .wake_tx_queue = mt76_wake_tx_queue, | |
5327b5ea | 301 | .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, |
7bc04215 FF |
302 | .release_buffered_frames = mt76_release_buffered_frames, |
303 | .set_coverage_class = mt76x2_set_coverage_class, | |
304 | .get_survey = mt76_get_survey, | |
d71ef286 | 305 | .set_tim = mt76x2_set_tim, |
5ebdc3e0 LB |
306 | .set_antenna = mt76x2_set_antenna, |
307 | .get_antenna = mt76x2_get_antenna, | |
f24909ab | 308 | .set_rts_threshold = mt76x2_set_rts_threshold, |
7bc04215 FF |
309 | }; |
310 |