1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2015 Intel Deutschland GmbH
5 #include <net/mac80211.h>
6 #include "ieee80211_i.h"
8 #include "driver-ops.h"
10 int drv_start(struct ieee80211_local
*local
)
16 if (WARN_ON(local
->started
))
19 trace_drv_start(local
);
20 local
->started
= true;
23 ret
= local
->ops
->start(&local
->hw
);
24 trace_drv_return_int(local
, ret
);
27 local
->started
= false;
32 void drv_stop(struct ieee80211_local
*local
)
36 if (WARN_ON(!local
->started
))
39 trace_drv_stop(local
);
40 local
->ops
->stop(&local
->hw
);
41 trace_drv_return_void(local
);
43 /* sync away all work on the tasklet before clearing started */
44 tasklet_disable(&local
->tasklet
);
45 tasklet_enable(&local
->tasklet
);
49 local
->started
= false;
52 int drv_add_interface(struct ieee80211_local
*local
,
53 struct ieee80211_sub_if_data
*sdata
)
59 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
))))
65 trace_drv_add_interface(local
, sdata
);
66 ret
= local
->ops
->add_interface(&local
->hw
, &sdata
->vif
);
67 trace_drv_return_int(local
, ret
);
70 sdata
->flags
|= IEEE80211_SDATA_IN_DRIVER
;
75 int drv_change_interface(struct ieee80211_local
*local
,
76 struct ieee80211_sub_if_data
*sdata
,
77 enum nl80211_iftype type
, bool p2p
)
83 if (!check_sdata_in_driver(sdata
))
86 trace_drv_change_interface(local
, sdata
, type
, p2p
);
87 ret
= local
->ops
->change_interface(&local
->hw
, &sdata
->vif
, type
, p2p
);
88 trace_drv_return_int(local
, ret
);
92 void drv_remove_interface(struct ieee80211_local
*local
,
93 struct ieee80211_sub_if_data
*sdata
)
97 if (!check_sdata_in_driver(sdata
))
100 trace_drv_remove_interface(local
, sdata
);
101 local
->ops
->remove_interface(&local
->hw
, &sdata
->vif
);
102 sdata
->flags
&= ~IEEE80211_SDATA_IN_DRIVER
;
103 trace_drv_return_void(local
);
107 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
)
117 sdata
= get_bss_sdata(sdata
);
118 if (!check_sdata_in_driver(sdata
))
121 trace_drv_sta_state(local
, sdata
, &sta
->sta
, old_state
, new_state
);
122 if (local
->ops
->sta_state
) {
123 ret
= local
->ops
->sta_state(&local
->hw
, &sdata
->vif
, &sta
->sta
,
124 old_state
, new_state
);
125 } else if (old_state
== IEEE80211_STA_AUTH
&&
126 new_state
== IEEE80211_STA_ASSOC
) {
127 ret
= drv_sta_add(local
, sdata
, &sta
->sta
);
129 sta
->uploaded
= true;
130 } else if (old_state
== IEEE80211_STA_ASSOC
&&
131 new_state
== IEEE80211_STA_AUTH
) {
132 drv_sta_remove(local
, sdata
, &sta
->sta
);
134 trace_drv_return_int(local
, ret
);
139 int drv_sta_set_txpwr(struct ieee80211_local
*local
,
140 struct ieee80211_sub_if_data
*sdata
,
141 struct sta_info
*sta
)
143 int ret
= -EOPNOTSUPP
;
147 sdata
= get_bss_sdata(sdata
);
148 if (!check_sdata_in_driver(sdata
))
151 trace_drv_sta_set_txpwr(local
, sdata
, &sta
->sta
);
152 if (local
->ops
->sta_set_txpwr
)
153 ret
= local
->ops
->sta_set_txpwr(&local
->hw
, &sdata
->vif
,
155 trace_drv_return_int(local
, ret
);
159 void drv_sta_rc_update(struct ieee80211_local
*local
,
160 struct ieee80211_sub_if_data
*sdata
,
161 struct ieee80211_sta
*sta
, u32 changed
)
163 sdata
= get_bss_sdata(sdata
);
164 if (!check_sdata_in_driver(sdata
))
167 WARN_ON(changed
& IEEE80211_RC_SUPP_RATES_CHANGED
&&
168 (sdata
->vif
.type
!= NL80211_IFTYPE_ADHOC
&&
169 sdata
->vif
.type
!= NL80211_IFTYPE_MESH_POINT
));
171 trace_drv_sta_rc_update(local
, sdata
, sta
, changed
);
172 if (local
->ops
->sta_rc_update
)
173 local
->ops
->sta_rc_update(&local
->hw
, &sdata
->vif
,
176 trace_drv_return_void(local
);
179 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
)
183 int ret
= -EOPNOTSUPP
;
187 if (!check_sdata_in_driver(sdata
))
190 if (params
->cw_min
== 0 || params
->cw_min
> params
->cw_max
) {
192 * If we can't configure hardware anyway, don't warn. We may
193 * never have initialized the CW parameters.
195 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
);
201 trace_drv_conf_tx(local
, sdata
, ac
, params
);
202 if (local
->ops
->conf_tx
)
203 ret
= local
->ops
->conf_tx(&local
->hw
, &sdata
->vif
,
205 trace_drv_return_int(local
, ret
);
209 u64
drv_get_tsf(struct ieee80211_local
*local
,
210 struct ieee80211_sub_if_data
*sdata
)
216 if (!check_sdata_in_driver(sdata
))
219 trace_drv_get_tsf(local
, sdata
);
220 if (local
->ops
->get_tsf
)
221 ret
= local
->ops
->get_tsf(&local
->hw
, &sdata
->vif
);
222 trace_drv_return_u64(local
, ret
);
226 void drv_set_tsf(struct ieee80211_local
*local
,
227 struct ieee80211_sub_if_data
*sdata
,
232 if (!check_sdata_in_driver(sdata
))
235 trace_drv_set_tsf(local
, sdata
, tsf
);
236 if (local
->ops
->set_tsf
)
237 local
->ops
->set_tsf(&local
->hw
, &sdata
->vif
, tsf
);
238 trace_drv_return_void(local
);
241 void drv_offset_tsf(struct ieee80211_local
*local
,
242 struct ieee80211_sub_if_data
*sdata
,
247 if (!check_sdata_in_driver(sdata
))
250 trace_drv_offset_tsf(local
, sdata
, offset
);
251 if (local
->ops
->offset_tsf
)
252 local
->ops
->offset_tsf(&local
->hw
, &sdata
->vif
, offset
);
253 trace_drv_return_void(local
);
256 void drv_reset_tsf(struct ieee80211_local
*local
,
257 struct ieee80211_sub_if_data
*sdata
)
261 if (!check_sdata_in_driver(sdata
))
264 trace_drv_reset_tsf(local
, sdata
);
265 if (local
->ops
->reset_tsf
)
266 local
->ops
->reset_tsf(&local
->hw
, &sdata
->vif
);
267 trace_drv_return_void(local
);
270 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
)
279 if (!local
->ops
->switch_vif_chanctx
)
282 for (i
= 0; i
< n_vifs
; i
++) {
283 struct ieee80211_chanctx
*new_ctx
=
284 container_of(vifs
[i
].new_ctx
,
285 struct ieee80211_chanctx
,
287 struct ieee80211_chanctx
*old_ctx
=
288 container_of(vifs
[i
].old_ctx
,
289 struct ieee80211_chanctx
,
292 WARN_ON_ONCE(!old_ctx
->driver_present
);
293 WARN_ON_ONCE((mode
== CHANCTX_SWMODE_SWAP_CONTEXTS
&&
294 new_ctx
->driver_present
) ||
295 (mode
== CHANCTX_SWMODE_REASSIGN_VIF
&&
296 !new_ctx
->driver_present
));
299 trace_drv_switch_vif_chanctx(local
, vifs
, n_vifs
, mode
);
300 ret
= local
->ops
->switch_vif_chanctx(&local
->hw
,
302 trace_drv_return_int(local
, ret
);
304 if (!ret
&& mode
== CHANCTX_SWMODE_SWAP_CONTEXTS
) {
305 for (i
= 0; i
< n_vifs
; i
++) {
306 struct ieee80211_chanctx
*new_ctx
=
307 container_of(vifs
[i
].new_ctx
,
308 struct ieee80211_chanctx
,
310 struct ieee80211_chanctx
*old_ctx
=
311 container_of(vifs
[i
].old_ctx
,
312 struct ieee80211_chanctx
,
315 new_ctx
->driver_present
= true;
316 old_ctx
->driver_present
= false;
323 int drv_ampdu_action(struct ieee80211_local
*local
,
324 struct ieee80211_sub_if_data
*sdata
,
325 struct ieee80211_ampdu_params
*params
)
327 int ret
= -EOPNOTSUPP
;
331 sdata
= get_bss_sdata(sdata
);
332 if (!check_sdata_in_driver(sdata
))
335 trace_drv_ampdu_action(local
, sdata
, params
);
337 if (local
->ops
->ampdu_action
)
338 ret
= local
->ops
->ampdu_action(&local
->hw
, &sdata
->vif
, params
);
340 trace_drv_return_int(local
, ret
);