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>
18 #include <linux/version.h>
20 static int mt7601u_start(struct ieee80211_hw
*hw
)
22 struct mt7601u_dev
*dev
= hw
->priv
;
25 mutex_lock(&dev
->mutex
);
27 ret
= mt7601u_mac_start(dev
);
31 ieee80211_queue_delayed_work(dev
->hw
, &dev
->mac_work
,
32 MT_CALIBRATE_INTERVAL
);
33 ieee80211_queue_delayed_work(dev
->hw
, &dev
->cal_work
,
34 MT_CALIBRATE_INTERVAL
);
36 mutex_unlock(&dev
->mutex
);
40 static void mt7601u_stop(struct ieee80211_hw
*hw
)
42 struct mt7601u_dev
*dev
= hw
->priv
;
44 mutex_lock(&dev
->mutex
);
46 cancel_delayed_work_sync(&dev
->cal_work
);
47 cancel_delayed_work_sync(&dev
->mac_work
);
48 mt7601u_mac_stop(dev
);
50 mutex_unlock(&dev
->mutex
);
53 static int mt7601u_add_interface(struct ieee80211_hw
*hw
,
54 struct ieee80211_vif
*vif
)
56 struct mt7601u_dev
*dev
= hw
->priv
;
57 struct mt76_vif
*mvif
= (struct mt76_vif
*) vif
->drv_priv
;
59 unsigned int wcid
= GROUP_WCID(idx
);
61 /* Note: for AP do the AP-STA things mt76 does:
63 * - do mac address tricks
68 if (dev
->wcid_mask
[wcid
/ BITS_PER_LONG
] & BIT(wcid
% BITS_PER_LONG
))
70 dev
->wcid_mask
[wcid
/ BITS_PER_LONG
] |= BIT(wcid
% BITS_PER_LONG
);
71 mvif
->group_wcid
.idx
= wcid
;
72 mvif
->group_wcid
.hw_key_idx
= -1;
77 static void mt7601u_remove_interface(struct ieee80211_hw
*hw
,
78 struct ieee80211_vif
*vif
)
80 struct mt7601u_dev
*dev
= hw
->priv
;
81 struct mt76_vif
*mvif
= (struct mt76_vif
*) vif
->drv_priv
;
82 unsigned int wcid
= mvif
->group_wcid
.idx
;
84 dev
->wcid_mask
[wcid
/ BITS_PER_LONG
] &= ~BIT(wcid
% BITS_PER_LONG
);
87 static int mt7601u_config(struct ieee80211_hw
*hw
, u32 changed
)
89 struct mt7601u_dev
*dev
= hw
->priv
;
92 mutex_lock(&dev
->mutex
);
94 if (changed
& IEEE80211_CONF_CHANGE_CHANNEL
) {
95 ieee80211_stop_queues(hw
);
96 ret
= mt7601u_phy_set_channel(dev
, &hw
->conf
.chandef
);
97 ieee80211_wake_queues(hw
);
100 mutex_unlock(&dev
->mutex
);
106 mt76_configure_filter(struct ieee80211_hw
*hw
, unsigned int changed_flags
,
107 unsigned int *total_flags
, u64 multicast
)
109 struct mt7601u_dev
*dev
= hw
->priv
;
112 #define MT76_FILTER(_flag, _hw) do { \
113 flags |= *total_flags & FIF_##_flag; \
114 dev->rxfilter &= ~(_hw); \
115 dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \
118 mutex_lock(&dev
->mutex
);
120 dev
->rxfilter
&= ~MT_RX_FILTR_CFG_OTHER_BSS
;
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 enum ieee80211_ampdu_mlme_action action
,
337 struct ieee80211_sta
*sta
, u16 tid
, u16
*ssn
, u8 buf_size
)
339 struct mt7601u_dev
*dev
= hw
->priv
;
340 struct mt76_sta
*msta
= (struct mt76_sta
*) sta
->drv_priv
;
342 WARN_ON(msta
->wcid
.idx
> GROUP_WCID(0));
345 case IEEE80211_AMPDU_RX_START
:
346 mt76_set(dev
, MT_WCID_ADDR(msta
->wcid
.idx
) + 4, BIT(16 + tid
));
348 case IEEE80211_AMPDU_RX_STOP
:
349 mt76_clear(dev
, MT_WCID_ADDR(msta
->wcid
.idx
) + 4,
352 case IEEE80211_AMPDU_TX_OPERATIONAL
:
353 ieee80211_send_bar(vif
, sta
->addr
, tid
, msta
->agg_ssn
[tid
]);
355 case IEEE80211_AMPDU_TX_STOP_FLUSH
:
356 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT
:
358 case IEEE80211_AMPDU_TX_START
:
359 msta
->agg_ssn
[tid
] = *ssn
<< 4;
360 ieee80211_start_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
362 case IEEE80211_AMPDU_TX_STOP_CONT
:
363 ieee80211_stop_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
371 mt76_sta_rate_tbl_update(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
372 struct ieee80211_sta
*sta
)
374 struct mt7601u_dev
*dev
= hw
->priv
;
375 struct mt76_sta
*msta
= (struct mt76_sta
*) sta
->drv_priv
;
376 struct ieee80211_sta_rates
*rates
;
377 struct ieee80211_tx_rate rate
= {};
380 rates
= rcu_dereference(sta
->rates
);
385 rate
.idx
= rates
->rate
[0].idx
;
386 rate
.flags
= rates
->rate
[0].flags
;
387 mt76_mac_wcid_set_rate(dev
, &msta
->wcid
, &rate
);
393 const struct ieee80211_ops mt7601u_ops
= {
395 .start
= mt7601u_start
,
396 .stop
= mt7601u_stop
,
397 .add_interface
= mt7601u_add_interface
,
398 .remove_interface
= mt7601u_remove_interface
,
399 .config
= mt7601u_config
,
400 .configure_filter
= mt76_configure_filter
,
401 .bss_info_changed
= mt7601u_bss_info_changed
,
402 .sta_add
= mt7601u_sta_add
,
403 .sta_remove
= mt7601u_sta_remove
,
404 .sta_notify
= mt7601u_sta_notify
,
405 .set_key
= mt7601u_set_key
,
406 .conf_tx
= mt7601u_conf_tx
,
407 .sw_scan_start
= mt7601u_sw_scan
,
408 .sw_scan_complete
= mt7601u_sw_scan_complete
,
409 .ampdu_action
= mt76_ampdu_action
,
410 .sta_rate_tbl_update
= mt76_sta_rate_tbl_update
,
411 .set_rts_threshold
= mt7601u_set_rts_threshold
,