linux/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.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) 2017        Intel Deutschland GmbH
   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 * The full GNU General Public License is included in this distribution
  20 * in the file called COPYING.
  21 *
  22 * Contact Information:
  23 *  Intel Linux Wireless <linuxwifi@intel.com>
  24 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  25 *
  26 * BSD LICENSE
  27 *
  28 * Copyright(c) 2017        Intel Deutschland GmbH
  29 * All rights reserved.
  30 *
  31 * Redistribution and use in source and binary forms, with or without
  32 * modification, are permitted provided that the following conditions
  33 * are met:
  34 *
  35 *  * Redistributions of source code must retain the above copyright
  36 *    notice, this list of conditions and the following disclaimer.
  37 *  * Redistributions in binary form must reproduce the above copyright
  38 *    notice, this list of conditions and the following disclaimer in
  39 *    the documentation and/or other materials provided with the
  40 *    distribution.
  41 *  * Neither the name Intel Corporation nor the names of its
  42 *    contributors may be used to endorse or promote products derived
  43 *    from this software without specific prior written permission.
  44 *
  45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  49 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  51 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  55 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  56 *
  57 *****************************************************************************/
  58#include "rs.h"
  59#include "fw-api.h"
  60#include "sta.h"
  61#include "iwl-op-mode.h"
  62#include "mvm.h"
  63
  64static u8 rs_fw_bw_from_sta_bw(struct ieee80211_sta *sta)
  65{
  66        switch (sta->bandwidth) {
  67        case IEEE80211_STA_RX_BW_160:
  68                return IWL_TLC_MNG_MAX_CH_WIDTH_160MHZ;
  69        case IEEE80211_STA_RX_BW_80:
  70                return IWL_TLC_MNG_MAX_CH_WIDTH_80MHZ;
  71        case IEEE80211_STA_RX_BW_40:
  72                return IWL_TLC_MNG_MAX_CH_WIDTH_40MHZ;
  73        case IEEE80211_STA_RX_BW_20:
  74        default:
  75                return IWL_TLC_MNG_MAX_CH_WIDTH_20MHZ;
  76        }
  77}
  78
  79static u8 rs_fw_set_active_chains(u8 chains)
  80{
  81        u8 fw_chains = 0;
  82
  83        if (chains & ANT_A)
  84                fw_chains |= IWL_TLC_MNG_CHAIN_A_MSK;
  85        if (chains & ANT_B)
  86                fw_chains |= IWL_TLC_MNG_CHAIN_B_MSK;
  87        if (chains & ANT_C)
  88                fw_chains |= IWL_TLC_MNG_CHAIN_C_MSK;
  89
  90        return fw_chains;
  91}
  92
  93static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
  94{
  95        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
  96        struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
  97        u8 supp = 0;
  98
  99        if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
 100                supp |= IWL_TLC_MNG_SGI_20MHZ_MSK;
 101        if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40)
 102                supp |= IWL_TLC_MNG_SGI_40MHZ_MSK;
 103        if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80)
 104                supp |= IWL_TLC_MNG_SGI_80MHZ_MSK;
 105        if (vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_160)
 106                supp |= IWL_TLC_MNG_SGI_160MHZ_MSK;
 107
 108        return supp;
 109}
 110
 111static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm,
 112                                  struct ieee80211_sta *sta)
 113{
 114        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 115        struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
 116        bool vht_ena = vht_cap && vht_cap->vht_supported;
 117        u16 flags = IWL_TLC_MNG_CFG_FLAGS_CCK_MSK |
 118                    IWL_TLC_MNG_CFG_FLAGS_DCM_MSK |
 119                    IWL_TLC_MNG_CFG_FLAGS_DD_MSK;
 120
 121        if (mvm->cfg->ht_params->stbc &&
 122            (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
 123            ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) ||
 124             (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))))
 125                flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK;
 126
 127        if (mvm->cfg->ht_params->ldpc &&
 128            ((ht_cap && (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)) ||
 129             (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
 130                flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
 131
 132        if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
 133            (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
 134            (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE))
 135                flags |= IWL_TLC_MNG_CFG_FLAGS_BF_MSK;
 136
 137        return flags;
 138}
 139
 140static
 141int rs_fw_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap,
 142                                   int nss)
 143{
 144        u16 rx_mcs = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) &
 145                (0x3 << (2 * (nss - 1)));
 146        rx_mcs >>= (2 * (nss - 1));
 147
 148        switch (rx_mcs) {
 149        case IEEE80211_VHT_MCS_SUPPORT_0_7:
 150                return IWL_TLC_MNG_HT_RATE_MCS7;
 151        case IEEE80211_VHT_MCS_SUPPORT_0_8:
 152                return IWL_TLC_MNG_HT_RATE_MCS8;
 153        case IEEE80211_VHT_MCS_SUPPORT_0_9:
 154                return IWL_TLC_MNG_HT_RATE_MCS9;
 155        default:
 156                WARN_ON_ONCE(1);
 157                break;
 158        }
 159
 160        return 0;
 161}
 162
 163static void rs_fw_vht_set_enabled_rates(struct ieee80211_sta *sta,
 164                                        struct ieee80211_sta_vht_cap *vht_cap,
 165                                        struct iwl_tlc_config_cmd *cmd)
 166{
 167        u16 supp;
 168        int i, highest_mcs;
 169
 170        for (i = 0; i < sta->rx_nss; i++) {
 171                if (i == MAX_RS_ANT_NUM)
 172                        break;
 173
 174                highest_mcs = rs_fw_vht_highest_rx_mcs_index(vht_cap, i + 1);
 175                if (!highest_mcs)
 176                        continue;
 177
 178                supp = BIT(highest_mcs + 1) - 1;
 179                if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
 180                        supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9);
 181
 182                cmd->ht_supp_rates[i] = cpu_to_le16(supp);
 183        }
 184}
 185
 186static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
 187                                 struct ieee80211_supported_band *sband,
 188                                 struct iwl_tlc_config_cmd *cmd)
 189{
 190        int i;
 191        unsigned long tmp;
 192        unsigned long supp; /* must be unsigned long for for_each_set_bit */
 193        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
 194        struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
 195
 196        /* non HT rates */
 197        supp = 0;
 198        tmp = sta->supp_rates[sband->band];
 199        for_each_set_bit(i, &tmp, BITS_PER_LONG)
 200                supp |= BIT(sband->bitrates[i].hw_value);
 201
 202        cmd->non_ht_supp_rates = cpu_to_le16(supp);
 203        cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
 204
 205        /* HT/VHT rates */
 206        if (vht_cap && vht_cap->vht_supported) {
 207                cmd->mode = IWL_TLC_MNG_MODE_VHT;
 208                rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd);
 209        } else if (ht_cap && ht_cap->ht_supported) {
 210                cmd->mode = IWL_TLC_MNG_MODE_HT;
 211                cmd->ht_supp_rates[0] = cpu_to_le16(ht_cap->mcs.rx_mask[0]);
 212                cmd->ht_supp_rates[1] = cpu_to_le16(ht_cap->mcs.rx_mask[1]);
 213        }
 214}
 215
 216static void rs_fw_tlc_mng_notif_req_config(struct iwl_mvm *mvm, u8 sta_id)
 217{
 218        u32 cmd_id = iwl_cmd_id(TLC_MNG_NOTIF_REQ_CMD, DATA_PATH_GROUP, 0);
 219        struct iwl_tlc_notif_req_config_cmd cfg_cmd = {
 220                .sta_id = sta_id,
 221                .flags = cpu_to_le16(IWL_TLC_NOTIF_INIT_RATE_MSK),
 222                .interval = cpu_to_le16(IWL_TLC_NOTIF_REQ_INTERVAL),
 223        };
 224        int ret;
 225
 226        ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd);
 227        if (ret)
 228                IWL_ERR(mvm, "Failed to send TLC notif request (%d)\n", ret);
 229}
 230
 231void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
 232{
 233        struct iwl_tlc_update_notif *notif;
 234        struct iwl_mvm_sta *mvmsta;
 235        struct iwl_lq_sta_rs_fw *lq_sta;
 236
 237        rcu_read_lock();
 238
 239        notif = (void *)pkt->data;
 240        mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, notif->sta_id);
 241
 242        if (!mvmsta) {
 243                IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n",
 244                        notif->sta_id);
 245                goto out;
 246        }
 247
 248        lq_sta = &mvmsta->lq_sta.rs_fw;
 249
 250        if (le16_to_cpu(notif->flags) & IWL_TLC_NOTIF_INIT_RATE_MSK) {
 251                lq_sta->last_rate_n_flags =
 252                        le32_to_cpu(notif->values[IWL_TLC_NOTIF_INIT_RATE_POS]);
 253                IWL_DEBUG_RATE(mvm, "new rate_n_flags: 0x%X\n",
 254                               lq_sta->last_rate_n_flags);
 255        }
 256out:
 257        rcu_read_unlock();
 258}
 259
 260void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 261                     enum nl80211_band band)
 262{
 263        struct ieee80211_hw *hw = mvm->hw;
 264        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
 265        struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
 266        u32 cmd_id = iwl_cmd_id(TLC_MNG_CONFIG_CMD, DATA_PATH_GROUP, 0);
 267        struct ieee80211_supported_band *sband;
 268        struct iwl_tlc_config_cmd cfg_cmd = {
 269                .sta_id = mvmsta->sta_id,
 270                .max_supp_ch_width = rs_fw_bw_from_sta_bw(sta),
 271                .flags = cpu_to_le16(rs_fw_set_config_flags(mvm, sta)),
 272                .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
 273                .max_supp_ss = sta->rx_nss,
 274                .max_ampdu_cnt = cpu_to_le32(mvmsta->max_agg_bufsize),
 275                .sgi_ch_width_supp = rs_fw_sgi_cw_support(sta),
 276        };
 277        int ret;
 278
 279        memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
 280
 281#ifdef CONFIG_IWLWIFI_DEBUGFS
 282        iwl_mvm_reset_frame_stats(mvm);
 283#endif
 284        sband = hw->wiphy->bands[band];
 285        rs_fw_set_supp_rates(sta, sband, &cfg_cmd);
 286
 287        ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd);
 288        if (ret)
 289                IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret);
 290
 291        rs_fw_tlc_mng_notif_req_config(mvm, cfg_cmd.sta_id);
 292}
 293
 294int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
 295                        bool enable)
 296{
 297        /* TODO: need to introduce a new FW cmd since LQ cmd is not relevant */
 298        IWL_DEBUG_RATE(mvm, "tx protection - not implemented yet.\n");
 299        return 0;
 300}
 301
 302void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta)
 303{
 304        struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw;
 305
 306        IWL_DEBUG_RATE(mvm, "create station rate scale window\n");
 307
 308        lq_sta->pers.drv = mvm;
 309        lq_sta->pers.sta_id = mvmsta->sta_id;
 310        lq_sta->pers.chains = 0;
 311        memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal));
 312        lq_sta->pers.last_rssi = S8_MIN;
 313        lq_sta->last_rate_n_flags = 0;
 314
 315#ifdef CONFIG_MAC80211_DEBUGFS
 316        lq_sta->pers.dbg_fixed_rate = 0;
 317#endif
 318}
 319