linux/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * This file is provided under a dual BSD/GPLv2 license.  When using or
   4 * redistributing this file, you may do so under either license.
   5 *
   6 * GPL LICENSE SUMMARY
   7 *
   8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
   9 * Copyright(c) 2016 Intel Deutschland GmbH
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of version 2 of the GNU General Public License as
  13 * published by the Free Software Foundation.
  14 *
  15 * This program is distributed in the hope that it will be useful, but
  16 * WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  23 * USA
  24 *
  25 * The full GNU General Public License is included in this distribution
  26 * in the file called COPYING.
  27 *
  28 * Contact Information:
  29 *  Intel Linux Wireless <linuxwifi@intel.com>
  30 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  31 *
  32 * BSD LICENSE
  33 *
  34 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  35 * Copyright(c) 2016 Intel Deutschland GmbH
  36 * All rights reserved.
  37 *
  38 * Redistribution and use in source and binary forms, with or without
  39 * modification, are permitted provided that the following conditions
  40 * are met:
  41 *
  42 *  * Redistributions of source code must retain the above copyright
  43 *    notice, this list of conditions and the following disclaimer.
  44 *  * Redistributions in binary form must reproduce the above copyright
  45 *    notice, this list of conditions and the following disclaimer in
  46 *    the documentation and/or other materials provided with the
  47 *    distribution.
  48 *  * Neither the name Intel Corporation nor the names of its
  49 *    contributors may be used to endorse or promote products derived
  50 *    from this software without specific prior written permission.
  51 *
  52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  53 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  54 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  55 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  56 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  57 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  58 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  59 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  62 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  63 *
  64 *****************************************************************************/
  65
  66#include <net/mac80211.h>
  67#include "fw-api.h"
  68#include "mvm.h"
  69
  70struct iwl_mvm_iface_iterator_data {
  71        struct ieee80211_vif *ignore_vif;
  72        int idx;
  73
  74        struct iwl_mvm_phy_ctxt *phyctxt;
  75
  76        u16 ids[MAX_MACS_IN_BINDING];
  77        u16 colors[MAX_MACS_IN_BINDING];
  78};
  79
  80static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action,
  81                               struct iwl_mvm_iface_iterator_data *data)
  82{
  83        struct iwl_binding_cmd cmd;
  84        struct iwl_mvm_phy_ctxt *phyctxt = data->phyctxt;
  85        int i, ret;
  86        u32 status;
  87        int size;
  88
  89        memset(&cmd, 0, sizeof(cmd));
  90
  91        if (fw_has_capa(&mvm->fw->ucode_capa,
  92                        IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) {
  93                size = sizeof(cmd);
  94                if (phyctxt->channel->band == NL80211_BAND_2GHZ ||
  95                    !iwl_mvm_is_cdb_supported(mvm))
  96                        cmd.lmac_id = cpu_to_le32(IWL_LMAC_24G_INDEX);
  97                else
  98                        cmd.lmac_id = cpu_to_le32(IWL_LMAC_5G_INDEX);
  99        } else {
 100                size = IWL_BINDING_CMD_SIZE_V1;
 101        }
 102
 103        cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
 104                                                           phyctxt->color));
 105        cmd.action = cpu_to_le32(action);
 106        cmd.phy = cpu_to_le32(FW_CMD_ID_AND_COLOR(phyctxt->id,
 107                                                  phyctxt->color));
 108
 109        for (i = 0; i < MAX_MACS_IN_BINDING; i++)
 110                cmd.macs[i] = cpu_to_le32(FW_CTXT_INVALID);
 111        for (i = 0; i < data->idx; i++)
 112                cmd.macs[i] = cpu_to_le32(FW_CMD_ID_AND_COLOR(data->ids[i],
 113                                                              data->colors[i]));
 114
 115        status = 0;
 116        ret = iwl_mvm_send_cmd_pdu_status(mvm, BINDING_CONTEXT_CMD,
 117                                          size, &cmd, &status);
 118        if (ret) {
 119                IWL_ERR(mvm, "Failed to send binding (action:%d): %d\n",
 120                        action, ret);
 121                return ret;
 122        }
 123
 124        if (status) {
 125                IWL_ERR(mvm, "Binding command failed: %u\n", status);
 126                ret = -EIO;
 127        }
 128
 129        return ret;
 130}
 131
 132static void iwl_mvm_iface_iterator(void *_data, u8 *mac,
 133                                   struct ieee80211_vif *vif)
 134{
 135        struct iwl_mvm_iface_iterator_data *data = _data;
 136        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 137
 138        if (vif == data->ignore_vif)
 139                return;
 140
 141        if (mvmvif->phy_ctxt != data->phyctxt)
 142                return;
 143
 144        if (WARN_ON_ONCE(data->idx >= MAX_MACS_IN_BINDING))
 145                return;
 146
 147        data->ids[data->idx] = mvmvif->id;
 148        data->colors[data->idx] = mvmvif->color;
 149        data->idx++;
 150}
 151
 152static int iwl_mvm_binding_update(struct iwl_mvm *mvm,
 153                                  struct ieee80211_vif *vif,
 154                                  struct iwl_mvm_phy_ctxt *phyctxt,
 155                                  bool add)
 156{
 157        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 158        struct iwl_mvm_iface_iterator_data data = {
 159                .ignore_vif = vif,
 160                .phyctxt = phyctxt,
 161        };
 162        u32 action = FW_CTXT_ACTION_MODIFY;
 163
 164        lockdep_assert_held(&mvm->mutex);
 165
 166        ieee80211_iterate_active_interfaces_atomic(mvm->hw,
 167                                                   IEEE80211_IFACE_ITER_NORMAL,
 168                                                   iwl_mvm_iface_iterator,
 169                                                   &data);
 170
 171        /*
 172         * If there are no other interfaces yet we
 173         * need to create a new binding.
 174         */
 175        if (data.idx == 0) {
 176                if (add)
 177                        action = FW_CTXT_ACTION_ADD;
 178                else
 179                        action = FW_CTXT_ACTION_REMOVE;
 180        }
 181
 182        if (add) {
 183                if (WARN_ON_ONCE(data.idx >= MAX_MACS_IN_BINDING))
 184                        return -EINVAL;
 185
 186                data.ids[data.idx] = mvmvif->id;
 187                data.colors[data.idx] = mvmvif->color;
 188                data.idx++;
 189        }
 190
 191        return iwl_mvm_binding_cmd(mvm, action, &data);
 192}
 193
 194int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 195{
 196        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 197
 198        if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
 199                return -EINVAL;
 200
 201        /*
 202         * Update SF - Disable if needed. if this fails, SF might still be on
 203         * while many macs are bound, which is forbidden - so fail the binding.
 204         */
 205        if (iwl_mvm_sf_update(mvm, vif, false))
 206                return -EINVAL;
 207
 208        return iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, true);
 209}
 210
 211int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 212{
 213        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 214        int ret;
 215
 216        if (WARN_ON_ONCE(!mvmvif->phy_ctxt))
 217                return -EINVAL;
 218
 219        ret = iwl_mvm_binding_update(mvm, vif, mvmvif->phy_ctxt, false);
 220
 221        if (!ret)
 222                if (iwl_mvm_sf_update(mvm, vif, true))
 223                        IWL_ERR(mvm, "Failed to update SF state\n");
 224
 225        return ret;
 226}
 227