18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2015 Intel Deutschland GmbH
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include <net/mac80211.h>
68c2ecf20Sopenharmony_ci#include "ieee80211_i.h"
78c2ecf20Sopenharmony_ci#include "trace.h"
88c2ecf20Sopenharmony_ci#include "driver-ops.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ciint drv_start(struct ieee80211_local *local)
118c2ecf20Sopenharmony_ci{
128c2ecf20Sopenharmony_ci	int ret;
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci	might_sleep();
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	if (WARN_ON(local->started))
178c2ecf20Sopenharmony_ci		return -EALREADY;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	trace_drv_start(local);
208c2ecf20Sopenharmony_ci	local->started = true;
218c2ecf20Sopenharmony_ci	/* allow rx frames */
228c2ecf20Sopenharmony_ci	smp_mb();
238c2ecf20Sopenharmony_ci	ret = local->ops->start(&local->hw);
248c2ecf20Sopenharmony_ci	trace_drv_return_int(local, ret);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (ret)
278c2ecf20Sopenharmony_ci		local->started = false;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	return ret;
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_civoid drv_stop(struct ieee80211_local *local)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	might_sleep();
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (WARN_ON(!local->started))
378c2ecf20Sopenharmony_ci		return;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	trace_drv_stop(local);
408c2ecf20Sopenharmony_ci	local->ops->stop(&local->hw);
418c2ecf20Sopenharmony_ci	trace_drv_return_void(local);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	/* sync away all work on the tasklet before clearing started */
448c2ecf20Sopenharmony_ci	tasklet_disable(&local->tasklet);
458c2ecf20Sopenharmony_ci	tasklet_enable(&local->tasklet);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	barrier();
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	local->started = false;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciint drv_add_interface(struct ieee80211_local *local,
538c2ecf20Sopenharmony_ci		      struct ieee80211_sub_if_data *sdata)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	int ret;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	might_sleep();
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
608c2ecf20Sopenharmony_ci		    (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
618c2ecf20Sopenharmony_ci		     !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
628c2ecf20Sopenharmony_ci		     !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
638c2ecf20Sopenharmony_ci		return -EINVAL;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	trace_drv_add_interface(local, sdata);
668c2ecf20Sopenharmony_ci	ret = local->ops->add_interface(&local->hw, &sdata->vif);
678c2ecf20Sopenharmony_ci	trace_drv_return_int(local, ret);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (ret == 0)
708c2ecf20Sopenharmony_ci		sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return ret;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciint drv_change_interface(struct ieee80211_local *local,
768c2ecf20Sopenharmony_ci			 struct ieee80211_sub_if_data *sdata,
778c2ecf20Sopenharmony_ci			 enum nl80211_iftype type, bool p2p)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	int ret;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	might_sleep();
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
848c2ecf20Sopenharmony_ci		return -EIO;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	trace_drv_change_interface(local, sdata, type, p2p);
878c2ecf20Sopenharmony_ci	ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
888c2ecf20Sopenharmony_ci	trace_drv_return_int(local, ret);
898c2ecf20Sopenharmony_ci	return ret;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_civoid drv_remove_interface(struct ieee80211_local *local,
938c2ecf20Sopenharmony_ci			  struct ieee80211_sub_if_data *sdata)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	might_sleep();
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
988c2ecf20Sopenharmony_ci		return;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	trace_drv_remove_interface(local, sdata);
1018c2ecf20Sopenharmony_ci	local->ops->remove_interface(&local->hw, &sdata->vif);
1028c2ecf20Sopenharmony_ci	sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
1038c2ecf20Sopenharmony_ci	trace_drv_return_void(local);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci__must_check
1078c2ecf20Sopenharmony_ciint drv_sta_state(struct ieee80211_local *local,
1088c2ecf20Sopenharmony_ci		  struct ieee80211_sub_if_data *sdata,
1098c2ecf20Sopenharmony_ci		  struct sta_info *sta,
1108c2ecf20Sopenharmony_ci		  enum ieee80211_sta_state old_state,
1118c2ecf20Sopenharmony_ci		  enum ieee80211_sta_state new_state)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	int ret = 0;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	might_sleep();
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	sdata = get_bss_sdata(sdata);
1188c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
1198c2ecf20Sopenharmony_ci		return -EIO;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
1228c2ecf20Sopenharmony_ci	if (local->ops->sta_state) {
1238c2ecf20Sopenharmony_ci		ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
1248c2ecf20Sopenharmony_ci					    old_state, new_state);
1258c2ecf20Sopenharmony_ci	} else if (old_state == IEEE80211_STA_AUTH &&
1268c2ecf20Sopenharmony_ci		   new_state == IEEE80211_STA_ASSOC) {
1278c2ecf20Sopenharmony_ci		ret = drv_sta_add(local, sdata, &sta->sta);
1288c2ecf20Sopenharmony_ci		if (ret == 0) {
1298c2ecf20Sopenharmony_ci			sta->uploaded = true;
1308c2ecf20Sopenharmony_ci			if (rcu_access_pointer(sta->sta.rates))
1318c2ecf20Sopenharmony_ci				drv_sta_rate_tbl_update(local, sdata, &sta->sta);
1328c2ecf20Sopenharmony_ci		}
1338c2ecf20Sopenharmony_ci	} else if (old_state == IEEE80211_STA_ASSOC &&
1348c2ecf20Sopenharmony_ci		   new_state == IEEE80211_STA_AUTH) {
1358c2ecf20Sopenharmony_ci		drv_sta_remove(local, sdata, &sta->sta);
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci	trace_drv_return_int(local, ret);
1388c2ecf20Sopenharmony_ci	return ret;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci__must_check
1428c2ecf20Sopenharmony_ciint drv_sta_set_txpwr(struct ieee80211_local *local,
1438c2ecf20Sopenharmony_ci		      struct ieee80211_sub_if_data *sdata,
1448c2ecf20Sopenharmony_ci		      struct sta_info *sta)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	int ret = -EOPNOTSUPP;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	might_sleep();
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	sdata = get_bss_sdata(sdata);
1518c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
1528c2ecf20Sopenharmony_ci		return -EIO;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	trace_drv_sta_set_txpwr(local, sdata, &sta->sta);
1558c2ecf20Sopenharmony_ci	if (local->ops->sta_set_txpwr)
1568c2ecf20Sopenharmony_ci		ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif,
1578c2ecf20Sopenharmony_ci						&sta->sta);
1588c2ecf20Sopenharmony_ci	trace_drv_return_int(local, ret);
1598c2ecf20Sopenharmony_ci	return ret;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_civoid drv_sta_rc_update(struct ieee80211_local *local,
1638c2ecf20Sopenharmony_ci		       struct ieee80211_sub_if_data *sdata,
1648c2ecf20Sopenharmony_ci		       struct ieee80211_sta *sta, u32 changed)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	sdata = get_bss_sdata(sdata);
1678c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
1688c2ecf20Sopenharmony_ci		return;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
1718c2ecf20Sopenharmony_ci		(sdata->vif.type != NL80211_IFTYPE_ADHOC &&
1728c2ecf20Sopenharmony_ci		 sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	trace_drv_sta_rc_update(local, sdata, sta, changed);
1758c2ecf20Sopenharmony_ci	if (local->ops->sta_rc_update)
1768c2ecf20Sopenharmony_ci		local->ops->sta_rc_update(&local->hw, &sdata->vif,
1778c2ecf20Sopenharmony_ci					  sta, changed);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	trace_drv_return_void(local);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ciint drv_conf_tx(struct ieee80211_local *local,
1838c2ecf20Sopenharmony_ci		struct ieee80211_sub_if_data *sdata, u16 ac,
1848c2ecf20Sopenharmony_ci		const struct ieee80211_tx_queue_params *params)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	int ret = -EOPNOTSUPP;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	might_sleep();
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
1918c2ecf20Sopenharmony_ci		return -EIO;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (params->cw_min == 0 || params->cw_min > params->cw_max) {
1948c2ecf20Sopenharmony_ci		/*
1958c2ecf20Sopenharmony_ci		 * If we can't configure hardware anyway, don't warn. We may
1968c2ecf20Sopenharmony_ci		 * never have initialized the CW parameters.
1978c2ecf20Sopenharmony_ci		 */
1988c2ecf20Sopenharmony_ci		WARN_ONCE(local->ops->conf_tx,
1998c2ecf20Sopenharmony_ci			  "%s: invalid CW_min/CW_max: %d/%d\n",
2008c2ecf20Sopenharmony_ci			  sdata->name, params->cw_min, params->cw_max);
2018c2ecf20Sopenharmony_ci		return -EINVAL;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	trace_drv_conf_tx(local, sdata, ac, params);
2058c2ecf20Sopenharmony_ci	if (local->ops->conf_tx)
2068c2ecf20Sopenharmony_ci		ret = local->ops->conf_tx(&local->hw, &sdata->vif,
2078c2ecf20Sopenharmony_ci					  ac, params);
2088c2ecf20Sopenharmony_ci	trace_drv_return_int(local, ret);
2098c2ecf20Sopenharmony_ci	return ret;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ciu64 drv_get_tsf(struct ieee80211_local *local,
2138c2ecf20Sopenharmony_ci		struct ieee80211_sub_if_data *sdata)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	u64 ret = -1ULL;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	might_sleep();
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
2208c2ecf20Sopenharmony_ci		return ret;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	trace_drv_get_tsf(local, sdata);
2238c2ecf20Sopenharmony_ci	if (local->ops->get_tsf)
2248c2ecf20Sopenharmony_ci		ret = local->ops->get_tsf(&local->hw, &sdata->vif);
2258c2ecf20Sopenharmony_ci	trace_drv_return_u64(local, ret);
2268c2ecf20Sopenharmony_ci	return ret;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_civoid drv_set_tsf(struct ieee80211_local *local,
2308c2ecf20Sopenharmony_ci		 struct ieee80211_sub_if_data *sdata,
2318c2ecf20Sopenharmony_ci		 u64 tsf)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	might_sleep();
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
2368c2ecf20Sopenharmony_ci		return;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	trace_drv_set_tsf(local, sdata, tsf);
2398c2ecf20Sopenharmony_ci	if (local->ops->set_tsf)
2408c2ecf20Sopenharmony_ci		local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
2418c2ecf20Sopenharmony_ci	trace_drv_return_void(local);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_civoid drv_offset_tsf(struct ieee80211_local *local,
2458c2ecf20Sopenharmony_ci		    struct ieee80211_sub_if_data *sdata,
2468c2ecf20Sopenharmony_ci		    s64 offset)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	might_sleep();
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
2518c2ecf20Sopenharmony_ci		return;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	trace_drv_offset_tsf(local, sdata, offset);
2548c2ecf20Sopenharmony_ci	if (local->ops->offset_tsf)
2558c2ecf20Sopenharmony_ci		local->ops->offset_tsf(&local->hw, &sdata->vif, offset);
2568c2ecf20Sopenharmony_ci	trace_drv_return_void(local);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_civoid drv_reset_tsf(struct ieee80211_local *local,
2608c2ecf20Sopenharmony_ci		   struct ieee80211_sub_if_data *sdata)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	might_sleep();
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
2658c2ecf20Sopenharmony_ci		return;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	trace_drv_reset_tsf(local, sdata);
2688c2ecf20Sopenharmony_ci	if (local->ops->reset_tsf)
2698c2ecf20Sopenharmony_ci		local->ops->reset_tsf(&local->hw, &sdata->vif);
2708c2ecf20Sopenharmony_ci	trace_drv_return_void(local);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciint drv_switch_vif_chanctx(struct ieee80211_local *local,
2748c2ecf20Sopenharmony_ci			   struct ieee80211_vif_chanctx_switch *vifs,
2758c2ecf20Sopenharmony_ci			   int n_vifs, enum ieee80211_chanctx_switch_mode mode)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	int ret = 0;
2788c2ecf20Sopenharmony_ci	int i;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	might_sleep();
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	if (!local->ops->switch_vif_chanctx)
2838c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	for (i = 0; i < n_vifs; i++) {
2868c2ecf20Sopenharmony_ci		struct ieee80211_chanctx *new_ctx =
2878c2ecf20Sopenharmony_ci			container_of(vifs[i].new_ctx,
2888c2ecf20Sopenharmony_ci				     struct ieee80211_chanctx,
2898c2ecf20Sopenharmony_ci				     conf);
2908c2ecf20Sopenharmony_ci		struct ieee80211_chanctx *old_ctx =
2918c2ecf20Sopenharmony_ci			container_of(vifs[i].old_ctx,
2928c2ecf20Sopenharmony_ci				     struct ieee80211_chanctx,
2938c2ecf20Sopenharmony_ci				     conf);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		WARN_ON_ONCE(!old_ctx->driver_present);
2968c2ecf20Sopenharmony_ci		WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
2978c2ecf20Sopenharmony_ci			      new_ctx->driver_present) ||
2988c2ecf20Sopenharmony_ci			     (mode == CHANCTX_SWMODE_REASSIGN_VIF &&
2998c2ecf20Sopenharmony_ci			      !new_ctx->driver_present));
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
3038c2ecf20Sopenharmony_ci	ret = local->ops->switch_vif_chanctx(&local->hw,
3048c2ecf20Sopenharmony_ci					     vifs, n_vifs, mode);
3058c2ecf20Sopenharmony_ci	trace_drv_return_int(local, ret);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
3088c2ecf20Sopenharmony_ci		for (i = 0; i < n_vifs; i++) {
3098c2ecf20Sopenharmony_ci			struct ieee80211_chanctx *new_ctx =
3108c2ecf20Sopenharmony_ci				container_of(vifs[i].new_ctx,
3118c2ecf20Sopenharmony_ci					     struct ieee80211_chanctx,
3128c2ecf20Sopenharmony_ci					     conf);
3138c2ecf20Sopenharmony_ci			struct ieee80211_chanctx *old_ctx =
3148c2ecf20Sopenharmony_ci				container_of(vifs[i].old_ctx,
3158c2ecf20Sopenharmony_ci					     struct ieee80211_chanctx,
3168c2ecf20Sopenharmony_ci					     conf);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci			new_ctx->driver_present = true;
3198c2ecf20Sopenharmony_ci			old_ctx->driver_present = false;
3208c2ecf20Sopenharmony_ci		}
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	return ret;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciint drv_ampdu_action(struct ieee80211_local *local,
3278c2ecf20Sopenharmony_ci		     struct ieee80211_sub_if_data *sdata,
3288c2ecf20Sopenharmony_ci		     struct ieee80211_ampdu_params *params)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	int ret = -EOPNOTSUPP;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	might_sleep();
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (!sdata)
3358c2ecf20Sopenharmony_ci		return -EIO;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	sdata = get_bss_sdata(sdata);
3388c2ecf20Sopenharmony_ci	if (!check_sdata_in_driver(sdata))
3398c2ecf20Sopenharmony_ci		return -EIO;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	trace_drv_ampdu_action(local, sdata, params);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (local->ops->ampdu_action)
3448c2ecf20Sopenharmony_ci		ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	trace_drv_return_int(local, ret);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return ret;
3498c2ecf20Sopenharmony_ci}
350