162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2015 Intel Deutschland GmbH 462306a36Sopenharmony_ci * Copyright (C) 2022-2023 Intel Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <net/mac80211.h> 762306a36Sopenharmony_ci#include "ieee80211_i.h" 862306a36Sopenharmony_ci#include "trace.h" 962306a36Sopenharmony_ci#include "driver-ops.h" 1062306a36Sopenharmony_ci#include "debugfs_sta.h" 1162306a36Sopenharmony_ci#include "debugfs_netdev.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ciint drv_start(struct ieee80211_local *local) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci int ret; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci might_sleep(); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci if (WARN_ON(local->started)) 2062306a36Sopenharmony_ci return -EALREADY; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci trace_drv_start(local); 2362306a36Sopenharmony_ci local->started = true; 2462306a36Sopenharmony_ci /* allow rx frames */ 2562306a36Sopenharmony_ci smp_mb(); 2662306a36Sopenharmony_ci ret = local->ops->start(&local->hw); 2762306a36Sopenharmony_ci trace_drv_return_int(local, ret); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (ret) 3062306a36Sopenharmony_ci local->started = false; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci return ret; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_civoid drv_stop(struct ieee80211_local *local) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci might_sleep(); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (WARN_ON(!local->started)) 4062306a36Sopenharmony_ci return; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci trace_drv_stop(local); 4362306a36Sopenharmony_ci local->ops->stop(&local->hw); 4462306a36Sopenharmony_ci trace_drv_return_void(local); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* sync away all work on the tasklet before clearing started */ 4762306a36Sopenharmony_ci tasklet_disable(&local->tasklet); 4862306a36Sopenharmony_ci tasklet_enable(&local->tasklet); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci barrier(); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci local->started = false; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ciint drv_add_interface(struct ieee80211_local *local, 5662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci int ret; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci might_sleep(); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || 6362306a36Sopenharmony_ci (sdata->vif.type == NL80211_IFTYPE_MONITOR && 6462306a36Sopenharmony_ci !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) && 6562306a36Sopenharmony_ci !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE)))) 6662306a36Sopenharmony_ci return -EINVAL; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci trace_drv_add_interface(local, sdata); 6962306a36Sopenharmony_ci ret = local->ops->add_interface(&local->hw, &sdata->vif); 7062306a36Sopenharmony_ci trace_drv_return_int(local, ret); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (ret == 0) 7362306a36Sopenharmony_ci sdata->flags |= IEEE80211_SDATA_IN_DRIVER; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return ret; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciint drv_change_interface(struct ieee80211_local *local, 7962306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 8062306a36Sopenharmony_ci enum nl80211_iftype type, bool p2p) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int ret; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci might_sleep(); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 8762306a36Sopenharmony_ci return -EIO; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci trace_drv_change_interface(local, sdata, type, p2p); 9062306a36Sopenharmony_ci ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p); 9162306a36Sopenharmony_ci trace_drv_return_int(local, ret); 9262306a36Sopenharmony_ci return ret; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_civoid drv_remove_interface(struct ieee80211_local *local, 9662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci might_sleep(); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 10162306a36Sopenharmony_ci return; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci trace_drv_remove_interface(local, sdata); 10462306a36Sopenharmony_ci local->ops->remove_interface(&local->hw, &sdata->vif); 10562306a36Sopenharmony_ci sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER; 10662306a36Sopenharmony_ci trace_drv_return_void(local); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci__must_check 11062306a36Sopenharmony_ciint drv_sta_state(struct ieee80211_local *local, 11162306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 11262306a36Sopenharmony_ci struct sta_info *sta, 11362306a36Sopenharmony_ci enum ieee80211_sta_state old_state, 11462306a36Sopenharmony_ci enum ieee80211_sta_state new_state) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci int ret = 0; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci might_sleep(); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci sdata = get_bss_sdata(sdata); 12162306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 12262306a36Sopenharmony_ci return -EIO; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state); 12562306a36Sopenharmony_ci if (local->ops->sta_state) { 12662306a36Sopenharmony_ci ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta, 12762306a36Sopenharmony_ci old_state, new_state); 12862306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_AUTH && 12962306a36Sopenharmony_ci new_state == IEEE80211_STA_ASSOC) { 13062306a36Sopenharmony_ci ret = drv_sta_add(local, sdata, &sta->sta); 13162306a36Sopenharmony_ci if (ret == 0) { 13262306a36Sopenharmony_ci sta->uploaded = true; 13362306a36Sopenharmony_ci if (rcu_access_pointer(sta->sta.rates)) 13462306a36Sopenharmony_ci drv_sta_rate_tbl_update(local, sdata, &sta->sta); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_ASSOC && 13762306a36Sopenharmony_ci new_state == IEEE80211_STA_AUTH) { 13862306a36Sopenharmony_ci drv_sta_remove(local, sdata, &sta->sta); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci trace_drv_return_int(local, ret); 14162306a36Sopenharmony_ci return ret; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci__must_check 14562306a36Sopenharmony_ciint drv_sta_set_txpwr(struct ieee80211_local *local, 14662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 14762306a36Sopenharmony_ci struct sta_info *sta) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci might_sleep(); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci sdata = get_bss_sdata(sdata); 15462306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 15562306a36Sopenharmony_ci return -EIO; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci trace_drv_sta_set_txpwr(local, sdata, &sta->sta); 15862306a36Sopenharmony_ci if (local->ops->sta_set_txpwr) 15962306a36Sopenharmony_ci ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif, 16062306a36Sopenharmony_ci &sta->sta); 16162306a36Sopenharmony_ci trace_drv_return_int(local, ret); 16262306a36Sopenharmony_ci return ret; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_civoid drv_sta_rc_update(struct ieee80211_local *local, 16662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 16762306a36Sopenharmony_ci struct ieee80211_sta *sta, u32 changed) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci sdata = get_bss_sdata(sdata); 17062306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 17162306a36Sopenharmony_ci return; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && 17462306a36Sopenharmony_ci (sdata->vif.type != NL80211_IFTYPE_ADHOC && 17562306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_MESH_POINT)); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci trace_drv_sta_rc_update(local, sdata, sta, changed); 17862306a36Sopenharmony_ci if (local->ops->sta_rc_update) 17962306a36Sopenharmony_ci local->ops->sta_rc_update(&local->hw, &sdata->vif, 18062306a36Sopenharmony_ci sta, changed); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci trace_drv_return_void(local); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ciint drv_conf_tx(struct ieee80211_local *local, 18662306a36Sopenharmony_ci struct ieee80211_link_data *link, u16 ac, 18762306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata = link->sdata; 19062306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci might_sleep(); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 19562306a36Sopenharmony_ci return -EIO; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (sdata->vif.active_links && 19862306a36Sopenharmony_ci !(sdata->vif.active_links & BIT(link->link_id))) 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (params->cw_min == 0 || params->cw_min > params->cw_max) { 20262306a36Sopenharmony_ci /* 20362306a36Sopenharmony_ci * If we can't configure hardware anyway, don't warn. We may 20462306a36Sopenharmony_ci * never have initialized the CW parameters. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci WARN_ONCE(local->ops->conf_tx, 20762306a36Sopenharmony_ci "%s: invalid CW_min/CW_max: %d/%d\n", 20862306a36Sopenharmony_ci sdata->name, params->cw_min, params->cw_max); 20962306a36Sopenharmony_ci return -EINVAL; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci trace_drv_conf_tx(local, sdata, link->link_id, ac, params); 21362306a36Sopenharmony_ci if (local->ops->conf_tx) 21462306a36Sopenharmony_ci ret = local->ops->conf_tx(&local->hw, &sdata->vif, 21562306a36Sopenharmony_ci link->link_id, ac, params); 21662306a36Sopenharmony_ci trace_drv_return_int(local, ret); 21762306a36Sopenharmony_ci return ret; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciu64 drv_get_tsf(struct ieee80211_local *local, 22162306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci u64 ret = -1ULL; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci might_sleep(); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 22862306a36Sopenharmony_ci return ret; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci trace_drv_get_tsf(local, sdata); 23162306a36Sopenharmony_ci if (local->ops->get_tsf) 23262306a36Sopenharmony_ci ret = local->ops->get_tsf(&local->hw, &sdata->vif); 23362306a36Sopenharmony_ci trace_drv_return_u64(local, ret); 23462306a36Sopenharmony_ci return ret; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_civoid drv_set_tsf(struct ieee80211_local *local, 23862306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 23962306a36Sopenharmony_ci u64 tsf) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci might_sleep(); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 24462306a36Sopenharmony_ci return; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci trace_drv_set_tsf(local, sdata, tsf); 24762306a36Sopenharmony_ci if (local->ops->set_tsf) 24862306a36Sopenharmony_ci local->ops->set_tsf(&local->hw, &sdata->vif, tsf); 24962306a36Sopenharmony_ci trace_drv_return_void(local); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_civoid drv_offset_tsf(struct ieee80211_local *local, 25362306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 25462306a36Sopenharmony_ci s64 offset) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci might_sleep(); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 25962306a36Sopenharmony_ci return; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci trace_drv_offset_tsf(local, sdata, offset); 26262306a36Sopenharmony_ci if (local->ops->offset_tsf) 26362306a36Sopenharmony_ci local->ops->offset_tsf(&local->hw, &sdata->vif, offset); 26462306a36Sopenharmony_ci trace_drv_return_void(local); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_civoid drv_reset_tsf(struct ieee80211_local *local, 26862306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci might_sleep(); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 27362306a36Sopenharmony_ci return; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci trace_drv_reset_tsf(local, sdata); 27662306a36Sopenharmony_ci if (local->ops->reset_tsf) 27762306a36Sopenharmony_ci local->ops->reset_tsf(&local->hw, &sdata->vif); 27862306a36Sopenharmony_ci trace_drv_return_void(local); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ciint drv_assign_vif_chanctx(struct ieee80211_local *local, 28262306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 28362306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 28462306a36Sopenharmony_ci struct ieee80211_chanctx *ctx) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int ret = 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci drv_verify_link_exists(sdata, link_conf); 28962306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 29062306a36Sopenharmony_ci return -EIO; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (sdata->vif.active_links && 29362306a36Sopenharmony_ci !(sdata->vif.active_links & BIT(link_conf->link_id))) 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci trace_drv_assign_vif_chanctx(local, sdata, link_conf, ctx); 29762306a36Sopenharmony_ci if (local->ops->assign_vif_chanctx) { 29862306a36Sopenharmony_ci WARN_ON_ONCE(!ctx->driver_present); 29962306a36Sopenharmony_ci ret = local->ops->assign_vif_chanctx(&local->hw, 30062306a36Sopenharmony_ci &sdata->vif, 30162306a36Sopenharmony_ci link_conf, 30262306a36Sopenharmony_ci &ctx->conf); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci trace_drv_return_int(local, ret); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return ret; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_civoid drv_unassign_vif_chanctx(struct ieee80211_local *local, 31062306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 31162306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 31262306a36Sopenharmony_ci struct ieee80211_chanctx *ctx) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci might_sleep(); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci drv_verify_link_exists(sdata, link_conf); 31762306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 31862306a36Sopenharmony_ci return; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (sdata->vif.active_links && 32162306a36Sopenharmony_ci !(sdata->vif.active_links & BIT(link_conf->link_id))) 32262306a36Sopenharmony_ci return; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci trace_drv_unassign_vif_chanctx(local, sdata, link_conf, ctx); 32562306a36Sopenharmony_ci if (local->ops->unassign_vif_chanctx) { 32662306a36Sopenharmony_ci WARN_ON_ONCE(!ctx->driver_present); 32762306a36Sopenharmony_ci local->ops->unassign_vif_chanctx(&local->hw, 32862306a36Sopenharmony_ci &sdata->vif, 32962306a36Sopenharmony_ci link_conf, 33062306a36Sopenharmony_ci &ctx->conf); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci trace_drv_return_void(local); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ciint drv_switch_vif_chanctx(struct ieee80211_local *local, 33662306a36Sopenharmony_ci struct ieee80211_vif_chanctx_switch *vifs, 33762306a36Sopenharmony_ci int n_vifs, enum ieee80211_chanctx_switch_mode mode) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci int ret = 0; 34062306a36Sopenharmony_ci int i; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci might_sleep(); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (!local->ops->switch_vif_chanctx) 34562306a36Sopenharmony_ci return -EOPNOTSUPP; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci for (i = 0; i < n_vifs; i++) { 34862306a36Sopenharmony_ci struct ieee80211_chanctx *new_ctx = 34962306a36Sopenharmony_ci container_of(vifs[i].new_ctx, 35062306a36Sopenharmony_ci struct ieee80211_chanctx, 35162306a36Sopenharmony_ci conf); 35262306a36Sopenharmony_ci struct ieee80211_chanctx *old_ctx = 35362306a36Sopenharmony_ci container_of(vifs[i].old_ctx, 35462306a36Sopenharmony_ci struct ieee80211_chanctx, 35562306a36Sopenharmony_ci conf); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci WARN_ON_ONCE(!old_ctx->driver_present); 35862306a36Sopenharmony_ci WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS && 35962306a36Sopenharmony_ci new_ctx->driver_present) || 36062306a36Sopenharmony_ci (mode == CHANCTX_SWMODE_REASSIGN_VIF && 36162306a36Sopenharmony_ci !new_ctx->driver_present)); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode); 36562306a36Sopenharmony_ci ret = local->ops->switch_vif_chanctx(&local->hw, 36662306a36Sopenharmony_ci vifs, n_vifs, mode); 36762306a36Sopenharmony_ci trace_drv_return_int(local, ret); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) { 37062306a36Sopenharmony_ci for (i = 0; i < n_vifs; i++) { 37162306a36Sopenharmony_ci struct ieee80211_chanctx *new_ctx = 37262306a36Sopenharmony_ci container_of(vifs[i].new_ctx, 37362306a36Sopenharmony_ci struct ieee80211_chanctx, 37462306a36Sopenharmony_ci conf); 37562306a36Sopenharmony_ci struct ieee80211_chanctx *old_ctx = 37662306a36Sopenharmony_ci container_of(vifs[i].old_ctx, 37762306a36Sopenharmony_ci struct ieee80211_chanctx, 37862306a36Sopenharmony_ci conf); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci new_ctx->driver_present = true; 38162306a36Sopenharmony_ci old_ctx->driver_present = false; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return ret; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ciint drv_ampdu_action(struct ieee80211_local *local, 38962306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 39062306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci might_sleep(); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (!sdata) 39762306a36Sopenharmony_ci return -EIO; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci sdata = get_bss_sdata(sdata); 40062306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 40162306a36Sopenharmony_ci return -EIO; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci trace_drv_ampdu_action(local, sdata, params); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (local->ops->ampdu_action) 40662306a36Sopenharmony_ci ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci trace_drv_return_int(local, ret); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_civoid drv_link_info_changed(struct ieee80211_local *local, 41462306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 41562306a36Sopenharmony_ci struct ieee80211_bss_conf *info, 41662306a36Sopenharmony_ci int link_id, u64 changed) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci might_sleep(); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | 42162306a36Sopenharmony_ci BSS_CHANGED_BEACON_ENABLED) && 42262306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_AP && 42362306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_ADHOC && 42462306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_MESH_POINT && 42562306a36Sopenharmony_ci sdata->vif.type != NL80211_IFTYPE_OCB)) 42662306a36Sopenharmony_ci return; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || 42962306a36Sopenharmony_ci sdata->vif.type == NL80211_IFTYPE_NAN || 43062306a36Sopenharmony_ci (sdata->vif.type == NL80211_IFTYPE_MONITOR && 43162306a36Sopenharmony_ci !sdata->vif.bss_conf.mu_mimo_owner && 43262306a36Sopenharmony_ci !(changed & BSS_CHANGED_TXPOWER)))) 43362306a36Sopenharmony_ci return; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 43662306a36Sopenharmony_ci return; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (sdata->vif.active_links && 43962306a36Sopenharmony_ci !(sdata->vif.active_links & BIT(link_id))) 44062306a36Sopenharmony_ci return; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci trace_drv_link_info_changed(local, sdata, info, changed); 44362306a36Sopenharmony_ci if (local->ops->link_info_changed) 44462306a36Sopenharmony_ci local->ops->link_info_changed(&local->hw, &sdata->vif, 44562306a36Sopenharmony_ci info, changed); 44662306a36Sopenharmony_ci else if (local->ops->bss_info_changed) 44762306a36Sopenharmony_ci local->ops->bss_info_changed(&local->hw, &sdata->vif, 44862306a36Sopenharmony_ci info, changed); 44962306a36Sopenharmony_ci trace_drv_return_void(local); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ciint drv_set_key(struct ieee80211_local *local, 45362306a36Sopenharmony_ci enum set_key_cmd cmd, 45462306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 45562306a36Sopenharmony_ci struct ieee80211_sta *sta, 45662306a36Sopenharmony_ci struct ieee80211_key_conf *key) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci int ret; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci might_sleep(); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci sdata = get_bss_sdata(sdata); 46362306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 46462306a36Sopenharmony_ci return -EIO; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (WARN_ON(key->link_id >= 0 && sdata->vif.active_links && 46762306a36Sopenharmony_ci !(sdata->vif.active_links & BIT(key->link_id)))) 46862306a36Sopenharmony_ci return -ENOLINK; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci trace_drv_set_key(local, cmd, sdata, sta, key); 47162306a36Sopenharmony_ci ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); 47262306a36Sopenharmony_ci trace_drv_return_int(local, ret); 47362306a36Sopenharmony_ci return ret; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ciint drv_change_vif_links(struct ieee80211_local *local, 47762306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 47862306a36Sopenharmony_ci u16 old_links, u16 new_links, 47962306a36Sopenharmony_ci struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct ieee80211_link_data *link; 48262306a36Sopenharmony_ci unsigned long links_to_add; 48362306a36Sopenharmony_ci unsigned long links_to_rem; 48462306a36Sopenharmony_ci unsigned int link_id; 48562306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci might_sleep(); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 49062306a36Sopenharmony_ci return -EIO; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (old_links == new_links) 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci links_to_add = ~old_links & new_links; 49662306a36Sopenharmony_ci links_to_rem = old_links & ~new_links; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) { 49962306a36Sopenharmony_ci link = rcu_access_pointer(sdata->link[link_id]); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci ieee80211_link_debugfs_drv_remove(link); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci trace_drv_change_vif_links(local, sdata, old_links, new_links); 50562306a36Sopenharmony_ci if (local->ops->change_vif_links) 50662306a36Sopenharmony_ci ret = local->ops->change_vif_links(&local->hw, &sdata->vif, 50762306a36Sopenharmony_ci old_links, new_links, old); 50862306a36Sopenharmony_ci trace_drv_return_int(local, ret); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (ret) 51162306a36Sopenharmony_ci return ret; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (!local->in_reconfig) { 51462306a36Sopenharmony_ci for_each_set_bit(link_id, &links_to_add, 51562306a36Sopenharmony_ci IEEE80211_MLD_MAX_NUM_LINKS) { 51662306a36Sopenharmony_ci link = rcu_access_pointer(sdata->link[link_id]); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci ieee80211_link_debugfs_drv_add(link); 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ciint drv_change_sta_links(struct ieee80211_local *local, 52662306a36Sopenharmony_ci struct ieee80211_sub_if_data *sdata, 52762306a36Sopenharmony_ci struct ieee80211_sta *sta, 52862306a36Sopenharmony_ci u16 old_links, u16 new_links) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct sta_info *info = container_of(sta, struct sta_info, sta); 53162306a36Sopenharmony_ci struct link_sta_info *link_sta; 53262306a36Sopenharmony_ci unsigned long links_to_add; 53362306a36Sopenharmony_ci unsigned long links_to_rem; 53462306a36Sopenharmony_ci unsigned int link_id; 53562306a36Sopenharmony_ci int ret = -EOPNOTSUPP; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci might_sleep(); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (!check_sdata_in_driver(sdata)) 54062306a36Sopenharmony_ci return -EIO; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci old_links &= sdata->vif.active_links; 54362306a36Sopenharmony_ci new_links &= sdata->vif.active_links; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (old_links == new_links) 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci links_to_add = ~old_links & new_links; 54962306a36Sopenharmony_ci links_to_rem = old_links & ~new_links; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) { 55262306a36Sopenharmony_ci link_sta = rcu_dereference_protected(info->link[link_id], 55362306a36Sopenharmony_ci lockdep_is_held(&local->sta_mtx)); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci ieee80211_link_sta_debugfs_drv_remove(link_sta); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci trace_drv_change_sta_links(local, sdata, sta, old_links, new_links); 55962306a36Sopenharmony_ci if (local->ops->change_sta_links) 56062306a36Sopenharmony_ci ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta, 56162306a36Sopenharmony_ci old_links, new_links); 56262306a36Sopenharmony_ci trace_drv_return_int(local, ret); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (ret) 56562306a36Sopenharmony_ci return ret; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* during reconfig don't add it to debugfs again */ 56862306a36Sopenharmony_ci if (local->in_reconfig) 56962306a36Sopenharmony_ci return 0; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) { 57262306a36Sopenharmony_ci link_sta = rcu_dereference_protected(info->link[link_id], 57362306a36Sopenharmony_ci lockdep_is_held(&local->sta_mtx)); 57462306a36Sopenharmony_ci ieee80211_link_sta_debugfs_drv_add(link_sta); 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci} 579