]> Git Repo - linux.git/blob - drivers/net/wireless/intel/iwlwifi/mvm/binding.c
Linux 6.14-rc3
[linux.git] / drivers / net / wireless / intel / iwlwifi / mvm / binding.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2012-2014, 2020 Intel Corporation
4  * Copyright (C) 2016 Intel Deutschland GmbH
5  * Copyright (C) 2022, 2024 Intel Corporation
6  */
7 #include <net/mac80211.h>
8 #include "fw-api.h"
9 #include "mvm.h"
10
11 struct iwl_mvm_iface_iterator_data {
12         struct ieee80211_vif *ignore_vif;
13         int idx;
14
15         struct iwl_mvm_phy_ctxt *phyctxt;
16
17         u16 ids[MAX_MACS_IN_BINDING];
18         u16 colors[MAX_MACS_IN_BINDING];
19 };
20
21 static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action,
22                                struct iwl_mvm_iface_iterator_data *data)
23 {
24         struct iwl_binding_cmd cmd;
25         struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt;
26         int i, ret;
27         u32 status;
28         int size;
29
30         memset(&cmd, 0, sizeof(cmd));
31
32         if (fw_has_capa(&mvm->fw->ucode_capa,
33                         IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) {
34                 size = sizeof(cmd);
35                 cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm,
36                                                               phyctxt->channel->band));
37         } else {
38                 size = IWL_BINDING_CMD_SIZE_V1;
39         }
40
41         cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
42                                                            phyctxt->color));
43         cmd.action = cpu_to_le32(action);
44         cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
45                                                   phyctxt->color));
46
47         for (i = 0; i < MAX_MACS_IN_BINDING; i++)
48                 cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
49         for (i = 0; i < data->idx; i++)
50                 cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i],
51                                                               data->colors[i]));
52
53         status = 0;
54         ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
55                                           size, &cmd, &status);
56         if (ret) {
57                 IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n",
58                         action, ret);
59                 return ret;
60         }
61
62         if (status) {
63                 IWL_ERR(mvm, "Binding command failed: %u\n", status);
64                 ret = -EIO;
65         }
66
67         return ret;
68 }
69
70 static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
71                                    struct ieee80211_vif *vif)
72 {
73         struct iwl_mvm_iface_iterator_data *data = _data;
74         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
75
76         if (vif == data->ignore_vif)
77                 return;
78
79         if (mvmvif->deflink.phy_ctxt != data->phyctxt)
80                 return;
81
82         if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING))
83                 return;
84
85         data->ids[data->idx] = mvmvif->id;
86         data->colors[data->idx] = mvmvif->color;
87         data->idx++;
88 }
89
90 static int iwl_mvm_binding_update(struct iwl_mvm *mvm,
91                                   struct ieee80211_vif *vif,
92                                   struct iwl_mvm_phy_ctxt *phyctxt,
93                                   bool add)
94 {
95         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
96         struct iwl_mvm_iface_iterator_data data = {
97                 .ignore_vif = vif,
98                 .phyctxt = phyctxt,
99         };
100         u32 action = FW_CTXT_ACTION_MODIFY;
101
102         lockdep_assert_held(&mvm->mutex);
103
104         ieee80211_iterate_active_interfaces_atomic(mvm->hw,
105                                                    IEEE80211_IFACE_ITER_NORMAL,
106                                                    iwl_mvm_iface_iterator,
107                                                    &data);
108
109         /*
110          * If there are no other interfaces yet we
111          * need to create a new binding.
112          */
113         if (data.idx == 0) {
114                 if (add)
115                         action = FW_CTXT_ACTION_ADD;
116                 else
117                         action = FW_CTXT_ACTION_REMOVE;
118         }
119
120         if (add) {
121                 if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING))
122                         return -EINVAL;
123
124                 data.ids[data.idx] = mvmvif->id;
125                 data.colors[data.idx] = mvmvif->color;
126                 data.idx++;
127         }
128
129         return iwl_mvm_binding_cmd(mvm, action, &data);
130 }
131
132 int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
133 {
134         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
135
136         if (WARN_ON_ONCE(!mvmvif->deflink.phy_ctxt))
137                 return -EINVAL;
138
139         /*
140          * Update SF - Disable if needed. if this fails, SF might still be on
141          * while many macs are bound, which is forbidden - so fail the binding.
142          */
143         if (iwl_mvm_sf_update(mvm, vif, false))
144                 return -EINVAL;
145
146         return iwl_mvm_binding_update(mvm, vif, mvmvif->deflink.phy_ctxt,
147                                       true);
148 }
149
150 int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
151 {
152         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
153         int ret;
154
155         if (WARN_ON_ONCE(!mvmvif->deflink.phy_ctxt))
156                 return -EINVAL;
157
158         ret = iwl_mvm_binding_update(mvm, vif, mvmvif->deflink.phy_ctxt,
159                                      false);
160
161         if (!ret && iwl_mvm_sf_update(mvm, vif, true))
162                 IWL_ERR(mvm, "Failed to update SF state\n");
163
164         return ret;
165 }
166
167 u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band)
168 {
169         if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CDB_SUPPORT) ||
170             band == NL80211_BAND_2GHZ)
171                 return IWL_LMAC_24G_INDEX;
172         return IWL_LMAC_5G_INDEX;
173 }
This page took 0.042669 seconds and 4 git commands to generate.