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