linux/drivers/net/wireless/iwlwifi/iwl-nvm-parse.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) 2008 - 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) 2005 - 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#include <linux/types.h>
  63#include <linux/slab.h>
  64#include <linux/export.h>
  65#include "iwl-drv.h"
  66#include "iwl-modparams.h"
  67#include "iwl-nvm-parse.h"
  68
  69/* NVM offsets (in words) definitions */
  70enum wkp_nvm_offsets {
  71        /* NVM HW-Section offset (in words) definitions */
  72        HW_ADDR = 0x15,
  73
  74/* NVM SW-Section offset (in words) definitions */
  75        NVM_SW_SECTION = 0x1C0,
  76        NVM_VERSION = 0,
  77        RADIO_CFG = 1,
  78        SKU = 2,
  79        N_HW_ADDRS = 3,
  80        NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
  81
  82/* NVM calibration section offset (in words) definitions */
  83        NVM_CALIB_SECTION = 0x2B8,
  84        XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
  85};
  86
  87/* SKU Capabilities (actual values from NVM definition) */
  88enum nvm_sku_bits {
  89        NVM_SKU_CAP_BAND_24GHZ  = BIT(0),
  90        NVM_SKU_CAP_BAND_52GHZ  = BIT(1),
  91        NVM_SKU_CAP_11N_ENABLE  = BIT(2),
  92        NVM_SKU_CAP_11AC_ENABLE = BIT(3),
  93};
  94
  95/* radio config bits (actual values from NVM definition) */
  96#define NVM_RF_CFG_DASH_MSK(x)   (x & 0x3)         /* bits 0-1   */
  97#define NVM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
  98#define NVM_RF_CFG_TYPE_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
  99#define NVM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
 100#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
 101#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
 102
 103/*
 104 * These are the channel numbers in the order that they are stored in the NVM
 105 */
 106static const u8 iwl_nvm_channels[] = {
 107        /* 2.4 GHz */
 108        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
 109        /* 5 GHz */
 110        36, 40, 44 , 48, 52, 56, 60, 64,
 111        100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
 112        149, 153, 157, 161, 165
 113};
 114
 115#define IWL_NUM_CHANNELS        ARRAY_SIZE(iwl_nvm_channels)
 116#define NUM_2GHZ_CHANNELS       14
 117#define FIRST_2GHZ_HT_MINUS     5
 118#define LAST_2GHZ_HT_PLUS       9
 119#define LAST_5GHZ_HT            161
 120
 121
 122/* rate data (static) */
 123static struct ieee80211_rate iwl_cfg80211_rates[] = {
 124        { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
 125        { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
 126          .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
 127        { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
 128          .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
 129        { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
 130          .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
 131        { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
 132        { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
 133        { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
 134        { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
 135        { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
 136        { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
 137        { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
 138        { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
 139};
 140#define RATES_24_OFFS   0
 141#define N_RATES_24      ARRAY_SIZE(iwl_cfg80211_rates)
 142#define RATES_52_OFFS   4
 143#define N_RATES_52      (N_RATES_24 - RATES_52_OFFS)
 144
 145/**
 146 * enum iwl_nvm_channel_flags - channel flags in NVM
 147 * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo
 148 * @NVM_CHANNEL_IBSS: usable as an IBSS channel
 149 * @NVM_CHANNEL_ACTIVE: active scanning allowed
 150 * @NVM_CHANNEL_RADAR: radar detection required
 151 * @NVM_CHANNEL_DFS: dynamic freq selection candidate
 152 * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
 153 * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
 154 * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
 155 * @NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
 156 */
 157enum iwl_nvm_channel_flags {
 158        NVM_CHANNEL_VALID = BIT(0),
 159        NVM_CHANNEL_IBSS = BIT(1),
 160        NVM_CHANNEL_ACTIVE = BIT(3),
 161        NVM_CHANNEL_RADAR = BIT(4),
 162        NVM_CHANNEL_DFS = BIT(7),
 163        NVM_CHANNEL_WIDE = BIT(8),
 164        NVM_CHANNEL_40MHZ = BIT(9),
 165        NVM_CHANNEL_80MHZ = BIT(10),
 166        NVM_CHANNEL_160MHZ = BIT(11),
 167};
 168
 169#define CHECK_AND_PRINT_I(x)    \
 170        ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "")
 171
 172static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
 173                                struct iwl_nvm_data *data,
 174                                const __le16 * const nvm_ch_flags)
 175{
 176        int ch_idx;
 177        int n_channels = 0;
 178        struct ieee80211_channel *channel;
 179        u16 ch_flags;
 180        bool is_5ghz;
 181
 182        for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) {
 183                ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
 184                if (!(ch_flags & NVM_CHANNEL_VALID)) {
 185                        IWL_DEBUG_EEPROM(dev,
 186                                         "Ch. %d Flags %x [%sGHz] - No traffic\n",
 187                                         iwl_nvm_channels[ch_idx],
 188                                         ch_flags,
 189                                         (ch_idx >= NUM_2GHZ_CHANNELS) ?
 190                                         "5.2" : "2.4");
 191                        continue;
 192                }
 193
 194                channel = &data->channels[n_channels];
 195                n_channels++;
 196
 197                channel->hw_value = iwl_nvm_channels[ch_idx];
 198                channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
 199                                IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
 200                channel->center_freq =
 201                        ieee80211_channel_to_frequency(
 202                                channel->hw_value, channel->band);
 203
 204                /* TODO: Need to be dependent to the NVM */
 205                channel->flags = IEEE80211_CHAN_NO_HT40;
 206                if (ch_idx < NUM_2GHZ_CHANNELS &&
 207                    (ch_flags & NVM_CHANNEL_40MHZ)) {
 208                        if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS)
 209                                channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
 210                        if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS)
 211                                channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
 212                } else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT &&
 213                           (ch_flags & NVM_CHANNEL_40MHZ)) {
 214                        if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
 215                                channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
 216                        else
 217                                channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
 218                }
 219                if (!(ch_flags & NVM_CHANNEL_80MHZ))
 220                        channel->flags |= IEEE80211_CHAN_NO_80MHZ;
 221                if (!(ch_flags & NVM_CHANNEL_160MHZ))
 222                        channel->flags |= IEEE80211_CHAN_NO_160MHZ;
 223
 224                if (!(ch_flags & NVM_CHANNEL_IBSS))
 225                        channel->flags |= IEEE80211_CHAN_NO_IBSS;
 226
 227                if (!(ch_flags & NVM_CHANNEL_ACTIVE))
 228                        channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
 229
 230                if (ch_flags & NVM_CHANNEL_RADAR)
 231                        channel->flags |= IEEE80211_CHAN_RADAR;
 232
 233                /* Initialize regulatory-based run-time data */
 234
 235                /* TODO: read the real value from the NVM */
 236                channel->max_power = 0;
 237                is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
 238                IWL_DEBUG_EEPROM(dev,
 239                                 "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
 240                                 channel->hw_value,
 241                                 is_5ghz ? "5.2" : "2.4",
 242                                 CHECK_AND_PRINT_I(VALID),
 243                                 CHECK_AND_PRINT_I(IBSS),
 244                                 CHECK_AND_PRINT_I(ACTIVE),
 245                                 CHECK_AND_PRINT_I(RADAR),
 246                                 CHECK_AND_PRINT_I(WIDE),
 247                                 CHECK_AND_PRINT_I(DFS),
 248                                 ch_flags,
 249                                 channel->max_power,
 250                                 ((ch_flags & NVM_CHANNEL_IBSS) &&
 251                                  !(ch_flags & NVM_CHANNEL_RADAR))
 252                                        ? "" : "not ");
 253        }
 254
 255        return n_channels;
 256}
 257
 258static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
 259                                  struct iwl_nvm_data *data,
 260                                  struct ieee80211_sta_vht_cap *vht_cap)
 261{
 262        vht_cap->vht_supported = true;
 263
 264        vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
 265                       IEEE80211_VHT_CAP_RXSTBC_1 |
 266                       IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
 267                       7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
 268
 269        if (iwlwifi_mod_params.amsdu_size_8K)
 270                vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
 271
 272        vht_cap->vht_mcs.rx_mcs_map =
 273                cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
 274                            IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
 275                            IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
 276                            IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
 277                            IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
 278                            IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
 279                            IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
 280                            IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
 281
 282        if (data->valid_rx_ant == 1 || cfg->rx_with_siso_diversity) {
 283                vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
 284                                IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
 285                /* this works because NOT_SUPPORTED == 3 */
 286                vht_cap->vht_mcs.rx_mcs_map |=
 287                        cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
 288        }
 289
 290        vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
 291}
 292
 293static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
 294                            struct iwl_nvm_data *data, const __le16 *nvm_sw,
 295                            bool enable_vht, u8 tx_chains, u8 rx_chains)
 296{
 297        int n_channels = iwl_init_channel_map(dev, cfg, data,
 298                        &nvm_sw[NVM_CHANNELS]);
 299        int n_used = 0;
 300        struct ieee80211_supported_band *sband;
 301
 302        sband = &data->bands[IEEE80211_BAND_2GHZ];
 303        sband->band = IEEE80211_BAND_2GHZ;
 304        sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
 305        sband->n_bitrates = N_RATES_24;
 306        n_used += iwl_init_sband_channels(data, sband, n_channels,
 307                                          IEEE80211_BAND_2GHZ);
 308        iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ,
 309                             tx_chains, rx_chains);
 310
 311        sband = &data->bands[IEEE80211_BAND_5GHZ];
 312        sband->band = IEEE80211_BAND_5GHZ;
 313        sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
 314        sband->n_bitrates = N_RATES_52;
 315        n_used += iwl_init_sband_channels(data, sband, n_channels,
 316                                          IEEE80211_BAND_5GHZ);
 317        iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
 318                             tx_chains, rx_chains);
 319        if (enable_vht)
 320                iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap);
 321
 322        if (n_channels != n_used)
 323                IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
 324                            n_used, n_channels);
 325}
 326
 327struct iwl_nvm_data *
 328iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
 329                   const __le16 *nvm_hw, const __le16 *nvm_sw,
 330                   const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains)
 331{
 332        struct iwl_nvm_data *data;
 333        u8 hw_addr[ETH_ALEN];
 334        u16 radio_cfg, sku;
 335
 336        data = kzalloc(sizeof(*data) +
 337                       sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
 338                       GFP_KERNEL);
 339        if (!data)
 340                return NULL;
 341
 342        data->nvm_version = le16_to_cpup(nvm_sw + NVM_VERSION);
 343
 344        radio_cfg = le16_to_cpup(nvm_sw + RADIO_CFG);
 345        data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
 346        data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
 347        data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
 348        data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
 349        data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
 350        data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
 351
 352        sku = le16_to_cpup(nvm_sw + SKU);
 353        data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
 354        data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
 355        data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
 356        if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
 357                data->sku_cap_11n_enable = false;
 358
 359        /* check overrides (some devices have wrong NVM) */
 360        if (cfg->valid_tx_ant)
 361                data->valid_tx_ant = cfg->valid_tx_ant;
 362        if (cfg->valid_rx_ant)
 363                data->valid_rx_ant = cfg->valid_rx_ant;
 364
 365        if (!data->valid_tx_ant || !data->valid_rx_ant) {
 366                IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n",
 367                            data->valid_tx_ant, data->valid_rx_ant);
 368                kfree(data);
 369                return NULL;
 370        }
 371
 372        data->n_hw_addrs = le16_to_cpup(nvm_sw + N_HW_ADDRS);
 373
 374        data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
 375        data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
 376
 377        /* The byte order is little endian 16 bit, meaning 214365 */
 378        memcpy(hw_addr, nvm_hw + HW_ADDR, ETH_ALEN);
 379        data->hw_addr[0] = hw_addr[1];
 380        data->hw_addr[1] = hw_addr[0];
 381        data->hw_addr[2] = hw_addr[3];
 382        data->hw_addr[3] = hw_addr[2];
 383        data->hw_addr[4] = hw_addr[5];
 384        data->hw_addr[5] = hw_addr[4];
 385
 386        iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE,
 387                        tx_chains, rx_chains);
 388
 389        data->calib_version = 255;   /* TODO:
 390                                        this value will prevent some checks from
 391                                        failing, we need to check if this
 392                                        field is still needed, and if it does,
 393                                        where is it in the NVM*/
 394
 395        return data;
 396}
 397IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
 398