Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2015 Intel Deutschland GmbH
0004  * Copyright (C) 2022 Intel Corporation
0005  */
0006 #include <net/mac80211.h>
0007 #include "ieee80211_i.h"
0008 #include "trace.h"
0009 #include "driver-ops.h"
0010 
0011 int drv_start(struct ieee80211_local *local)
0012 {
0013     int ret;
0014 
0015     might_sleep();
0016 
0017     if (WARN_ON(local->started))
0018         return -EALREADY;
0019 
0020     trace_drv_start(local);
0021     local->started = true;
0022     /* allow rx frames */
0023     smp_mb();
0024     ret = local->ops->start(&local->hw);
0025     trace_drv_return_int(local, ret);
0026 
0027     if (ret)
0028         local->started = false;
0029 
0030     return ret;
0031 }
0032 
0033 void drv_stop(struct ieee80211_local *local)
0034 {
0035     might_sleep();
0036 
0037     if (WARN_ON(!local->started))
0038         return;
0039 
0040     trace_drv_stop(local);
0041     local->ops->stop(&local->hw);
0042     trace_drv_return_void(local);
0043 
0044     /* sync away all work on the tasklet before clearing started */
0045     tasklet_disable(&local->tasklet);
0046     tasklet_enable(&local->tasklet);
0047 
0048     barrier();
0049 
0050     local->started = false;
0051 }
0052 
0053 int drv_add_interface(struct ieee80211_local *local,
0054               struct ieee80211_sub_if_data *sdata)
0055 {
0056     int ret;
0057 
0058     might_sleep();
0059 
0060     if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
0061             (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
0062              !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
0063              !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
0064         return -EINVAL;
0065 
0066     trace_drv_add_interface(local, sdata);
0067     ret = local->ops->add_interface(&local->hw, &sdata->vif);
0068     trace_drv_return_int(local, ret);
0069 
0070     if (ret == 0)
0071         sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
0072 
0073     return ret;
0074 }
0075 
0076 int drv_change_interface(struct ieee80211_local *local,
0077              struct ieee80211_sub_if_data *sdata,
0078              enum nl80211_iftype type, bool p2p)
0079 {
0080     int ret;
0081 
0082     might_sleep();
0083 
0084     if (!check_sdata_in_driver(sdata))
0085         return -EIO;
0086 
0087     trace_drv_change_interface(local, sdata, type, p2p);
0088     ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
0089     trace_drv_return_int(local, ret);
0090     return ret;
0091 }
0092 
0093 void drv_remove_interface(struct ieee80211_local *local,
0094               struct ieee80211_sub_if_data *sdata)
0095 {
0096     might_sleep();
0097 
0098     if (!check_sdata_in_driver(sdata))
0099         return;
0100 
0101     trace_drv_remove_interface(local, sdata);
0102     local->ops->remove_interface(&local->hw, &sdata->vif);
0103     sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
0104     trace_drv_return_void(local);
0105 }
0106 
0107 __must_check
0108 int drv_sta_state(struct ieee80211_local *local,
0109           struct ieee80211_sub_if_data *sdata,
0110           struct sta_info *sta,
0111           enum ieee80211_sta_state old_state,
0112           enum ieee80211_sta_state new_state)
0113 {
0114     int ret = 0;
0115 
0116     might_sleep();
0117 
0118     sdata = get_bss_sdata(sdata);
0119     if (!check_sdata_in_driver(sdata))
0120         return -EIO;
0121 
0122     trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
0123     if (local->ops->sta_state) {
0124         ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
0125                         old_state, new_state);
0126     } else if (old_state == IEEE80211_STA_AUTH &&
0127            new_state == IEEE80211_STA_ASSOC) {
0128         ret = drv_sta_add(local, sdata, &sta->sta);
0129         if (ret == 0) {
0130             sta->uploaded = true;
0131             if (rcu_access_pointer(sta->sta.rates))
0132                 drv_sta_rate_tbl_update(local, sdata, &sta->sta);
0133         }
0134     } else if (old_state == IEEE80211_STA_ASSOC &&
0135            new_state == IEEE80211_STA_AUTH) {
0136         drv_sta_remove(local, sdata, &sta->sta);
0137     }
0138     trace_drv_return_int(local, ret);
0139     return ret;
0140 }
0141 
0142 __must_check
0143 int drv_sta_set_txpwr(struct ieee80211_local *local,
0144               struct ieee80211_sub_if_data *sdata,
0145               struct sta_info *sta)
0146 {
0147     int ret = -EOPNOTSUPP;
0148 
0149     might_sleep();
0150 
0151     sdata = get_bss_sdata(sdata);
0152     if (!check_sdata_in_driver(sdata))
0153         return -EIO;
0154 
0155     trace_drv_sta_set_txpwr(local, sdata, &sta->sta);
0156     if (local->ops->sta_set_txpwr)
0157         ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif,
0158                         &sta->sta);
0159     trace_drv_return_int(local, ret);
0160     return ret;
0161 }
0162 
0163 void drv_sta_rc_update(struct ieee80211_local *local,
0164                struct ieee80211_sub_if_data *sdata,
0165                struct ieee80211_sta *sta, u32 changed)
0166 {
0167     sdata = get_bss_sdata(sdata);
0168     if (!check_sdata_in_driver(sdata))
0169         return;
0170 
0171     WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
0172         (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
0173          sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
0174 
0175     trace_drv_sta_rc_update(local, sdata, sta, changed);
0176     if (local->ops->sta_rc_update)
0177         local->ops->sta_rc_update(&local->hw, &sdata->vif,
0178                       sta, changed);
0179 
0180     trace_drv_return_void(local);
0181 }
0182 
0183 int drv_conf_tx(struct ieee80211_local *local,
0184         struct ieee80211_link_data *link, u16 ac,
0185         const struct ieee80211_tx_queue_params *params)
0186 {
0187     struct ieee80211_sub_if_data *sdata = link->sdata;
0188     int ret = -EOPNOTSUPP;
0189 
0190     might_sleep();
0191 
0192     if (!check_sdata_in_driver(sdata))
0193         return -EIO;
0194 
0195     if (params->cw_min == 0 || params->cw_min > params->cw_max) {
0196         /*
0197          * If we can't configure hardware anyway, don't warn. We may
0198          * never have initialized the CW parameters.
0199          */
0200         WARN_ONCE(local->ops->conf_tx,
0201               "%s: invalid CW_min/CW_max: %d/%d\n",
0202               sdata->name, params->cw_min, params->cw_max);
0203         return -EINVAL;
0204     }
0205 
0206     trace_drv_conf_tx(local, sdata, link->link_id, ac, params);
0207     if (local->ops->conf_tx)
0208         ret = local->ops->conf_tx(&local->hw, &sdata->vif,
0209                       link->link_id, ac, params);
0210     trace_drv_return_int(local, ret);
0211     return ret;
0212 }
0213 
0214 u64 drv_get_tsf(struct ieee80211_local *local,
0215         struct ieee80211_sub_if_data *sdata)
0216 {
0217     u64 ret = -1ULL;
0218 
0219     might_sleep();
0220 
0221     if (!check_sdata_in_driver(sdata))
0222         return ret;
0223 
0224     trace_drv_get_tsf(local, sdata);
0225     if (local->ops->get_tsf)
0226         ret = local->ops->get_tsf(&local->hw, &sdata->vif);
0227     trace_drv_return_u64(local, ret);
0228     return ret;
0229 }
0230 
0231 void drv_set_tsf(struct ieee80211_local *local,
0232          struct ieee80211_sub_if_data *sdata,
0233          u64 tsf)
0234 {
0235     might_sleep();
0236 
0237     if (!check_sdata_in_driver(sdata))
0238         return;
0239 
0240     trace_drv_set_tsf(local, sdata, tsf);
0241     if (local->ops->set_tsf)
0242         local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
0243     trace_drv_return_void(local);
0244 }
0245 
0246 void drv_offset_tsf(struct ieee80211_local *local,
0247             struct ieee80211_sub_if_data *sdata,
0248             s64 offset)
0249 {
0250     might_sleep();
0251 
0252     if (!check_sdata_in_driver(sdata))
0253         return;
0254 
0255     trace_drv_offset_tsf(local, sdata, offset);
0256     if (local->ops->offset_tsf)
0257         local->ops->offset_tsf(&local->hw, &sdata->vif, offset);
0258     trace_drv_return_void(local);
0259 }
0260 
0261 void drv_reset_tsf(struct ieee80211_local *local,
0262            struct ieee80211_sub_if_data *sdata)
0263 {
0264     might_sleep();
0265 
0266     if (!check_sdata_in_driver(sdata))
0267         return;
0268 
0269     trace_drv_reset_tsf(local, sdata);
0270     if (local->ops->reset_tsf)
0271         local->ops->reset_tsf(&local->hw, &sdata->vif);
0272     trace_drv_return_void(local);
0273 }
0274 
0275 int drv_switch_vif_chanctx(struct ieee80211_local *local,
0276                struct ieee80211_vif_chanctx_switch *vifs,
0277                int n_vifs, enum ieee80211_chanctx_switch_mode mode)
0278 {
0279     int ret = 0;
0280     int i;
0281 
0282     might_sleep();
0283 
0284     if (!local->ops->switch_vif_chanctx)
0285         return -EOPNOTSUPP;
0286 
0287     for (i = 0; i < n_vifs; i++) {
0288         struct ieee80211_chanctx *new_ctx =
0289             container_of(vifs[i].new_ctx,
0290                      struct ieee80211_chanctx,
0291                      conf);
0292         struct ieee80211_chanctx *old_ctx =
0293             container_of(vifs[i].old_ctx,
0294                      struct ieee80211_chanctx,
0295                      conf);
0296 
0297         WARN_ON_ONCE(!old_ctx->driver_present);
0298         WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
0299                   new_ctx->driver_present) ||
0300                  (mode == CHANCTX_SWMODE_REASSIGN_VIF &&
0301                   !new_ctx->driver_present));
0302     }
0303 
0304     trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
0305     ret = local->ops->switch_vif_chanctx(&local->hw,
0306                          vifs, n_vifs, mode);
0307     trace_drv_return_int(local, ret);
0308 
0309     if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
0310         for (i = 0; i < n_vifs; i++) {
0311             struct ieee80211_chanctx *new_ctx =
0312                 container_of(vifs[i].new_ctx,
0313                          struct ieee80211_chanctx,
0314                          conf);
0315             struct ieee80211_chanctx *old_ctx =
0316                 container_of(vifs[i].old_ctx,
0317                          struct ieee80211_chanctx,
0318                          conf);
0319 
0320             new_ctx->driver_present = true;
0321             old_ctx->driver_present = false;
0322         }
0323     }
0324 
0325     return ret;
0326 }
0327 
0328 int drv_ampdu_action(struct ieee80211_local *local,
0329              struct ieee80211_sub_if_data *sdata,
0330              struct ieee80211_ampdu_params *params)
0331 {
0332     int ret = -EOPNOTSUPP;
0333 
0334     might_sleep();
0335 
0336     sdata = get_bss_sdata(sdata);
0337     if (!check_sdata_in_driver(sdata))
0338         return -EIO;
0339 
0340     trace_drv_ampdu_action(local, sdata, params);
0341 
0342     if (local->ops->ampdu_action)
0343         ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params);
0344 
0345     trace_drv_return_int(local, ret);
0346 
0347     return ret;
0348 }