1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64#include <net/mac80211.h>
65#include "fw-api.h"
66#include "mvm.h"
67
68struct iwl_mvm_iface_iterator_data {
69 struct ieee80211_vif *ignore_vif;
70 int idx;
71
72 struct iwl_mvm_phy_ctxt *phyctxt;
73
74 u16 ids[MAX_MACS_IN_BINDING];
75 u16 colors[MAX_MACS_IN_BINDING];
76};
77
78static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action,
79 struct iwl_mvm_iface_iterator_data *data)
80{
81 struct iwl_binding_cmd cmd;
82 struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt;
83 int i, ret;
84 u32 status;
85
86 memset(&cmd, 0, sizeof(cmd));
87
88 cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
89 phyctxt->color));
90 cmd.action = cpu_to_le32(action);
91 cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
92 phyctxt->color));
93
94 for (i = 0; i < MAX_MACS_IN_BINDING; i++)
95 cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
96 for (i = 0; i < data->idx; i++)
97 cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i],
98 data->colors[i]));
99
100 status = 0;
101 ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
102 sizeof(cmd), &cmd, &status);
103 if (ret) {
104 IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n",
105 action, ret);
106 return ret;
107 }
108
109 if (status) {
110 IWL_ERR(mvm, "Binding command failed: %u\n", status);
111 ret = -EIO;
112 }
113
114 return ret;
115}
116
117static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
118 struct ieee80211_vif *vif)
119{
120 struct iwl_mvm_iface_iterator_data *data = _data;
121 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
122
123 if (vif == data->ignore_vif)
124 return;
125
126 if (mvmvif->phy_ctxt != data->phyctxt)
127 return;
128
129 if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING))
130 return;
131
132 data->ids[data->idx] = mvmvif->id;
133 data->colors[data->idx] = mvmvif->color;
134 data->idx++;
135}
136
137static int iwl_mvm_binding_update(struct iwl_mvm *mvm,
138 struct ieee80211_vif *vif,
139 struct iwl_mvm_phy_ctxt *phyctxt,
140 bool add)
141{
142 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
143 struct iwl_mvm_iface_iterator_data data = {
144 .ignore_vif = vif,
145 .phyctxt = phyctxt,
146 };
147 u32 action = FW_CTXT_ACTION_MODIFY;
148
149 lockdep_assert_held(&mvm->mutex);
150
151 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
152 IEEE80211_IFACE_ITER_NORMAL,
153 iwl_mvm_iface_iterator,
154 &data);
155
156
157
158
159
160 if (data.idx == 0) {
161 if (add)
162 action = FW_CTXT_ACTION_ADD;
163 else
164 action = FW_CTXT_ACTION_REMOVE;
165 }
166
167 if (add) {
168 if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING))
169 return -EINVAL;
170
171 data.ids[data.idx] = mvmvif->id;
172 data.colors[data.idx] = mvmvif->color;
173 data.idx++;
174 }
175
176 return iwl_mvm_binding_cmd(mvm, action, &data);
177}
178
179int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
180{
181 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
182
183 if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
184 return -EINVAL;
185
186
187
188
189
190 if (iwl_mvm_sf_update(mvm, vif, false))
191 return -EINVAL;
192
193 return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
194}
195
196int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
197{
198 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
199 int ret;
200
201 if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
202 return -EINVAL;
203
204 ret = iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
205
206 if (!ret)
207 if (iwl_mvm_sf_update(mvm, vif, true))
208 IWL_ERR(mvm, "Failed to update SF state\n");
209
210 return ret;
211}
212