1 // SPDX-License-Identifier: GPL-2.0-only
3 * Implementation of mac80211 API.
5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
6 * Copyright (c) 2010, ST-Ericsson
8 #include <linux/etherdevice.h>
9 #include <net/mac80211.h>
19 #include "hif_tx_mib.h"
21 #define HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES 2
23 u32
wfx_rate_mask_to_hw(struct wfx_dev
*wdev
, u32 rates
)
27 // WFx only support 2GHz
28 struct ieee80211_supported_band
*sband
= wdev
->hw
->wiphy
->bands
[NL80211_BAND_2GHZ
];
30 for (i
= 0; i
< sband
->n_bitrates
; i
++) {
32 if (i
>= sband
->n_bitrates
)
33 dev_warn(wdev
->dev
, "unsupported basic rate\n");
35 ret
|= BIT(sband
->bitrates
[i
].hw_value
);
41 void wfx_cooling_timeout_work(struct work_struct
*work
)
43 struct wfx_dev
*wdev
= container_of(to_delayed_work(work
),
45 cooling_timeout_work
);
47 wdev
->chip_frozen
= true;
51 void wfx_suspend_hot_dev(struct wfx_dev
*wdev
, enum sta_notify_cmd cmd
)
53 if (cmd
== STA_NOTIFY_AWAKE
) {
54 // Device recover normal temperature
55 if (cancel_delayed_work(&wdev
->cooling_timeout_work
))
59 schedule_delayed_work(&wdev
->cooling_timeout_work
, 10 * HZ
);
64 static void wfx_filter_beacon(struct wfx_vif
*wvif
, bool filter_beacon
)
66 static const struct hif_ie_table_entry filter_ies
[] = {
68 .ie_id
= WLAN_EID_VENDOR_SPECIFIC
,
72 .oui
= { 0x50, 0x6F, 0x9A },
74 .ie_id
= WLAN_EID_HT_OPERATION
,
79 .ie_id
= WLAN_EID_ERP_INFO
,
87 hif_beacon_filter_control(wvif
, 0, 1);
89 hif_set_beacon_filter_table(wvif
, 3, filter_ies
);
90 hif_beacon_filter_control(wvif
, HIF_BEACON_FILTER_ENABLE
, 0);
94 void wfx_configure_filter(struct ieee80211_hw
*hw
, unsigned int changed_flags
,
95 unsigned int *total_flags
, u64 unused
)
97 struct wfx_vif
*wvif
= NULL
;
98 struct wfx_dev
*wdev
= hw
->priv
;
99 bool filter_bssid
, filter_prbreq
, filter_beacon
;
102 // - Probe responses (FIF_BCN_PRBRESP_PROMISC) are never filtered
103 // - PS-Poll (FIF_PSPOLL) are never filtered
104 // - RTS, CTS and Ack (FIF_CONTROL) are always filtered
105 // - Broken frames (FIF_FCSFAIL and FIF_PLCPFAIL) are always filtered
106 // - Firmware does (yet) allow to forward unicast traffic sent to
107 // other stations (aka. promiscuous mode)
108 *total_flags
&= FIF_BCN_PRBRESP_PROMISC
| FIF_ALLMULTI
| FIF_OTHER_BSS
|
109 FIF_PROBE_REQ
| FIF_PSPOLL
;
111 mutex_lock(&wdev
->conf_mutex
);
112 while ((wvif
= wvif_iterate(wdev
, wvif
)) != NULL
) {
113 mutex_lock(&wvif
->scan_lock
);
115 // Note: FIF_BCN_PRBRESP_PROMISC covers probe response and
116 // beacons from other BSS
117 if (*total_flags
& FIF_BCN_PRBRESP_PROMISC
)
118 filter_beacon
= false;
120 filter_beacon
= true;
121 wfx_filter_beacon(wvif
, filter_beacon
);
123 if (*total_flags
& FIF_OTHER_BSS
)
124 filter_bssid
= false;
128 // In AP mode, chip can reply to probe request itself
129 if (*total_flags
& FIF_PROBE_REQ
&&
130 wvif
->vif
->type
== NL80211_IFTYPE_AP
) {
131 dev_dbg(wdev
->dev
, "do not forward probe request in AP mode\n");
132 *total_flags
&= ~FIF_PROBE_REQ
;
135 if (*total_flags
& FIF_PROBE_REQ
)
136 filter_prbreq
= false;
138 filter_prbreq
= true;
139 hif_set_rx_filter(wvif
, filter_bssid
, filter_prbreq
);
141 mutex_unlock(&wvif
->scan_lock
);
143 mutex_unlock(&wdev
->conf_mutex
);
146 static int wfx_get_ps_timeout(struct wfx_vif
*wvif
, bool *enable_ps
)
148 struct ieee80211_channel
*chan0
= NULL
, *chan1
= NULL
;
149 struct ieee80211_conf
*conf
= &wvif
->wdev
->hw
->conf
;
151 WARN(!wvif
->vif
->bss_conf
.assoc
&& enable_ps
,
152 "enable_ps is reliable only if associated");
153 if (wdev_to_wvif(wvif
->wdev
, 0))
154 chan0
= wdev_to_wvif(wvif
->wdev
, 0)->vif
->bss_conf
.chandef
.chan
;
155 if (wdev_to_wvif(wvif
->wdev
, 1))
156 chan1
= wdev_to_wvif(wvif
->wdev
, 1)->vif
->bss_conf
.chandef
.chan
;
157 if (chan0
&& chan1
&& chan0
->hw_value
!= chan1
->hw_value
&&
158 wvif
->vif
->type
!= NL80211_IFTYPE_AP
) {
159 // It is necessary to enable powersave if channels
163 if (wvif
->wdev
->force_ps_timeout
> -1)
164 return wvif
->wdev
->force_ps_timeout
;
165 else if (wfx_api_older_than(wvif
->wdev
, 3, 2))
171 *enable_ps
= wvif
->vif
->bss_conf
.ps
;
172 if (wvif
->wdev
->force_ps_timeout
> -1)
173 return wvif
->wdev
->force_ps_timeout
;
174 else if (wvif
->vif
->bss_conf
.assoc
&& wvif
->vif
->bss_conf
.ps
)
175 return conf
->dynamic_ps_timeout
;
180 int wfx_update_pm(struct wfx_vif
*wvif
)
185 if (!wvif
->vif
->bss_conf
.assoc
)
187 ps_timeout
= wfx_get_ps_timeout(wvif
, &ps
);
190 WARN_ON(ps_timeout
< 0);
191 if (wvif
->uapsd_mask
)
194 if (!wait_for_completion_timeout(&wvif
->set_pm_mode_complete
,
196 dev_warn(wvif
->wdev
->dev
,
197 "timeout while waiting of set_pm_mode_complete\n");
198 return hif_set_pm(wvif
, ps
, ps_timeout
);
201 int wfx_conf_tx(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
202 u16 queue
, const struct ieee80211_tx_queue_params
*params
)
204 struct wfx_dev
*wdev
= hw
->priv
;
205 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
206 int old_uapsd
= wvif
->uapsd_mask
;
208 WARN_ON(queue
>= hw
->queues
);
210 mutex_lock(&wdev
->conf_mutex
);
211 assign_bit(queue
, &wvif
->uapsd_mask
, params
->uapsd
);
212 hif_set_edca_queue_params(wvif
, queue
, params
);
213 if (wvif
->vif
->type
== NL80211_IFTYPE_STATION
&&
214 old_uapsd
!= wvif
->uapsd_mask
) {
215 hif_set_uapsd_info(wvif
, wvif
->uapsd_mask
);
218 mutex_unlock(&wdev
->conf_mutex
);
222 int wfx_set_rts_threshold(struct ieee80211_hw
*hw
, u32 value
)
224 struct wfx_dev
*wdev
= hw
->priv
;
225 struct wfx_vif
*wvif
= NULL
;
227 while ((wvif
= wvif_iterate(wdev
, wvif
)) != NULL
)
228 hif_rts_threshold(wvif
, value
);
234 void wfx_event_report_rssi(struct wfx_vif
*wvif
, u8 raw_rcpi_rssi
)
236 /* RSSI: signed Q8.0, RCPI: unsigned Q7.1
237 * RSSI = RCPI / 2 - 110
242 rcpi_rssi
= raw_rcpi_rssi
/ 2 - 110;
243 if (rcpi_rssi
<= wvif
->vif
->bss_conf
.cqm_rssi_thold
)
244 cqm_evt
= NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW
;
246 cqm_evt
= NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH
;
247 ieee80211_cqm_rssi_notify(wvif
->vif
, cqm_evt
, rcpi_rssi
, GFP_KERNEL
);
250 static void wfx_beacon_loss_work(struct work_struct
*work
)
252 struct wfx_vif
*wvif
= container_of(to_delayed_work(work
),
253 struct wfx_vif
, beacon_loss_work
);
254 struct ieee80211_bss_conf
*bss_conf
= &wvif
->vif
->bss_conf
;
256 ieee80211_beacon_loss(wvif
->vif
);
257 schedule_delayed_work(to_delayed_work(work
),
258 msecs_to_jiffies(bss_conf
->beacon_int
));
261 void wfx_set_default_unicast_key(struct ieee80211_hw
*hw
,
262 struct ieee80211_vif
*vif
, int idx
)
264 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
266 hif_wep_default_key_id(wvif
, idx
);
269 void wfx_reset(struct wfx_vif
*wvif
)
271 struct wfx_dev
*wdev
= wvif
->wdev
;
273 wfx_tx_lock_flush(wdev
);
274 hif_reset(wvif
, false);
275 wfx_tx_policy_init(wvif
);
276 if (wvif_count(wdev
) <= 1)
277 hif_set_block_ack_policy(wvif
, 0xFF, 0xFF);
279 wvif
->join_in_progress
= false;
280 cancel_delayed_work_sync(&wvif
->beacon_loss_work
);
282 while ((wvif
= wvif_iterate(wdev
, wvif
)) != NULL
)
286 int wfx_sta_add(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
287 struct ieee80211_sta
*sta
)
289 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
290 struct wfx_sta_priv
*sta_priv
= (struct wfx_sta_priv
*)&sta
->drv_priv
;
292 sta_priv
->vif_id
= wvif
->id
;
294 if (vif
->type
== NL80211_IFTYPE_STATION
)
295 hif_set_mfp(wvif
, sta
->mfp
, sta
->mfp
);
297 // In station mode, the firmware interprets new link-id as a TDLS peer.
298 if (vif
->type
== NL80211_IFTYPE_STATION
&& !sta
->tdls
)
300 sta_priv
->link_id
= ffz(wvif
->link_id_map
);
301 wvif
->link_id_map
|= BIT(sta_priv
->link_id
);
302 WARN_ON(!sta_priv
->link_id
);
303 WARN_ON(sta_priv
->link_id
>= HIF_LINK_ID_MAX
);
304 hif_map_link(wvif
, false, sta
->addr
, sta_priv
->link_id
, sta
->mfp
);
309 int wfx_sta_remove(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
310 struct ieee80211_sta
*sta
)
312 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
313 struct wfx_sta_priv
*sta_priv
= (struct wfx_sta_priv
*)&sta
->drv_priv
;
315 // See note in wfx_sta_add()
316 if (!sta_priv
->link_id
)
318 // FIXME add a mutex?
319 hif_map_link(wvif
, true, sta
->addr
, sta_priv
->link_id
, false);
320 wvif
->link_id_map
&= ~BIT(sta_priv
->link_id
);
324 static int wfx_upload_ap_templates(struct wfx_vif
*wvif
)
328 skb
= ieee80211_beacon_get(wvif
->wdev
->hw
, wvif
->vif
);
331 hif_set_template_frame(wvif
, skb
, HIF_TMPLT_BCN
,
332 API_RATE_INDEX_B_1MBPS
);
335 skb
= ieee80211_proberesp_get(wvif
->wdev
->hw
, wvif
->vif
);
338 hif_set_template_frame(wvif
, skb
, HIF_TMPLT_PRBRES
,
339 API_RATE_INDEX_B_1MBPS
);
344 static void wfx_set_mfp_ap(struct wfx_vif
*wvif
)
346 struct sk_buff
*skb
= ieee80211_beacon_get(wvif
->wdev
->hw
, wvif
->vif
);
347 const int ieoffset
= offsetof(struct ieee80211_mgmt
, u
.beacon
.variable
);
348 const u16
*ptr
= (u16
*)cfg80211_find_ie(WLAN_EID_RSN
,
349 skb
->data
+ ieoffset
,
350 skb
->len
- ieoffset
);
351 const int pairwise_cipher_suite_count_offset
= 8 / sizeof(u16
);
352 const int pairwise_cipher_suite_size
= 4 / sizeof(u16
);
353 const int akm_suite_size
= 4 / sizeof(u16
);
356 ptr
+= pairwise_cipher_suite_count_offset
;
357 if (WARN_ON(ptr
> (u16
*)skb_tail_pointer(skb
)))
359 ptr
+= 1 + pairwise_cipher_suite_size
* *ptr
;
360 if (WARN_ON(ptr
> (u16
*)skb_tail_pointer(skb
)))
362 ptr
+= 1 + akm_suite_size
* *ptr
;
363 if (WARN_ON(ptr
> (u16
*)skb_tail_pointer(skb
)))
365 hif_set_mfp(wvif
, *ptr
& BIT(7), *ptr
& BIT(6));
369 int wfx_start_ap(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
371 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
372 struct wfx_dev
*wdev
= wvif
->wdev
;
376 while ((wvif
= wvif_iterate(wdev
, wvif
)) != NULL
)
378 wvif
= (struct wfx_vif
*)vif
->drv_priv
;
379 wfx_upload_ap_templates(wvif
);
380 ret
= hif_start(wvif
, &vif
->bss_conf
, wvif
->channel
);
383 wfx_set_mfp_ap(wvif
);
387 void wfx_stop_ap(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
389 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
394 static void wfx_join(struct wfx_vif
*wvif
)
397 struct ieee80211_bss_conf
*conf
= &wvif
->vif
->bss_conf
;
398 struct cfg80211_bss
*bss
= NULL
;
399 u8 ssid
[IEEE80211_MAX_SSID_LEN
];
400 const u8
*ssidie
= NULL
;
403 wfx_tx_lock_flush(wvif
->wdev
);
405 bss
= cfg80211_get_bss(wvif
->wdev
->hw
->wiphy
, wvif
->channel
,
406 conf
->bssid
, NULL
, 0,
407 IEEE80211_BSS_TYPE_ANY
, IEEE80211_PRIVACY_ANY
);
408 if (!bss
&& !conf
->ibss_joined
) {
409 wfx_tx_unlock(wvif
->wdev
);
413 rcu_read_lock(); // protect ssidie
415 ssidie
= ieee80211_bss_get_ie(bss
, WLAN_EID_SSID
);
418 if (ssidlen
> IEEE80211_MAX_SSID_LEN
)
419 ssidlen
= IEEE80211_MAX_SSID_LEN
;
420 memcpy(ssid
, &ssidie
[2], ssidlen
);
424 cfg80211_put_bss(wvif
->wdev
->hw
->wiphy
, bss
);
426 wvif
->join_in_progress
= true;
427 ret
= hif_join(wvif
, conf
, wvif
->channel
, ssid
, ssidlen
);
429 ieee80211_connection_loss(wvif
->vif
);
432 /* Due to beacon filtering it is possible that the
433 * AP's beacon is not known for the mac80211 stack.
434 * Disable filtering temporary to make sure the stack
435 * receives at least one
437 wfx_filter_beacon(wvif
, false);
439 wfx_tx_unlock(wvif
->wdev
);
442 static void wfx_join_finalize(struct wfx_vif
*wvif
,
443 struct ieee80211_bss_conf
*info
)
445 struct ieee80211_sta
*sta
= NULL
;
446 int ampdu_density
= 0;
447 bool greenfield
= false;
449 rcu_read_lock(); // protect sta
450 if (info
->bssid
&& !info
->ibss_joined
)
451 sta
= ieee80211_find_sta(wvif
->vif
, info
->bssid
);
452 if (sta
&& sta
->ht_cap
.ht_supported
)
453 ampdu_density
= sta
->ht_cap
.ampdu_density
;
454 if (sta
&& sta
->ht_cap
.ht_supported
&&
455 !(info
->ht_operation_mode
& IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT
))
456 greenfield
= !!(sta
->ht_cap
.cap
& IEEE80211_HT_CAP_GRN_FLD
);
459 wvif
->join_in_progress
= false;
460 hif_set_association_mode(wvif
, ampdu_density
, greenfield
,
461 info
->use_short_preamble
);
462 hif_keep_alive_period(wvif
, 0);
463 // beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use
465 hif_set_bss_params(wvif
, info
->aid
, 7);
466 hif_set_beacon_wakeup_period(wvif
, 1, 1);
470 int wfx_join_ibss(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
472 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
474 wfx_upload_ap_templates(wvif
);
479 void wfx_leave_ibss(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
481 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
486 static void wfx_enable_beacon(struct wfx_vif
*wvif
, bool enable
)
488 // Driver has Content After DTIM Beacon in queue. Driver is waiting for
489 // a signal from the firmware. Since we are going to stop to send
490 // beacons, this signal will never happens. See also
491 // wfx_suspend_resume_mc()
492 if (!enable
&& wfx_tx_queues_has_cab(wvif
)) {
493 wvif
->after_dtim_tx_allowed
= true;
494 wfx_bh_request_tx(wvif
->wdev
);
496 hif_beacon_transmit(wvif
, enable
);
499 void wfx_bss_info_changed(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
500 struct ieee80211_bss_conf
*info
, u32 changed
)
502 struct wfx_dev
*wdev
= hw
->priv
;
503 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
506 mutex_lock(&wdev
->conf_mutex
);
508 if (changed
& BSS_CHANGED_BASIC_RATES
||
509 changed
& BSS_CHANGED_BEACON_INT
||
510 changed
& BSS_CHANGED_BSSID
) {
511 if (vif
->type
== NL80211_IFTYPE_STATION
)
515 if (changed
& BSS_CHANGED_ASSOC
) {
516 if (info
->assoc
|| info
->ibss_joined
)
517 wfx_join_finalize(wvif
, info
);
518 else if (!info
->assoc
&& vif
->type
== NL80211_IFTYPE_STATION
)
521 dev_warn(wdev
->dev
, "%s: misunderstood change: ASSOC\n",
525 if (changed
& BSS_CHANGED_BEACON_INFO
) {
526 if (vif
->type
!= NL80211_IFTYPE_STATION
)
527 dev_warn(wdev
->dev
, "%s: misunderstood change: BEACON_INFO\n",
529 hif_set_beacon_wakeup_period(wvif
, info
->dtim_period
,
531 // We temporary forwarded beacon for join process. It is now no
533 wfx_filter_beacon(wvif
, true);
536 if (changed
& BSS_CHANGED_ARP_FILTER
) {
537 for (i
= 0; i
< HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES
; i
++) {
538 __be32
*arp_addr
= &info
->arp_addr_list
[i
];
540 if (info
->arp_addr_cnt
> HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES
)
542 if (i
>= info
->arp_addr_cnt
)
544 hif_set_arp_ipv4_filter(wvif
, i
, arp_addr
);
548 if (changed
& BSS_CHANGED_AP_PROBE_RESP
||
549 changed
& BSS_CHANGED_BEACON
)
550 wfx_upload_ap_templates(wvif
);
552 if (changed
& BSS_CHANGED_BEACON_ENABLED
)
553 wfx_enable_beacon(wvif
, info
->enable_beacon
);
555 if (changed
& BSS_CHANGED_KEEP_ALIVE
)
556 hif_keep_alive_period(wvif
, info
->max_idle_period
*
557 USEC_PER_TU
/ USEC_PER_MSEC
);
559 if (changed
& BSS_CHANGED_ERP_CTS_PROT
)
560 hif_erp_use_protection(wvif
, info
->use_cts_prot
);
562 if (changed
& BSS_CHANGED_ERP_SLOT
)
563 hif_slot_time(wvif
, info
->use_short_slot
? 9 : 20);
565 if (changed
& BSS_CHANGED_CQM
)
566 hif_set_rcpi_rssi_threshold(wvif
, info
->cqm_rssi_thold
,
567 info
->cqm_rssi_hyst
);
569 if (changed
& BSS_CHANGED_TXPOWER
)
570 hif_set_output_power(wvif
, info
->txpower
);
572 if (changed
& BSS_CHANGED_PS
)
575 mutex_unlock(&wdev
->conf_mutex
);
578 static int wfx_update_tim(struct wfx_vif
*wvif
)
581 u16 tim_offset
, tim_length
;
584 skb
= ieee80211_beacon_get_tim(wvif
->wdev
->hw
, wvif
->vif
,
585 &tim_offset
, &tim_length
);
588 tim_ptr
= skb
->data
+ tim_offset
;
590 if (tim_offset
&& tim_length
>= 6) {
591 /* Ignore DTIM count from mac80211:
592 * firmware handles DTIM internally.
596 /* Set/reset aid0 bit */
597 if (wfx_tx_queues_has_cab(wvif
))
603 hif_update_ie_beacon(wvif
, tim_ptr
, tim_length
);
609 static void wfx_update_tim_work(struct work_struct
*work
)
611 struct wfx_vif
*wvif
= container_of(work
, struct wfx_vif
, update_tim_work
);
613 wfx_update_tim(wvif
);
616 int wfx_set_tim(struct ieee80211_hw
*hw
, struct ieee80211_sta
*sta
, bool set
)
618 struct wfx_dev
*wdev
= hw
->priv
;
619 struct wfx_sta_priv
*sta_dev
= (struct wfx_sta_priv
*)&sta
->drv_priv
;
620 struct wfx_vif
*wvif
= wdev_to_wvif(wdev
, sta_dev
->vif_id
);
623 dev_warn(wdev
->dev
, "%s: received event for non-existent vif\n", __func__
);
626 schedule_work(&wvif
->update_tim_work
);
630 void wfx_suspend_resume_mc(struct wfx_vif
*wvif
, enum sta_notify_cmd notify_cmd
)
632 if (notify_cmd
!= STA_NOTIFY_AWAKE
)
634 WARN(!wfx_tx_queues_has_cab(wvif
), "incorrect sequence");
635 WARN(wvif
->after_dtim_tx_allowed
, "incorrect sequence");
636 wvif
->after_dtim_tx_allowed
= true;
637 wfx_bh_request_tx(wvif
->wdev
);
640 int wfx_ampdu_action(struct ieee80211_hw
*hw
,
641 struct ieee80211_vif
*vif
,
642 struct ieee80211_ampdu_params
*params
)
644 // Aggregation is implemented fully in firmware
645 switch (params
->action
) {
646 case IEEE80211_AMPDU_RX_START
:
647 case IEEE80211_AMPDU_RX_STOP
:
648 // Just acknowledge it to enable frame re-ordering
651 // Leave the firmware doing its business for tx aggregation
656 int wfx_add_chanctx(struct ieee80211_hw
*hw
,
657 struct ieee80211_chanctx_conf
*conf
)
662 void wfx_remove_chanctx(struct ieee80211_hw
*hw
,
663 struct ieee80211_chanctx_conf
*conf
)
667 void wfx_change_chanctx(struct ieee80211_hw
*hw
,
668 struct ieee80211_chanctx_conf
*conf
,
673 int wfx_assign_vif_chanctx(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
674 struct ieee80211_chanctx_conf
*conf
)
676 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
677 struct ieee80211_channel
*ch
= conf
->def
.chan
;
679 WARN(wvif
->channel
, "channel overwrite");
685 void wfx_unassign_vif_chanctx(struct ieee80211_hw
*hw
,
686 struct ieee80211_vif
*vif
,
687 struct ieee80211_chanctx_conf
*conf
)
689 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
690 struct ieee80211_channel
*ch
= conf
->def
.chan
;
692 WARN(wvif
->channel
!= ch
, "channel mismatch");
693 wvif
->channel
= NULL
;
696 int wfx_config(struct ieee80211_hw
*hw
, u32 changed
)
701 int wfx_add_interface(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
704 struct wfx_dev
*wdev
= hw
->priv
;
705 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
707 vif
->driver_flags
|= IEEE80211_VIF_BEACON_FILTER
|
708 IEEE80211_VIF_SUPPORTS_UAPSD
|
709 IEEE80211_VIF_SUPPORTS_CQM_RSSI
;
711 mutex_lock(&wdev
->conf_mutex
);
714 case NL80211_IFTYPE_STATION
:
715 case NL80211_IFTYPE_ADHOC
:
716 case NL80211_IFTYPE_AP
:
719 mutex_unlock(&wdev
->conf_mutex
);
723 // FIXME: prefer use of container_of() to get vif
727 wvif
->link_id_map
= 1; // link-id 0 is reserved for multicast
728 INIT_WORK(&wvif
->update_tim_work
, wfx_update_tim_work
);
729 INIT_DELAYED_WORK(&wvif
->beacon_loss_work
, wfx_beacon_loss_work
);
731 init_completion(&wvif
->set_pm_mode_complete
);
732 complete(&wvif
->set_pm_mode_complete
);
733 INIT_WORK(&wvif
->tx_policy_upload_work
, wfx_tx_policy_upload_work
);
735 mutex_init(&wvif
->scan_lock
);
736 init_completion(&wvif
->scan_complete
);
737 INIT_WORK(&wvif
->scan_work
, wfx_hw_scan_work
);
739 wfx_tx_queues_init(wvif
);
740 wfx_tx_policy_init(wvif
);
742 for (i
= 0; i
< ARRAY_SIZE(wdev
->vif
); i
++) {
749 WARN(i
== ARRAY_SIZE(wdev
->vif
), "try to instantiate more vif than supported");
751 hif_set_macaddr(wvif
, vif
->addr
);
753 mutex_unlock(&wdev
->conf_mutex
);
756 while ((wvif
= wvif_iterate(wdev
, wvif
)) != NULL
) {
757 // Combo mode does not support Block Acks. We can re-enable them
758 if (wvif_count(wdev
) == 1)
759 hif_set_block_ack_policy(wvif
, 0xFF, 0xFF);
761 hif_set_block_ack_policy(wvif
, 0x00, 0x00);
766 void wfx_remove_interface(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
)
768 struct wfx_dev
*wdev
= hw
->priv
;
769 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
771 wait_for_completion_timeout(&wvif
->set_pm_mode_complete
, msecs_to_jiffies(300));
772 wfx_tx_queues_check_empty(wvif
);
774 mutex_lock(&wdev
->conf_mutex
);
775 WARN(wvif
->link_id_map
!= 1, "corrupted state");
777 hif_reset(wvif
, false);
778 hif_set_macaddr(wvif
, NULL
);
779 wfx_tx_policy_init(wvif
);
781 cancel_delayed_work_sync(&wvif
->beacon_loss_work
);
782 wdev
->vif
[wvif
->id
] = NULL
;
785 mutex_unlock(&wdev
->conf_mutex
);
788 while ((wvif
= wvif_iterate(wdev
, wvif
)) != NULL
) {
789 // Combo mode does not support Block Acks. We can re-enable them
790 if (wvif_count(wdev
) == 1)
791 hif_set_block_ack_policy(wvif
, 0xFF, 0xFF);
793 hif_set_block_ack_policy(wvif
, 0x00, 0x00);
797 int wfx_start(struct ieee80211_hw
*hw
)
802 void wfx_stop(struct ieee80211_hw
*hw
)
804 struct wfx_dev
*wdev
= hw
->priv
;
806 WARN_ON(!skb_queue_empty_lockless(&wdev
->tx_pending
));