Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Copyright 2015 Intel Deutschland GmbH
4 : : */
5 : : #include <net/mac80211.h>
6 : : #include "ieee80211_i.h"
7 : : #include "trace.h"
8 : : #include "driver-ops.h"
9 : :
10 : 0 : int drv_start(struct ieee80211_local *local)
11 : : {
12 : 0 : int ret;
13 : :
14 : 0 : might_sleep();
15 : :
16 [ # # # # ]: 0 : if (WARN_ON(local->started))
17 : : return -EALREADY;
18 : :
19 : 0 : trace_drv_start(local);
20 : 0 : local->started = true;
21 : : /* allow rx frames */
22 : 0 : smp_mb();
23 : 0 : ret = local->ops->start(&local->hw);
24 : 0 : trace_drv_return_int(local, ret);
25 : :
26 [ # # ]: 0 : if (ret)
27 : 0 : local->started = false;
28 : :
29 : : return ret;
30 : : }
31 : :
32 : 0 : void drv_stop(struct ieee80211_local *local)
33 : : {
34 : 0 : might_sleep();
35 : :
36 [ # # # # ]: 0 : if (WARN_ON(!local->started))
37 : : return;
38 : :
39 : 0 : trace_drv_stop(local);
40 : 0 : local->ops->stop(&local->hw);
41 : 0 : trace_drv_return_void(local);
42 : :
43 : : /* sync away all work on the tasklet before clearing started */
44 : 0 : tasklet_disable(&local->tasklet);
45 : 0 : tasklet_enable(&local->tasklet);
46 : :
47 : 0 : barrier();
48 : :
49 : 0 : local->started = false;
50 : : }
51 : :
52 : 0 : int drv_add_interface(struct ieee80211_local *local,
53 : : struct ieee80211_sub_if_data *sdata)
54 : : {
55 : 0 : int ret;
56 : :
57 : 0 : might_sleep();
58 : :
59 [ # # # # : 0 : if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
# # # # #
# # # ]
60 : : (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
61 : : !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
62 : : !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
63 : : return -EINVAL;
64 : :
65 : 0 : trace_drv_add_interface(local, sdata);
66 : 0 : ret = local->ops->add_interface(&local->hw, &sdata->vif);
67 : 0 : trace_drv_return_int(local, ret);
68 : :
69 [ # # ]: 0 : if (ret == 0)
70 : 0 : sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
71 : :
72 : : return ret;
73 : : }
74 : :
75 : 0 : int drv_change_interface(struct ieee80211_local *local,
76 : : struct ieee80211_sub_if_data *sdata,
77 : : enum nl80211_iftype type, bool p2p)
78 : : {
79 : 0 : int ret;
80 : :
81 : 0 : might_sleep();
82 : :
83 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
84 : : return -EIO;
85 : :
86 : 0 : trace_drv_change_interface(local, sdata, type, p2p);
87 : 0 : ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
88 : 0 : trace_drv_return_int(local, ret);
89 : 0 : return ret;
90 : : }
91 : :
92 : 0 : void drv_remove_interface(struct ieee80211_local *local,
93 : : struct ieee80211_sub_if_data *sdata)
94 : : {
95 : 0 : might_sleep();
96 : :
97 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
98 : : return;
99 : :
100 : 0 : trace_drv_remove_interface(local, sdata);
101 : 0 : local->ops->remove_interface(&local->hw, &sdata->vif);
102 : 0 : sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
103 : 0 : trace_drv_return_void(local);
104 : : }
105 : :
106 : : __must_check
107 : 0 : int drv_sta_state(struct ieee80211_local *local,
108 : : struct ieee80211_sub_if_data *sdata,
109 : : struct sta_info *sta,
110 : : enum ieee80211_sta_state old_state,
111 : : enum ieee80211_sta_state new_state)
112 : : {
113 : 0 : int ret = 0;
114 : :
115 : 0 : might_sleep();
116 : :
117 [ # # ]: 0 : sdata = get_bss_sdata(sdata);
118 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
119 : : return -EIO;
120 : :
121 : 0 : trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
122 [ # # ]: 0 : if (local->ops->sta_state) {
123 : 0 : ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
124 : : old_state, new_state);
125 : 0 : } else if (old_state == IEEE80211_STA_AUTH &&
126 [ # # ]: 0 : new_state == IEEE80211_STA_ASSOC) {
127 : 0 : ret = drv_sta_add(local, sdata, &sta->sta);
128 [ # # ]: 0 : if (ret == 0)
129 : 0 : sta->uploaded = true;
130 : 0 : } else if (old_state == IEEE80211_STA_ASSOC &&
131 [ # # ]: 0 : new_state == IEEE80211_STA_AUTH) {
132 : 0 : drv_sta_remove(local, sdata, &sta->sta);
133 : : }
134 : 0 : trace_drv_return_int(local, ret);
135 : 0 : return ret;
136 : : }
137 : :
138 : : __must_check
139 : 0 : int drv_sta_set_txpwr(struct ieee80211_local *local,
140 : : struct ieee80211_sub_if_data *sdata,
141 : : struct sta_info *sta)
142 : : {
143 : 0 : int ret = -EOPNOTSUPP;
144 : :
145 : 0 : might_sleep();
146 : :
147 [ # # ]: 0 : sdata = get_bss_sdata(sdata);
148 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
149 : : return -EIO;
150 : :
151 : 0 : trace_drv_sta_set_txpwr(local, sdata, &sta->sta);
152 [ # # ]: 0 : if (local->ops->sta_set_txpwr)
153 : 0 : ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif,
154 : : &sta->sta);
155 : 0 : trace_drv_return_int(local, ret);
156 : 0 : return ret;
157 : : }
158 : :
159 : 0 : void drv_sta_rc_update(struct ieee80211_local *local,
160 : : struct ieee80211_sub_if_data *sdata,
161 : : struct ieee80211_sta *sta, u32 changed)
162 : : {
163 [ # # ]: 0 : sdata = get_bss_sdata(sdata);
164 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
165 : : return;
166 : :
167 [ # # # # : 0 : WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
# # ]
168 : : (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
169 : : sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
170 : :
171 : 0 : trace_drv_sta_rc_update(local, sdata, sta, changed);
172 [ # # ]: 0 : if (local->ops->sta_rc_update)
173 : 0 : local->ops->sta_rc_update(&local->hw, &sdata->vif,
174 : : sta, changed);
175 : :
176 : 0 : trace_drv_return_void(local);
177 : : }
178 : :
179 : 0 : int drv_conf_tx(struct ieee80211_local *local,
180 : : struct ieee80211_sub_if_data *sdata, u16 ac,
181 : : const struct ieee80211_tx_queue_params *params)
182 : : {
183 : 0 : int ret = -EOPNOTSUPP;
184 : :
185 : 0 : might_sleep();
186 : :
187 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
188 : : return -EIO;
189 : :
190 [ # # # # ]: 0 : if (params->cw_min == 0 || params->cw_min > params->cw_max) {
191 : : /*
192 : : * If we can't configure hardware anyway, don't warn. We may
193 : : * never have initialized the CW parameters.
194 : : */
195 [ # # # # ]: 0 : WARN_ONCE(local->ops->conf_tx,
196 : : "%s: invalid CW_min/CW_max: %d/%d\n",
197 : : sdata->name, params->cw_min, params->cw_max);
198 : 0 : return -EINVAL;
199 : : }
200 : :
201 : 0 : trace_drv_conf_tx(local, sdata, ac, params);
202 [ # # ]: 0 : if (local->ops->conf_tx)
203 : 0 : ret = local->ops->conf_tx(&local->hw, &sdata->vif,
204 : : ac, params);
205 : 0 : trace_drv_return_int(local, ret);
206 : 0 : return ret;
207 : : }
208 : :
209 : 0 : u64 drv_get_tsf(struct ieee80211_local *local,
210 : : struct ieee80211_sub_if_data *sdata)
211 : : {
212 : 0 : u64 ret = -1ULL;
213 : :
214 : 0 : might_sleep();
215 : :
216 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
217 : : return ret;
218 : :
219 : 0 : trace_drv_get_tsf(local, sdata);
220 [ # # ]: 0 : if (local->ops->get_tsf)
221 : 0 : ret = local->ops->get_tsf(&local->hw, &sdata->vif);
222 : 0 : trace_drv_return_u64(local, ret);
223 : 0 : return ret;
224 : : }
225 : :
226 : 0 : void drv_set_tsf(struct ieee80211_local *local,
227 : : struct ieee80211_sub_if_data *sdata,
228 : : u64 tsf)
229 : : {
230 : 0 : might_sleep();
231 : :
232 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
233 : : return;
234 : :
235 : 0 : trace_drv_set_tsf(local, sdata, tsf);
236 [ # # ]: 0 : if (local->ops->set_tsf)
237 : 0 : local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
238 : 0 : trace_drv_return_void(local);
239 : : }
240 : :
241 : 0 : void drv_offset_tsf(struct ieee80211_local *local,
242 : : struct ieee80211_sub_if_data *sdata,
243 : : s64 offset)
244 : : {
245 : 0 : might_sleep();
246 : :
247 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
248 : : return;
249 : :
250 : 0 : trace_drv_offset_tsf(local, sdata, offset);
251 [ # # ]: 0 : if (local->ops->offset_tsf)
252 : 0 : local->ops->offset_tsf(&local->hw, &sdata->vif, offset);
253 : 0 : trace_drv_return_void(local);
254 : : }
255 : :
256 : 0 : void drv_reset_tsf(struct ieee80211_local *local,
257 : : struct ieee80211_sub_if_data *sdata)
258 : : {
259 : 0 : might_sleep();
260 : :
261 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
262 : : return;
263 : :
264 : 0 : trace_drv_reset_tsf(local, sdata);
265 [ # # ]: 0 : if (local->ops->reset_tsf)
266 : 0 : local->ops->reset_tsf(&local->hw, &sdata->vif);
267 : 0 : trace_drv_return_void(local);
268 : : }
269 : :
270 : 0 : int drv_switch_vif_chanctx(struct ieee80211_local *local,
271 : : struct ieee80211_vif_chanctx_switch *vifs,
272 : : int n_vifs, enum ieee80211_chanctx_switch_mode mode)
273 : : {
274 : 0 : int ret = 0;
275 : 0 : int i;
276 : :
277 : 0 : might_sleep();
278 : :
279 [ # # ]: 0 : if (!local->ops->switch_vif_chanctx)
280 : : return -EOPNOTSUPP;
281 : :
282 [ # # ]: 0 : for (i = 0; i < n_vifs; i++) {
283 : 0 : struct ieee80211_chanctx *new_ctx =
284 : 0 : container_of(vifs[i].new_ctx,
285 : : struct ieee80211_chanctx,
286 : : conf);
287 : 0 : struct ieee80211_chanctx *old_ctx =
288 : 0 : container_of(vifs[i].old_ctx,
289 : : struct ieee80211_chanctx,
290 : : conf);
291 : :
292 [ # # ]: 0 : WARN_ON_ONCE(!old_ctx->driver_present);
293 [ # # # # : 0 : WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
# # # # #
# ]
294 : : new_ctx->driver_present) ||
295 : : (mode == CHANCTX_SWMODE_REASSIGN_VIF &&
296 : : !new_ctx->driver_present));
297 : : }
298 : :
299 : 0 : trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
300 : 0 : ret = local->ops->switch_vif_chanctx(&local->hw,
301 : : vifs, n_vifs, mode);
302 : 0 : trace_drv_return_int(local, ret);
303 : :
304 [ # # ]: 0 : if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
305 [ # # ]: 0 : for (i = 0; i < n_vifs; i++) {
306 : 0 : struct ieee80211_chanctx *new_ctx =
307 : 0 : container_of(vifs[i].new_ctx,
308 : : struct ieee80211_chanctx,
309 : : conf);
310 : 0 : struct ieee80211_chanctx *old_ctx =
311 : 0 : container_of(vifs[i].old_ctx,
312 : : struct ieee80211_chanctx,
313 : : conf);
314 : :
315 : 0 : new_ctx->driver_present = true;
316 : 0 : old_ctx->driver_present = false;
317 : : }
318 : : }
319 : :
320 : : return ret;
321 : : }
322 : :
323 : 0 : int drv_ampdu_action(struct ieee80211_local *local,
324 : : struct ieee80211_sub_if_data *sdata,
325 : : struct ieee80211_ampdu_params *params)
326 : : {
327 : 0 : int ret = -EOPNOTSUPP;
328 : :
329 : 0 : might_sleep();
330 : :
331 [ # # ]: 0 : sdata = get_bss_sdata(sdata);
332 [ # # ]: 0 : if (!check_sdata_in_driver(sdata))
333 : : return -EIO;
334 : :
335 : 0 : trace_drv_ampdu_action(local, sdata, params);
336 : :
337 [ # # ]: 0 : if (local->ops->ampdu_action)
338 : 0 : ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params);
339 : :
340 : 0 : trace_drv_return_int(local, ret);
341 : :
342 : 0 : return ret;
343 : : }
|