linux/drivers/net/wireless/iwlwifi/mvm/quota.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 - 2013 Intel Corporation. All rights reserved.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of version 2 of the GNU General Public License as
  12 * published by the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but
  15 * WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  22 * USA
  23 *
  24 * The full GNU General Public License is included in this distribution
  25 * in the file called COPYING.
  26 *
  27 * Contact Information:
  28 *  Intel Linux Wireless <ilw@linux.intel.com>
  29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  30 *
  31 * BSD LICENSE
  32 *
  33 * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
  34 * All rights reserved.
  35 *
  36 * Redistribution and use in source and binary forms, with or without
  37 * modification, are permitted provided that the following conditions
  38 * are met:
  39 *
  40 *  * Redistributions of source code must retain the above copyright
  41 *    notice, this list of conditions and the following disclaimer.
  42 *  * Redistributions in binary form must reproduce the above copyright
  43 *    notice, this list of conditions and the following disclaimer in
  44 *    the documentation and/or other materials provided with the
  45 *    distribution.
  46 *  * Neither the name Intel Corporation nor the names of its
  47 *    contributors may be used to endorse or promote products derived
  48 *    from this software without specific prior written permission.
  49 *
  50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61 *
  62 *****************************************************************************/
  63
  64#include <net/mac80211.h>
  65#include "fw-api.h"
  66#include "mvm.h"
  67
  68struct iwl_mvm_quota_iterator_data {
  69        int n_interfaces[MAX_BINDINGS];
  70        int colors[MAX_BINDINGS];
  71        struct ieee80211_vif *new_vif;
  72};
  73
  74static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
  75                                   struct ieee80211_vif *vif)
  76{
  77        struct iwl_mvm_quota_iterator_data *data = _data;
  78        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
  79        u16 id;
  80
  81        /*
  82         * We'll account for the new interface (if any) below,
  83         * skip it here in case we're not called from within
  84         * the add_interface callback (otherwise it won't show
  85         * up in iteration)
  86         */
  87        if (vif == data->new_vif)
  88                return;
  89
  90        if (!mvmvif->phy_ctxt)
  91                return;
  92
  93        /* currently, PHY ID == binding ID */
  94        id = mvmvif->phy_ctxt->id;
  95
  96        /* need at least one binding per PHY */
  97        BUILD_BUG_ON(NUM_PHY_CTX > MAX_BINDINGS);
  98
  99        if (WARN_ON_ONCE(id >= MAX_BINDINGS))
 100                return;
 101
 102        if (data->colors[id] < 0)
 103                data->colors[id] = mvmvif->phy_ctxt->color;
 104        else
 105                WARN_ON_ONCE(data->colors[id] != mvmvif->phy_ctxt->color);
 106
 107        switch (vif->type) {
 108        case NL80211_IFTYPE_STATION:
 109                if (vif->bss_conf.assoc)
 110                        data->n_interfaces[id]++;
 111                break;
 112        case NL80211_IFTYPE_AP:
 113                if (mvmvif->ap_active)
 114                        data->n_interfaces[id]++;
 115                break;
 116        case NL80211_IFTYPE_MONITOR:
 117                if (mvmvif->monitor_active)
 118                        data->n_interfaces[id]++;
 119                break;
 120        case NL80211_IFTYPE_P2P_DEVICE:
 121                break;
 122        case NL80211_IFTYPE_ADHOC:
 123                if (vif->bss_conf.ibss_joined)
 124                        data->n_interfaces[id]++;
 125                break;
 126        default:
 127                WARN_ON_ONCE(1);
 128                break;
 129        }
 130}
 131
 132int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
 133{
 134        struct iwl_time_quota_cmd cmd;
 135        int i, idx, ret, num_active_bindings, quota, quota_rem;
 136        struct iwl_mvm_quota_iterator_data data = {
 137                .n_interfaces = {},
 138                .colors = { -1, -1, -1, -1 },
 139                .new_vif = newvif,
 140        };
 141
 142        /* update all upon completion */
 143        if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
 144                return 0;
 145
 146        BUILD_BUG_ON(data.colors[MAX_BINDINGS - 1] != -1);
 147
 148        lockdep_assert_held(&mvm->mutex);
 149
 150        memset(&cmd, 0, sizeof(cmd));
 151
 152        ieee80211_iterate_active_interfaces_atomic(
 153                mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
 154                iwl_mvm_quota_iterator, &data);
 155        if (newvif) {
 156                data.new_vif = NULL;
 157                iwl_mvm_quota_iterator(&data, newvif->addr, newvif);
 158        }
 159
 160        /*
 161         * The FW's scheduling session consists of
 162         * IWL_MVM_MAX_QUOTA fragments. Divide these fragments
 163         * equally between all the bindings that require quota
 164         */
 165        num_active_bindings = 0;
 166        for (i = 0; i < MAX_BINDINGS; i++) {
 167                cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID);
 168                if (data.n_interfaces[i] > 0)
 169                        num_active_bindings++;
 170        }
 171
 172        quota = 0;
 173        quota_rem = 0;
 174        if (num_active_bindings) {
 175                quota = IWL_MVM_MAX_QUOTA / num_active_bindings;
 176                quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings;
 177        }
 178
 179        for (idx = 0, i = 0; i < MAX_BINDINGS; i++) {
 180                if (data.colors[i] < 0)
 181                        continue;
 182
 183                cmd.quotas[idx].id_and_color =
 184                        cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
 185
 186                if (data.n_interfaces[i] <= 0) {
 187                        cmd.quotas[idx].quota = cpu_to_le32(0);
 188                        cmd.quotas[idx].max_duration = cpu_to_le32(0);
 189                } else {
 190                        cmd.quotas[idx].quota = cpu_to_le32(quota);
 191                        cmd.quotas[idx].max_duration =
 192                                cpu_to_le32(IWL_MVM_MAX_QUOTA);
 193                }
 194                idx++;
 195        }
 196
 197        /* Give the remainder of the session to the first binding */
 198        le32_add_cpu(&cmd.quotas[0].quota, quota_rem);
 199
 200        ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
 201                                   sizeof(cmd), &cmd);
 202        if (ret)
 203                IWL_ERR(mvm, "Failed to send quota: %d\n", ret);
 204        return ret;
 205}
 206