Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /*
0003  * Copyright (C) 2012-2014, 2020 Intel Corporation
0004  * Copyright (C) 2016 Intel Deutschland GmbH
0005  */
0006 #include <net/mac80211.h>
0007 #include "fw-api.h"
0008 #include "mvm.h"
0009 
0010 struct iwl_mvm_iface_iterator_data {
0011     struct ieee80211_vif *ignore_vif;
0012     int idx;
0013 
0014     struct iwl_mvm_phy_ctxt *phyctxt;
0015 
0016     u16 ids[MAX_MACS_IN_BINDING];
0017     u16 colors[MAX_MACS_IN_BINDING];
0018 };
0019 
0020 static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action,
0021                    struct iwl_mvm_iface_iterator_data *data)
0022 {
0023     struct iwl_binding_cmd cmd;
0024     struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt;
0025     int i, ret;
0026     u32 status;
0027     int size;
0028 
0029     memset(&cmd, 0, sizeof(cmd));
0030 
0031     if (fw_has_capa(&mvm->fw->ucode_capa,
0032             IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) {
0033         size = sizeof(cmd);
0034         cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw,
0035                                   phyctxt->channel->band));
0036     } else {
0037         size = IWL_BINDING_CMD_SIZE_V1;
0038     }
0039 
0040     cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
0041                                phyctxt->color));
0042     cmd.action = cpu_to_le32(action);
0043     cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
0044                           phyctxt->color));
0045 
0046     for (i = 0; i < MAX_MACS_IN_BINDING; i++)
0047         cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
0048     for (i = 0; i < data->idx; i++)
0049         cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i],
0050                                   data->colors[i]));
0051 
0052     status = 0;
0053     ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
0054                       size, &cmd, &status);
0055     if (ret) {
0056         IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n",
0057             action, ret);
0058         return ret;
0059     }
0060 
0061     if (status) {
0062         IWL_ERR(mvm, "Binding command failed: %u\n", status);
0063         ret = -EIO;
0064     }
0065 
0066     return ret;
0067 }
0068 
0069 static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
0070                    struct ieee80211_vif *vif)
0071 {
0072     struct iwl_mvm_iface_iterator_data *data = _data;
0073     struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0074 
0075     if (vif == data->ignore_vif)
0076         return;
0077 
0078     if (mvmvif->phy_ctxt != data->phyctxt)
0079         return;
0080 
0081     if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING))
0082         return;
0083 
0084     data->ids[data->idx] = mvmvif->id;
0085     data->colors[data->idx] = mvmvif->color;
0086     data->idx++;
0087 }
0088 
0089 static int iwl_mvm_binding_update(struct iwl_mvm *mvm,
0090                   struct ieee80211_vif *vif,
0091                   struct iwl_mvm_phy_ctxt *phyctxt,
0092                   bool add)
0093 {
0094     struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0095     struct iwl_mvm_iface_iterator_data data = {
0096         .ignore_vif = vif,
0097         .phyctxt = phyctxt,
0098     };
0099     u32 action = FW_CTXT_ACTION_MODIFY;
0100 
0101     lockdep_assert_held(&mvm->mutex);
0102 
0103     ieee80211_iterate_active_interfaces_atomic(mvm->hw,
0104                            IEEE80211_IFACE_ITER_NORMAL,
0105                            iwl_mvm_iface_iterator,
0106                            &data);
0107 
0108     /*
0109      * If there are no other interfaces yet we
0110      * need to create a new binding.
0111      */
0112     if (data.idx == 0) {
0113         if (add)
0114             action = FW_CTXT_ACTION_ADD;
0115         else
0116             action = FW_CTXT_ACTION_REMOVE;
0117     }
0118 
0119     if (add) {
0120         if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING))
0121             return -EINVAL;
0122 
0123         data.ids[data.idx] = mvmvif->id;
0124         data.colors[data.idx] = mvmvif->color;
0125         data.idx++;
0126     }
0127 
0128     return iwl_mvm_binding_cmd(mvm, action, &data);
0129 }
0130 
0131 int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
0132 {
0133     struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0134 
0135     if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
0136         return -EINVAL;
0137 
0138     /*
0139      * Update SF - Disable if needed. if this fails, SF might still be on
0140      * while many macs are bound, which is forbidden - so fail the binding.
0141      */
0142     if (iwl_mvm_sf_update(mvm, vif, false))
0143         return -EINVAL;
0144 
0145     return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
0146 }
0147 
0148 int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
0149 {
0150     struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
0151     int ret;
0152 
0153     if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
0154         return -EINVAL;
0155 
0156     ret = iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
0157 
0158     if (!ret)
0159         if (iwl_mvm_sf_update(mvm, vif, true))
0160             IWL_ERR(mvm, "Failed to update SF state\n");
0161 
0162     return ret;
0163 }