wifi: iwlwifi: mvm: add all missing ops to iwl_mvm_mld_ops
[linux-block.git] / drivers / net / wireless / intel / iwlwifi / mvm / mld-mac80211.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2022 Intel Corporation
4  */
5 #include "mvm.h"
6
7 static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
8                                          struct ieee80211_vif *vif)
9 {
10         struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
11         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
12         int ret;
13
14         mutex_lock(&mvm->mutex);
15
16         /* Common for MLD and non-MLD API */
17         if (iwl_mvm_mac_add_interface_common(mvm, hw, vif, &ret))
18                 goto out_unlock;
19
20         ret = iwl_mvm_mld_mac_ctxt_add(mvm, vif);
21         if (ret)
22                 goto out_unlock;
23
24         ret = iwl_mvm_power_update_mac(mvm);
25         if (ret)
26                 goto out_remove_mac;
27
28         /* beacon filtering */
29         ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
30         if (ret)
31                 goto out_remove_mac;
32
33         if (!mvm->bf_allowed_vif &&
34             vif->type == NL80211_IFTYPE_STATION && !vif->p2p) {
35                 mvm->bf_allowed_vif = mvmvif;
36                 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
37                                      IEEE80211_VIF_SUPPORTS_CQM_RSSI;
38         }
39
40         /*
41          * P2P_DEVICE interface does not have a channel context assigned to it,
42          * so a dedicated PHY context is allocated to it and the corresponding
43          * MAC context is bound to it at this stage.
44          */
45         if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
46                 mvmvif->deflink.phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm);
47                 if (!mvmvif->deflink.phy_ctxt) {
48                         ret = -ENOSPC;
49                         goto out_free_bf;
50                 }
51
52                 iwl_mvm_phy_ctxt_ref(mvm, mvmvif->deflink.phy_ctxt);
53                 ret = iwl_mvm_add_link(mvm, vif);
54                 if (ret)
55                         goto out_unref_phy;
56
57                 ret = iwl_mvm_link_changed(mvm, vif,
58                                            LINK_CONTEXT_MODIFY_ACTIVE |
59                                            LINK_CONTEXT_MODIFY_RATES_INFO,
60                                            true);
61                 if (ret)
62                         goto out_remove_link;
63
64                 ret = iwl_mvm_mld_add_bcast_sta(mvm, vif);
65                 if (ret)
66                         goto out_remove_link;
67
68                 /* Save a pointer to p2p device vif, so it can later be used to
69                  * update the p2p device MAC when a GO is started/stopped
70                  */
71                 mvm->p2p_device_vif = vif;
72         }
73
74         iwl_mvm_tcm_add_vif(mvm, vif);
75         INIT_DELAYED_WORK(&mvmvif->csa_work,
76                           iwl_mvm_channel_switch_disconnect_wk);
77
78         if (vif->type == NL80211_IFTYPE_MONITOR) {
79                 mvm->monitor_on = true;
80                 ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS);
81         }
82
83         iwl_mvm_vif_dbgfs_register(mvm, vif);
84
85         if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
86             vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
87             !mvm->csme_vif && mvm->mei_registered) {
88                 iwl_mei_set_nic_info(vif->addr, mvm->nvm_data->hw_addr);
89                 iwl_mei_set_netdev(ieee80211_vif_to_wdev(vif)->netdev);
90                 mvm->csme_vif = vif;
91         }
92
93         goto out_unlock;
94
95  out_remove_link:
96         /* Link needs to be deactivated before removal */
97         iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, false);
98         iwl_mvm_remove_link(mvm, vif);
99  out_unref_phy:
100         iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);
101  out_free_bf:
102         if (mvm->bf_allowed_vif == mvmvif) {
103                 mvm->bf_allowed_vif = NULL;
104                 vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
105                                        IEEE80211_VIF_SUPPORTS_CQM_RSSI);
106         }
107  out_remove_mac:
108         mvmvif->deflink.phy_ctxt = NULL;
109         mvmvif->link[0] = NULL;
110         iwl_mvm_mld_mac_ctxt_remove(mvm, vif);
111  out_unlock:
112         mutex_unlock(&mvm->mutex);
113
114         return ret;
115 }
116
117 static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw,
118                                              struct ieee80211_vif *vif)
119 {
120         struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
121         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
122
123         if (iwl_mvm_mac_remove_interface_common(hw, vif))
124                 goto out;
125
126         if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
127                 mvm->p2p_device_vif = NULL;
128                 iwl_mvm_mld_rm_bcast_sta(mvm, vif);
129                 /* Link needs to be deactivated before removal */
130                 iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE,
131                                      false);
132                 iwl_mvm_remove_link(mvm, vif);
133                 iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);
134                 mvmvif->deflink.phy_ctxt = NULL;
135         }
136
137         iwl_mvm_mld_mac_ctxt_remove(mvm, vif);
138
139         RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL);
140
141         if (vif->type == NL80211_IFTYPE_MONITOR) {
142                 mvm->monitor_on = false;
143                 __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mvm->hw->flags);
144         }
145
146 out:
147         mutex_unlock(&mvm->mutex);
148 }
149
150 static int __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
151                                             struct ieee80211_vif *vif,
152                                             struct ieee80211_chanctx_conf *ctx,
153                                             bool switching_chanctx)
154 {
155         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
156         int ret;
157
158         if (__iwl_mvm_assign_vif_chanctx_common(mvm, vif, ctx,
159                                                 switching_chanctx, &ret))
160                 goto out;
161
162         ret = iwl_mvm_add_link(mvm, vif);
163         if (ret)
164                 goto out;
165         ret = iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE,
166                                    true);
167         if (ret)
168                 goto out_remove_link;
169
170         /*
171          * Power state must be updated before quotas,
172          * otherwise fw will complain.
173          */
174         iwl_mvm_power_update_mac(mvm);
175
176         if (vif->type == NL80211_IFTYPE_MONITOR) {
177                 ret = iwl_mvm_mld_add_snif_sta(mvm, vif);
178                 if (ret)
179                         goto out_remove_link;
180         }
181
182         goto out;
183
184 out_remove_link:
185         /* Link needs to be deactivated before removal */
186         iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, false);
187         iwl_mvm_remove_link(mvm, vif);
188         iwl_mvm_power_update_mac(mvm);
189 out:
190         if (ret)
191                 mvmvif->deflink.phy_ctxt = NULL;
192         return ret;
193 }
194
195 static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
196                                           struct ieee80211_vif *vif,
197                                           struct ieee80211_bss_conf *link_conf,
198                                           struct ieee80211_chanctx_conf *ctx)
199 {
200         struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
201         int ret;
202
203         mutex_lock(&mvm->mutex);
204         ret = __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, ctx, false);
205         mutex_unlock(&mvm->mutex);
206
207         return ret;
208 }
209
210 static void __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
211                                                struct ieee80211_vif *vif,
212                                                struct ieee80211_chanctx_conf *ctx,
213                                                bool switching_chanctx)
214 {
215         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
216
217         if (__iwl_mvm_unassign_vif_chanctx_common(mvm, vif, switching_chanctx))
218                 goto out;
219
220         if (vif->type == NL80211_IFTYPE_MONITOR)
221                 iwl_mvm_mld_rm_snif_sta(mvm, vif);
222
223         /* Link needs to be deactivated before removal */
224         iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, false);
225         iwl_mvm_remove_link(mvm, vif);
226
227 out:
228         if (switching_chanctx)
229                 return;
230         mvmvif->deflink.phy_ctxt = NULL;
231         iwl_mvm_power_update_mac(mvm);
232 }
233
234 static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
235                                              struct ieee80211_vif *vif,
236                                              struct ieee80211_bss_conf *link_conf,
237                                              struct ieee80211_chanctx_conf *ctx)
238 {
239         struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
240
241         mutex_lock(&mvm->mutex);
242         __iwl_mvm_mld_unassign_vif_chanctx(mvm, vif, ctx, false);
243         mutex_unlock(&mvm->mutex);
244 }
245
246 static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw,
247                                      struct ieee80211_vif *vif,
248                                      struct ieee80211_bss_conf *link_conf)
249 {
250         struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
251         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
252         int ret;
253
254         mutex_lock(&mvm->mutex);
255
256         /* Send the beacon template */
257         ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif);
258         if (ret)
259                 goto out_unlock;
260
261         /* No need to re-calculate the tsf_is, as it was offloaded */
262
263         /* Add the mac context */
264         ret = iwl_mvm_mld_mac_ctxt_add(mvm, vif);
265         if (ret)
266                 goto out_unlock;
267
268         /* Add link and activate it */
269         ret = iwl_mvm_add_link(mvm, vif);
270         if (ret)
271                 goto out_remove_mac;
272
273         ret = iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE,
274                                    true);
275         if (ret)
276                 goto out_remove_link;
277
278         ret = iwl_mvm_mld_add_mcast_sta(mvm, vif);
279         if (ret)
280                 goto out_remove_link;
281
282         /* Send the bcast station. At this stage the TBTT and DTIM time
283          * events are added and applied to the scheduler
284          */
285         ret = iwl_mvm_mld_add_bcast_sta(mvm, vif);
286         if (ret)
287                 goto out_rm_mcast;
288
289         if (iwl_mvm_start_ap_ibss_common(hw, vif, &ret))
290                 goto out_failed;
291
292         /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
293         if (vif->p2p && mvm->p2p_device_vif)
294                 iwl_mvm_mld_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
295
296         iwl_mvm_bt_coex_vif_change(mvm);
297
298         /* we don't support TDLS during DCM */
299         if (iwl_mvm_phy_ctx_count(mvm) > 1)
300                 iwl_mvm_teardown_tdls_peers(mvm);
301
302         iwl_mvm_ftm_restart_responder(mvm, vif);
303
304         goto out_unlock;
305
306 out_failed:
307         iwl_mvm_power_update_mac(mvm);
308         mvmvif->ap_ibss_active = false;
309         iwl_mvm_mld_rm_bcast_sta(mvm, vif);
310 out_rm_mcast:
311         iwl_mvm_mld_rm_mcast_sta(mvm, vif);
312 out_remove_link:
313         /* Link needs to be deactivated before removal */
314         iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, false);
315         iwl_mvm_remove_link(mvm, vif);
316 out_remove_mac:
317         iwl_mvm_mld_mac_ctxt_remove(mvm, vif);
318 out_unlock:
319         mutex_unlock(&mvm->mutex);
320         return ret;
321 }
322
323 static int iwl_mvm_mld_start_ap(struct ieee80211_hw *hw,
324                                 struct ieee80211_vif *vif,
325                                 struct ieee80211_bss_conf *link_conf)
326 {
327         return iwl_mvm_mld_start_ap_ibss(hw, vif, link_conf);
328 }
329
330 static int iwl_mvm_mld_start_ibss(struct ieee80211_hw *hw,
331                                   struct ieee80211_vif *vif)
332 {
333         return iwl_mvm_mld_start_ap_ibss(hw, vif, &vif->bss_conf);
334 }
335
336 static void iwl_mvm_mld_stop_ap_ibss(struct ieee80211_hw *hw,
337                                      struct ieee80211_vif *vif,
338                                      struct ieee80211_bss_conf *link_conf)
339 {
340         struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
341
342         mutex_lock(&mvm->mutex);
343
344         iwl_mvm_stop_ap_ibss_common(mvm, vif);
345
346         /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
347         if (vif->p2p && mvm->p2p_device_vif)
348                 iwl_mvm_mld_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
349
350         iwl_mvm_ftm_responder_clear(mvm, vif);
351
352         iwl_mvm_mld_rm_bcast_sta(mvm, vif);
353         iwl_mvm_mld_rm_mcast_sta(mvm, vif);
354
355         /* Link needs to be deactivated before removal */
356         iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, false);
357         iwl_mvm_remove_link(mvm, vif);
358
359         iwl_mvm_power_update_mac(mvm);
360
361         iwl_mvm_mld_mac_ctxt_remove(mvm, vif);
362
363         mutex_unlock(&mvm->mutex);
364 }
365
366 static void iwl_mvm_mld_stop_ap(struct ieee80211_hw *hw,
367                                 struct ieee80211_vif *vif,
368                                 struct ieee80211_bss_conf *link_conf)
369 {
370         iwl_mvm_mld_stop_ap_ibss(hw, vif, link_conf);
371 }
372
373 static void iwl_mvm_mld_stop_ibss(struct ieee80211_hw *hw,
374                                   struct ieee80211_vif *vif)
375 {
376         iwl_mvm_mld_stop_ap_ibss(hw, vif, &vif->bss_conf);
377 }
378
379 static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw,
380                                      struct ieee80211_vif *vif,
381                                      struct ieee80211_sta *sta,
382                                      enum ieee80211_sta_state old_state,
383                                      enum ieee80211_sta_state new_state)
384 {
385         struct iwl_mvm_sta_state_ops callbacks = {
386                 .add_sta = iwl_mvm_mld_add_sta,
387                 .update_sta = iwl_mvm_mld_update_sta,
388                 .rm_sta = iwl_mvm_mld_rm_sta,
389                 .mac_ctxt_changed = iwl_mvm_mld_mac_ctxt_changed,
390         };
391
392         return iwl_mvm_mac_sta_state_common(hw, vif, sta, old_state, new_state,
393                                             &callbacks);
394 }
395
396 static void
397 iwl_mvm_mld_bss_info_changed_station(struct iwl_mvm *mvm,
398                                      struct ieee80211_vif *vif,
399                                      struct ieee80211_bss_conf *bss_conf,
400                                      u64 changes)
401 {
402         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
403         int ret;
404         u32 link_changes = 0;
405         bool has_he = vif->bss_conf.he_support &&
406                           !iwlwifi_mod_params.disable_11ax;
407         bool has_eht = vif->bss_conf.eht_support &&
408                           !iwlwifi_mod_params.disable_11be;
409
410         if (changes & BSS_CHANGED_ASSOC && vif->cfg.assoc &&
411             (has_he || has_eht)) {
412                 IWL_DEBUG_MAC80211(mvm, "Associated in HE mode\n");
413                 link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;
414         }
415
416         /* Update MU EDCA params */
417         if (changes & BSS_CHANGED_QOS && vif->cfg.assoc &&
418             (has_he || has_eht))
419                 link_changes |= LINK_CONTEXT_MODIFY_QOS_PARAMS;
420
421         /* Update EHT Puncturing info */
422         if (changes & BSS_CHANGED_EHT_PUNCTURING && vif->cfg.assoc && has_eht)
423                 link_changes |= LINK_CONTEXT_MODIFY_EHT_PARAMS;
424
425         if (link_changes) {
426                 ret = iwl_mvm_link_changed(mvm, vif, link_changes, true);
427                 if (ret)
428                         IWL_ERR(mvm, "failed to update link\n");
429         }
430
431         ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);
432         if (ret)
433                 IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
434
435         memcpy(mvmvif->deflink.bssid, bss_conf->bssid, ETH_ALEN);
436         mvmvif->associated = vif->cfg.assoc;
437
438         if (changes & BSS_CHANGED_ASSOC) {
439                 if (vif->cfg.assoc) {
440                         /* clear statistics to get clean beacon counter */
441                         iwl_mvm_request_statistics(mvm, true);
442                         memset(&mvmvif->deflink.beacon_stats, 0,
443                                sizeof(mvmvif->deflink.beacon_stats));
444
445                         if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
446                                       &mvm->status) &&
447                             !vif->bss_conf.dtim_period) {
448                                 /* If we're not restarting and still haven't
449                                  * heard a beacon (dtim period unknown) then
450                                  * make sure we still have enough minimum time
451                                  * remaining in the time event, since the auth
452                                  * might actually have taken quite a while
453                                  * (especially for SAE) and so the remaining
454                                  * time could be small without us having heard
455                                  * a beacon yet.
456                                  */
457                                 iwl_mvm_protect_assoc(mvm, vif, 0);
458                         }
459
460                         iwl_mvm_sf_update(mvm, vif, false);
461                         iwl_mvm_power_vif_assoc(mvm, vif);
462                         if (vif->p2p) {
463                                 iwl_mvm_update_smps(mvm, vif,
464                                                     IWL_MVM_SMPS_REQ_PROT,
465                                                     IEEE80211_SMPS_DYNAMIC);
466                         }
467                 } else if (mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) {
468                         iwl_mvm_mei_host_disassociated(mvm);
469                         /* If update fails - SF might be running in associated
470                          * mode while disassociated - which is forbidden.
471                          */
472                         ret = iwl_mvm_sf_update(mvm, vif, false);
473                         WARN_ONCE(ret &&
474                                   !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
475                                             &mvm->status),
476                                   "Failed to update SF upon disassociation\n");
477
478                         /* If we get an assert during the connection (after the
479                          * station has been added, but before the vif is set
480                          * to associated), mac80211 will re-add the station and
481                          * then configure the vif. Since the vif is not
482                          * associated, we would remove the station here and
483                          * this would fail the recovery.
484                          */
485                         if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
486                                       &mvm->status)) {
487                                 /* first remove remaining keys */
488                                 iwl_mvm_sec_key_remove_ap(mvm, vif);
489
490                                 /* Remove AP station now that
491                                  * the MAC is unassoc
492                                  */
493                                 ret = iwl_mvm_mld_rm_sta_id(mvm, vif,
494                                                             mvmvif->deflink.ap_sta_id);
495                                 if (ret)
496                                         IWL_ERR(mvm,
497                                                 "failed to remove AP station\n");
498
499                                 mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA;
500                         }
501                 }
502
503                 iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes);
504         }
505
506         iwl_mvm_bss_info_changed_station_common(mvm, vif, changes);
507 }
508
509 static void
510 iwl_mvm_mld_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
511                                      struct ieee80211_vif *vif,
512                                      struct ieee80211_bss_conf *bss_conf,
513                                      u64 changes)
514 {
515         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
516         u32 link_changes = LINK_CONTEXT_MODIFY_PROTECT_FLAGS |
517                            LINK_CONTEXT_MODIFY_QOS_PARAMS;
518
519         /* Changes will be applied when the AP/IBSS is started */
520         if (!mvmvif->ap_ibss_active)
521                 return;
522
523         if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |
524                        BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS) &&
525                        iwl_mvm_link_changed(mvm, vif, link_changes, true))
526                 IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
527
528         /* Need to send a new beacon template to the FW */
529         if (changes & BSS_CHANGED_BEACON &&
530             iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
531                 IWL_WARN(mvm, "Failed updating beacon data\n");
532
533         if (changes & BSS_CHANGED_FTM_RESPONDER) {
534                 int ret = iwl_mvm_ftm_start_responder(mvm, vif);
535
536                 if (ret)
537                         IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n",
538                                  ret);
539         }
540 }
541
542 static void iwl_mvm_mld_bss_info_changed(struct ieee80211_hw *hw,
543                                          struct ieee80211_vif *vif,
544                                          struct ieee80211_bss_conf *bss_conf,
545                                          u64 changes)
546 {
547         struct iwl_mvm_bss_info_changed_ops callbacks = {
548                 .bss_info_changed_sta = iwl_mvm_mld_bss_info_changed_station,
549                 .bss_info_changed_ap_ibss =
550                         iwl_mvm_mld_bss_info_changed_ap_ibss,
551         };
552
553         iwl_mvm_bss_info_changed_common(hw, vif, bss_conf, &callbacks,
554                                         changes);
555 }
556
557 static int
558 iwl_mvm_mld_switch_vif_chanctx(struct ieee80211_hw *hw,
559                                struct ieee80211_vif_chanctx_switch *vifs,
560                                int n_vifs,
561                                enum ieee80211_chanctx_switch_mode mode)
562 {
563         struct iwl_mvm_switch_vif_chanctx_ops ops = {
564                 .__assign_vif_chanctx = __iwl_mvm_mld_assign_vif_chanctx,
565                 .__unassign_vif_chanctx = __iwl_mvm_mld_unassign_vif_chanctx,
566         };
567
568         return iwl_mvm_switch_vif_chanctx_common(hw, vifs, n_vifs, mode, &ops);
569 }
570
571 static void iwl_mvm_mld_config_iface_filter(struct ieee80211_hw *hw,
572                                             struct ieee80211_vif *vif,
573                                             unsigned int filter_flags,
574                                             unsigned int changed_flags)
575 {
576         struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
577
578         /* We support only filter for probe requests */
579         if (!(changed_flags & FIF_PROBE_REQ))
580                 return;
581
582         /* Supported only for p2p client interfaces */
583         if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc ||
584             !vif->p2p)
585                 return;
586
587         mutex_lock(&mvm->mutex);
588         iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);
589         mutex_unlock(&mvm->mutex);
590 }
591
592 static int
593 iwl_mvm_mld_mac_conf_tx(struct ieee80211_hw *hw,
594                         struct ieee80211_vif *vif,
595                         unsigned int link_id, u16 ac,
596                         const struct ieee80211_tx_queue_params *params)
597 {
598         struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
599         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
600
601         mvmvif->deflink.queue_params[ac] = *params;
602
603         /* No need to update right away, we'll get BSS_CHANGED_QOS
604          * The exception is P2P_DEVICE interface which needs immediate update.
605          */
606         if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
607                 int ret;
608
609                 mutex_lock(&mvm->mutex);
610                 ret = iwl_mvm_link_changed(mvm, vif,
611                                            LINK_CONTEXT_MODIFY_QOS_PARAMS,
612                                            true);
613                 mutex_unlock(&mvm->mutex);
614                 return ret;
615         }
616         return 0;
617 }
618
619 static int iwl_mvm_link_switch_phy_ctx(struct iwl_mvm *mvm,
620                                        struct ieee80211_vif *vif,
621                                        struct iwl_mvm_phy_ctxt *new_phy_ctxt)
622 {
623         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
624         int ret = 0;
625
626         lockdep_assert_held(&mvm->mutex);
627
628         /* Inorder to change the phy_ctx of a link, the link needs to be
629          * inactive. Therefore, first deactivate the link, then change its
630          * phy_ctx, and then activate it again.
631          */
632         ret = iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, false);
633         if (WARN(ret, "Failed to deactivate link\n"))
634                 return ret;
635
636         iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);
637
638         mvmvif->deflink.phy_ctxt = new_phy_ctxt;
639
640         ret = iwl_mvm_link_changed(mvm, vif, 0, false);
641         if (WARN(ret, "Failed to deactivate link\n"))
642                 return ret;
643
644         ret = iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, true);
645         WARN(ret, "Failed binding P2P_DEVICE\n");
646         return ret;
647 }
648
649 static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
650                            struct ieee80211_channel *channel, int duration,
651                            enum ieee80211_roc_type type)
652 {
653         struct iwl_mvm_roc_ops ops = {
654                 .add_aux_sta_for_hs20 = iwl_mvm_mld_add_aux_sta,
655                 .switch_phy_ctxt = iwl_mvm_link_switch_phy_ctx,
656         };
657
658         return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
659 }
660 const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
661         .tx = iwl_mvm_mac_tx,
662         .wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
663         .ampdu_action = iwl_mvm_mac_ampdu_action,
664         .get_antenna = iwl_mvm_op_get_antenna,
665         .start = iwl_mvm_mac_start,
666         .reconfig_complete = iwl_mvm_mac_reconfig_complete,
667         .stop = iwl_mvm_mac_stop,
668         .add_interface = iwl_mvm_mld_mac_add_interface,
669         .remove_interface = iwl_mvm_mld_mac_remove_interface,
670         .config = iwl_mvm_mac_config,
671         .prepare_multicast = iwl_mvm_prepare_multicast,
672         .configure_filter = iwl_mvm_configure_filter,
673         .config_iface_filter = iwl_mvm_mld_config_iface_filter,
674         .bss_info_changed = iwl_mvm_mld_bss_info_changed,
675         .hw_scan = iwl_mvm_mac_hw_scan,
676         .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan,
677         .sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove,
678         .sta_state = iwl_mvm_mld_mac_sta_state,
679         .sta_notify = iwl_mvm_mac_sta_notify,
680         .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames,
681         .release_buffered_frames = iwl_mvm_mac_release_buffered_frames,
682         .set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
683         .sta_rc_update = iwl_mvm_sta_rc_update,
684         .conf_tx = iwl_mvm_mld_mac_conf_tx,
685         .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
686         .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,
687         .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover,
688         .flush = iwl_mvm_mac_flush,
689         .sched_scan_start = iwl_mvm_mac_sched_scan_start,
690         .sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
691         .set_key = iwl_mvm_mac_set_key,
692         .update_tkip_key = iwl_mvm_mac_update_tkip_key,
693         .remain_on_channel = iwl_mvm_mld_roc,
694         .cancel_remain_on_channel = iwl_mvm_cancel_roc,
695         .add_chanctx = iwl_mvm_add_chanctx,
696         .remove_chanctx = iwl_mvm_remove_chanctx,
697         .change_chanctx = iwl_mvm_change_chanctx,
698         .assign_vif_chanctx = iwl_mvm_mld_assign_vif_chanctx,
699         .unassign_vif_chanctx = iwl_mvm_mld_unassign_vif_chanctx,
700         .switch_vif_chanctx = iwl_mvm_mld_switch_vif_chanctx,
701
702         .start_ap = iwl_mvm_mld_start_ap,
703         .stop_ap = iwl_mvm_mld_stop_ap,
704         .join_ibss = iwl_mvm_mld_start_ibss,
705         .leave_ibss = iwl_mvm_mld_stop_ibss,
706
707         .tx_last_beacon = iwl_mvm_tx_last_beacon,
708
709         .set_tim = iwl_mvm_set_tim,
710
711         .channel_switch = iwl_mvm_channel_switch,
712         .pre_channel_switch = iwl_mvm_pre_channel_switch,
713         .post_channel_switch = iwl_mvm_post_channel_switch,
714         .abort_channel_switch = iwl_mvm_abort_channel_switch,
715         .channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon,
716
717         .tdls_channel_switch = iwl_mvm_tdls_channel_switch,
718         .tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch,
719         .tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch,
720
721         .event_callback = iwl_mvm_mac_event_callback,
722
723         .sync_rx_queues = iwl_mvm_sync_rx_queues,
724
725         CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd)
726
727 #ifdef CONFIG_PM_SLEEP
728         /* look at d3.c */
729         .suspend = iwl_mvm_suspend,
730         .resume = iwl_mvm_resume,
731         .set_wakeup = iwl_mvm_set_wakeup,
732         .set_rekey_data = iwl_mvm_set_rekey_data,
733 #if IS_ENABLED(CONFIG_IPV6)
734         .ipv6_addr_change = iwl_mvm_ipv6_addr_change,
735 #endif
736         .set_default_unicast_key = iwl_mvm_set_default_unicast_key,
737 #endif
738         .get_survey = iwl_mvm_mac_get_survey,
739         .sta_statistics = iwl_mvm_mac_sta_statistics,
740         .get_ftm_responder_stats = iwl_mvm_mac_get_ftm_responder_stats,
741         .start_pmsr = iwl_mvm_start_pmsr,
742         .abort_pmsr = iwl_mvm_abort_pmsr,
743
744 #ifdef CONFIG_IWLWIFI_DEBUGFS
745         .sta_add_debugfs = iwl_mvm_sta_add_debugfs,
746 #endif
747 };