2 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
17 #include <linux/etherdevice.h>
19 static int mt7601u_start(struct ieee80211_hw
*hw
)
21 struct mt7601u_dev
*dev
= hw
->priv
;
24 mutex_lock(&dev
->mutex
);
26 ret
= mt7601u_mac_start(dev
);
30 ieee80211_queue_delayed_work(dev
->hw
, &dev
->mac_work
,
31 MT_CALIBRATE_INTERVAL
);
32 ieee80211_queue_delayed_work(dev
->hw
, &dev
->cal_work
,
33 MT_CALIBRATE_INTERVAL
);
35 mutex_unlock(&dev
->mutex
);
39 static void mt7601u_stop(struct ieee80211_hw
*hw
)
41 struct mt7601u_dev
*dev
= hw
->priv
;
43 mutex_lock(&dev
->mutex
);
45 cancel_delayed_work_sync(&dev
->cal_work
);
46 cancel_delayed_work_sync(&dev
->mac_work
);
47 mt7601u_mac_stop(dev
);
49 mutex_unlock(&dev
->mutex
);
52 static int mt7601u_add_interface(struct ieee80211_hw
*hw
,
53 struct ieee80211_vif
*vif
)
55 struct mt7601u_dev
*dev
= hw
->priv
;
56 struct mt76_vif
*mvif
= (struct mt76_vif
*) vif
->drv_priv
;
58 unsigned int wcid
= GROUP_WCID(idx
);
60 /* Note: for AP do the AP-STA things mt76 does:
62 * - do mac address tricks
67 if (dev
->wcid_mask
[wcid
/ BITS_PER_LONG
] & BIT(wcid
% BITS_PER_LONG
))
69 dev
->wcid_mask
[wcid
/ BITS_PER_LONG
] |= BIT(wcid
% BITS_PER_LONG
);
70 mvif
->group_wcid
.idx
= wcid
;
71 mvif
->group_wcid
.hw_key_idx
= -1;
76 static void mt7601u_remove_interface(struct ieee80211_hw
*hw
,
77 struct ieee80211_vif
*vif
)
79 struct mt7601u_dev
*dev
= hw
->priv
;
80 struct mt76_vif
*mvif
= (struct mt76_vif
*) vif
->drv_priv
;
81 unsigned int wcid
= mvif
->group_wcid
.idx
;
83 dev
->wcid_mask
[wcid
/ BITS_PER_LONG
] &= ~BIT(wcid
% BITS_PER_LONG
);
86 static int mt7601u_config(struct ieee80211_hw
*hw
, u32 changed
)
88 struct mt7601u_dev
*dev
= hw
->priv
;
91 mutex_lock(&dev
->mutex
);
93 if (changed
& IEEE80211_CONF_CHANGE_CHANNEL
) {
94 ieee80211_stop_queues(hw
);
95 ret
= mt7601u_phy_set_channel(dev
, &hw
->conf
.chandef
);
96 ieee80211_wake_queues(hw
);
99 mutex_unlock(&dev
->mutex
);
105 mt76_configure_filter(struct ieee80211_hw
*hw
, unsigned int changed_flags
,
106 unsigned int *total_flags
, u64 multicast
)
108 struct mt7601u_dev
*dev
= hw
->priv
;
111 #define MT76_FILTER(_flag, _hw) do { \
112 flags |= *total_flags & FIF_##_flag; \
113 dev->rxfilter &= ~(_hw); \
114 dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \
117 mutex_lock(&dev
->mutex
);
119 dev
->rxfilter
&= ~MT_RX_FILTR_CFG_OTHER_BSS
;
121 MT76_FILTER(OTHER_BSS
, MT_RX_FILTR_CFG_PROMISC
);
122 MT76_FILTER(FCSFAIL
, MT_RX_FILTR_CFG_CRC_ERR
);
123 MT76_FILTER(PLCPFAIL
, MT_RX_FILTR_CFG_PHY_ERR
);
124 MT76_FILTER(CONTROL
, MT_RX_FILTR_CFG_ACK
|
125 MT_RX_FILTR_CFG_CTS
|
126 MT_RX_FILTR_CFG_CFEND
|
127 MT_RX_FILTR_CFG_CFACK
|
129 MT_RX_FILTR_CFG_CTRL_RSV
);
130 MT76_FILTER(PSPOLL
, MT_RX_FILTR_CFG_PSPOLL
);
132 *total_flags
= flags
;
133 mt76_wr(dev
, MT_RX_FILTR_CFG
, dev
->rxfilter
);
135 mutex_unlock(&dev
->mutex
);
139 mt7601u_bss_info_changed(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
140 struct ieee80211_bss_conf
*info
, u32 changed
)
142 struct mt7601u_dev
*dev
= hw
->priv
;
144 mutex_lock(&dev
->mutex
);
146 if (changed
& BSS_CHANGED_ASSOC
)
147 mt7601u_phy_con_cal_onoff(dev
, info
);
149 if (changed
& BSS_CHANGED_BSSID
) {
150 mt7601u_addr_wr(dev
, MT_MAC_BSSID_DW0
, info
->bssid
);
152 /* Note: this is a hack because beacon_int is not changed
153 * on leave nor is any more appropriate event generated.
154 * rt2x00 doesn't seem to be bothered though.
156 if (is_zero_ether_addr(info
->bssid
))
157 mt7601u_mac_config_tsf(dev
, false, 0);
160 if (changed
& BSS_CHANGED_BASIC_RATES
) {
161 mt7601u_wr(dev
, MT_LEGACY_BASIC_RATE
, info
->basic_rates
);
162 mt7601u_wr(dev
, MT_HT_FBK_CFG0
, 0x65432100);
163 mt7601u_wr(dev
, MT_HT_FBK_CFG1
, 0xedcba980);
164 mt7601u_wr(dev
, MT_LG_FBK_CFG0
, 0xedcba988);
165 mt7601u_wr(dev
, MT_LG_FBK_CFG1
, 0x00002100);
168 if (changed
& BSS_CHANGED_BEACON_INT
)
169 mt7601u_mac_config_tsf(dev
, true, info
->beacon_int
);
171 if (changed
& BSS_CHANGED_HT
|| changed
& BSS_CHANGED_ERP_CTS_PROT
)
172 mt7601u_mac_set_protection(dev
, info
->use_cts_prot
,
173 info
->ht_operation_mode
);
175 if (changed
& BSS_CHANGED_ERP_PREAMBLE
)
176 mt7601u_mac_set_short_preamble(dev
, info
->use_short_preamble
);
178 if (changed
& BSS_CHANGED_ERP_SLOT
) {
179 int slottime
= info
->use_short_slot
? 9 : 20;
181 mt76_rmw_field(dev
, MT_BKOFF_SLOT_CFG
,
182 MT_BKOFF_SLOT_CFG_SLOTTIME
, slottime
);
185 if (changed
& BSS_CHANGED_ASSOC
)
186 mt7601u_phy_recalibrate_after_assoc(dev
);
188 mutex_unlock(&dev
->mutex
);
192 mt76_wcid_alloc(struct mt7601u_dev
*dev
)
196 for (i
= 0; i
< ARRAY_SIZE(dev
->wcid_mask
); i
++) {
197 idx
= ffs(~dev
->wcid_mask
[i
]);
202 dev
->wcid_mask
[i
] |= BIT(idx
);
206 idx
= i
* BITS_PER_LONG
+ idx
;
214 mt7601u_sta_add(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
215 struct ieee80211_sta
*sta
)
217 struct mt7601u_dev
*dev
= hw
->priv
;
218 struct mt76_sta
*msta
= (struct mt76_sta
*) sta
->drv_priv
;
219 struct mt76_vif
*mvif
= (struct mt76_vif
*) vif
->drv_priv
;
223 mutex_lock(&dev
->mutex
);
225 idx
= mt76_wcid_alloc(dev
);
231 msta
->wcid
.idx
= idx
;
232 msta
->wcid
.hw_key_idx
= -1;
233 mt7601u_mac_wcid_setup(dev
, idx
, mvif
->idx
, sta
->addr
);
234 mt76_clear(dev
, MT_WCID_DROP(idx
), MT_WCID_DROP_MASK(idx
));
235 rcu_assign_pointer(dev
->wcid
[idx
], &msta
->wcid
);
236 mt7601u_mac_set_ampdu_factor(dev
);
239 mutex_unlock(&dev
->mutex
);
245 mt7601u_sta_remove(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
246 struct ieee80211_sta
*sta
)
248 struct mt7601u_dev
*dev
= hw
->priv
;
249 struct mt76_sta
*msta
= (struct mt76_sta
*) sta
->drv_priv
;
250 int idx
= msta
->wcid
.idx
;
252 mutex_lock(&dev
->mutex
);
253 rcu_assign_pointer(dev
->wcid
[idx
], NULL
);
254 mt76_set(dev
, MT_WCID_DROP(idx
), MT_WCID_DROP_MASK(idx
));
255 dev
->wcid_mask
[idx
/ BITS_PER_LONG
] &= ~BIT(idx
% BITS_PER_LONG
);
256 mt7601u_mac_wcid_setup(dev
, idx
, 0, NULL
);
257 mt7601u_mac_set_ampdu_factor(dev
);
258 mutex_unlock(&dev
->mutex
);
264 mt7601u_sta_notify(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
265 enum sta_notify_cmd cmd
, struct ieee80211_sta
*sta
)
270 mt7601u_sw_scan(struct ieee80211_hw
*hw
,
271 struct ieee80211_vif
*vif
,
274 struct mt7601u_dev
*dev
= hw
->priv
;
276 mt7601u_agc_save(dev
);
277 set_bit(MT7601U_STATE_SCANNING
, &dev
->state
);
281 mt7601u_sw_scan_complete(struct ieee80211_hw
*hw
,
282 struct ieee80211_vif
*vif
)
284 struct mt7601u_dev
*dev
= hw
->priv
;
286 mt7601u_agc_restore(dev
);
287 clear_bit(MT7601U_STATE_SCANNING
, &dev
->state
);
291 mt7601u_set_key(struct ieee80211_hw
*hw
, enum set_key_cmd cmd
,
292 struct ieee80211_vif
*vif
, struct ieee80211_sta
*sta
,
293 struct ieee80211_key_conf
*key
)
295 struct mt7601u_dev
*dev
= hw
->priv
;
296 struct mt76_vif
*mvif
= (struct mt76_vif
*) vif
->drv_priv
;
297 struct mt76_sta
*msta
= sta
? (struct mt76_sta
*) sta
->drv_priv
: NULL
;
298 struct mt76_wcid
*wcid
= msta
? &msta
->wcid
: &mvif
->group_wcid
;
299 int idx
= key
->keyidx
;
302 if (cmd
== SET_KEY
) {
303 key
->hw_key_idx
= wcid
->idx
;
304 wcid
->hw_key_idx
= idx
;
306 if (idx
== wcid
->hw_key_idx
)
307 wcid
->hw_key_idx
= -1;
313 if (key
|| wcid
->hw_key_idx
== idx
) {
314 ret
= mt76_mac_wcid_set_key(dev
, wcid
->idx
, key
);
319 return mt76_mac_shared_key_setup(dev
, mvif
->idx
, idx
, key
);
322 return mt76_mac_wcid_set_key(dev
, msta
->wcid
.idx
, key
);
325 static int mt7601u_set_rts_threshold(struct ieee80211_hw
*hw
, u32 value
)
327 struct mt7601u_dev
*dev
= hw
->priv
;
329 mt76_rmw_field(dev
, MT_TX_RTS_CFG
, MT_TX_RTS_CFG_THRESH
, value
);
335 mt76_ampdu_action(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
336 struct ieee80211_ampdu_params
*params
)
338 struct mt7601u_dev
*dev
= hw
->priv
;
339 struct ieee80211_sta
*sta
= params
->sta
;
340 enum ieee80211_ampdu_mlme_action action
= params
->action
;
341 u16 tid
= params
->tid
;
342 u16
*ssn
= ¶ms
->ssn
;
343 struct mt76_sta
*msta
= (struct mt76_sta
*) sta
->drv_priv
;
345 WARN_ON(msta
->wcid
.idx
> GROUP_WCID(0));
348 case IEEE80211_AMPDU_RX_START
:
349 mt76_set(dev
, MT_WCID_ADDR(msta
->wcid
.idx
) + 4, BIT(16 + tid
));
351 case IEEE80211_AMPDU_RX_STOP
:
352 mt76_clear(dev
, MT_WCID_ADDR(msta
->wcid
.idx
) + 4,
355 case IEEE80211_AMPDU_TX_OPERATIONAL
:
356 ieee80211_send_bar(vif
, sta
->addr
, tid
, msta
->agg_ssn
[tid
]);
358 case IEEE80211_AMPDU_TX_STOP_FLUSH
:
359 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT
:
361 case IEEE80211_AMPDU_TX_START
:
362 msta
->agg_ssn
[tid
] = *ssn
<< 4;
363 ieee80211_start_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
365 case IEEE80211_AMPDU_TX_STOP_CONT
:
366 ieee80211_stop_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
374 mt76_sta_rate_tbl_update(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
375 struct ieee80211_sta
*sta
)
377 struct mt7601u_dev
*dev
= hw
->priv
;
378 struct mt76_sta
*msta
= (struct mt76_sta
*) sta
->drv_priv
;
379 struct ieee80211_sta_rates
*rates
;
380 struct ieee80211_tx_rate rate
= {};
383 rates
= rcu_dereference(sta
->rates
);
388 rate
.idx
= rates
->rate
[0].idx
;
389 rate
.flags
= rates
->rate
[0].flags
;
390 mt76_mac_wcid_set_rate(dev
, &msta
->wcid
, &rate
);
396 const struct ieee80211_ops mt7601u_ops
= {
398 .start
= mt7601u_start
,
399 .stop
= mt7601u_stop
,
400 .add_interface
= mt7601u_add_interface
,
401 .remove_interface
= mt7601u_remove_interface
,
402 .config
= mt7601u_config
,
403 .configure_filter
= mt76_configure_filter
,
404 .bss_info_changed
= mt7601u_bss_info_changed
,
405 .sta_add
= mt7601u_sta_add
,
406 .sta_remove
= mt7601u_sta_remove
,
407 .sta_notify
= mt7601u_sta_notify
,
408 .set_key
= mt7601u_set_key
,
409 .conf_tx
= mt7601u_conf_tx
,
410 .sw_scan_start
= mt7601u_sw_scan
,
411 .sw_scan_complete
= mt7601u_sw_scan_complete
,
412 .ampdu_action
= mt76_ampdu_action
,
413 .sta_rate_tbl_update
= mt76_sta_rate_tbl_update
,
414 .set_rts_threshold
= mt7601u_set_rts_threshold
,