Merge git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git
authorKalle Valo <kvalo@codeaurora.org>
Thu, 26 Apr 2018 10:26:37 +0000 (13:26 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Thu, 26 Apr 2018 10:26:37 +0000 (13:26 +0300)
To fix a conflict reported by Stephen Rothwell <sfr@canb.auug.org.au>:

Today's linux-next merge of the wireless-drivers-next tree got a
conflict in:

  drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c

between commit:

  77e30e10ee28 ("iwlwifi: mvm: query regdb for wmm rule if needed")

from the wireless-drivers tree and commits:

  9c4f7d512740 ("iwlwifi: move all NVM parsing code to the common files")
  4c625c564ba2 ("iwlwifi: get rid of fw/nvm.c")

from the wireless-drivers-next tree.

1  2 
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c

@@@ -943,302 -978,42 +990,333 @@@ iwl_parse_nvm_mcc_info(struct device *d
        }
  
        regd->n_reg_rules = valid_rules;
+       regd->n_wmm_rules = n_wmms;
  
-       /* set alpha2 from FW. */
-       regd->alpha2[0] = fw_mcc >> 8;
-       regd->alpha2[1] = fw_mcc & 0xff;
+       /*
+        * Narrow down regdom for unused regulatory rules to prevent hole
+        * between reg rules to wmm rules.
+        */
+       regd_to_copy = sizeof(struct ieee80211_regdomain) +
+               valid_rules * sizeof(struct ieee80211_reg_rule);
+       wmms_to_copy = sizeof(struct ieee80211_wmm_rule) * n_wmms;
+       copy_rd = kzalloc(regd_to_copy + wmms_to_copy, GFP_KERNEL);
+       if (!copy_rd) {
+               copy_rd = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+       memcpy(copy_rd, regd, regd_to_copy);
+       memcpy((u8 *)copy_rd + regd_to_copy, (u8 *)regd + size_of_regd,
+              wmms_to_copy);
+       d_wmm = (struct ieee80211_wmm_rule *)((u8 *)copy_rd + regd_to_copy);
+       s_wmm = (struct ieee80211_wmm_rule *)((u8 *)regd + size_of_regd);
+       for (i = 0; i < regd->n_reg_rules; i++) {
+               if (!regd->reg_rules[i].wmm_rule)
+                       continue;
+               copy_rd->reg_rules[i].wmm_rule = d_wmm +
+                       (regd->reg_rules[i].wmm_rule - s_wmm) /
+                       sizeof(struct ieee80211_wmm_rule);
+       }
  
-       return regd;
+ out:
+       kfree(regdb_ptrs);
+       kfree(regd);
+       return copy_rd;
  }
  IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);
 +
 +#define IWL_MAX_NVM_SECTION_SIZE      0x1b58
 +#define IWL_MAX_EXT_NVM_SECTION_SIZE  0x1ffc
 +#define MAX_NVM_FILE_LEN      16384
 +
 +void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data,
 +                  unsigned int len)
 +{
 +#define IWL_4165_DEVICE_ID    0x5501
 +#define NVM_SKU_CAP_MIMO_DISABLE BIT(5)
 +
 +      if (section == NVM_SECTION_TYPE_PHY_SKU &&
 +          hw_id == IWL_4165_DEVICE_ID && data && len >= 5 &&
 +          (data[4] & NVM_SKU_CAP_MIMO_DISABLE))
 +              /* OTP 0x52 bug work around: it's a 1x1 device */
 +              data[3] = ANT_B | (ANT_B << 4);
 +}
 +IWL_EXPORT_SYMBOL(iwl_nvm_fixups);
 +
 +/*
 + * Reads external NVM from a file into mvm->nvm_sections
 + *
 + * HOW TO CREATE THE NVM FILE FORMAT:
 + * ------------------------------
 + * 1. create hex file, format:
 + *      3800 -> header
 + *      0000 -> header
 + *      5a40 -> data
 + *
 + *   rev - 6 bit (word1)
 + *   len - 10 bit (word1)
 + *   id - 4 bit (word2)
 + *   rsv - 12 bit (word2)
 + *
 + * 2. flip 8bits with 8 bits per line to get the right NVM file format
 + *
 + * 3. create binary file from the hex file
 + *
 + * 4. save as "iNVM_xxx.bin" under /lib/firmware
 + */
 +int iwl_read_external_nvm(struct iwl_trans *trans,
 +                        const char *nvm_file_name,
 +                        struct iwl_nvm_section *nvm_sections)
 +{
 +      int ret, section_size;
 +      u16 section_id;
 +      const struct firmware *fw_entry;
 +      const struct {
 +              __le16 word1;
 +              __le16 word2;
 +              u8 data[];
 +      } *file_sec;
 +      const u8 *eof;
 +      u8 *temp;
 +      int max_section_size;
 +      const __le32 *dword_buff;
 +
 +#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
 +#define NVM_WORD2_ID(x) (x >> 12)
 +#define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8))
 +#define EXT_NVM_WORD1_ID(x) ((x) >> 4)
 +#define NVM_HEADER_0  (0x2A504C54)
 +#define NVM_HEADER_1  (0x4E564D2A)
 +#define NVM_HEADER_SIZE       (4 * sizeof(u32))
 +
 +      IWL_DEBUG_EEPROM(trans->dev, "Read from external NVM\n");
 +
 +      /* Maximal size depends on NVM version */
 +      if (trans->cfg->nvm_type != IWL_NVM_EXT)
 +              max_section_size = IWL_MAX_NVM_SECTION_SIZE;
 +      else
 +              max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE;
 +
 +      /*
 +       * Obtain NVM image via request_firmware. Since we already used
 +       * request_firmware_nowait() for the firmware binary load and only
 +       * get here after that we assume the NVM request can be satisfied
 +       * synchronously.
 +       */
 +      ret = request_firmware(&fw_entry, nvm_file_name, trans->dev);
 +      if (ret) {
 +              IWL_ERR(trans, "ERROR: %s isn't available %d\n",
 +                      nvm_file_name, ret);
 +              return ret;
 +      }
 +
 +      IWL_INFO(trans, "Loaded NVM file %s (%zu bytes)\n",
 +               nvm_file_name, fw_entry->size);
 +
 +      if (fw_entry->size > MAX_NVM_FILE_LEN) {
 +              IWL_ERR(trans, "NVM file too large\n");
 +              ret = -EINVAL;
 +              goto out;
 +      }
 +
 +      eof = fw_entry->data + fw_entry->size;
 +      dword_buff = (__le32 *)fw_entry->data;
 +
 +      /* some NVM file will contain a header.
 +       * The header is identified by 2 dwords header as follow:
 +       * dword[0] = 0x2A504C54
 +       * dword[1] = 0x4E564D2A
 +       *
 +       * This header must be skipped when providing the NVM data to the FW.
 +       */
 +      if (fw_entry->size > NVM_HEADER_SIZE &&
 +          dword_buff[0] == cpu_to_le32(NVM_HEADER_0) &&
 +          dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) {
 +              file_sec = (void *)(fw_entry->data + NVM_HEADER_SIZE);
 +              IWL_INFO(trans, "NVM Version %08X\n", le32_to_cpu(dword_buff[2]));
 +              IWL_INFO(trans, "NVM Manufacturing date %08X\n",
 +                       le32_to_cpu(dword_buff[3]));
 +
 +              /* nvm file validation, dword_buff[2] holds the file version */
 +              if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
 +                  CSR_HW_REV_STEP(trans->hw_rev) == SILICON_C_STEP &&
 +                  le32_to_cpu(dword_buff[2]) < 0xE4A) {
 +                      ret = -EFAULT;
 +                      goto out;
 +              }
 +      } else {
 +              file_sec = (void *)fw_entry->data;
 +      }
 +
 +      while (true) {
 +              if (file_sec->data > eof) {
 +                      IWL_ERR(trans,
 +                              "ERROR - NVM file too short for section header\n");
 +                      ret = -EINVAL;
 +                      break;
 +              }
 +
 +              /* check for EOF marker */
 +              if (!file_sec->word1 && !file_sec->word2) {
 +                      ret = 0;
 +                      break;
 +              }
 +
 +              if (trans->cfg->nvm_type != IWL_NVM_EXT) {
 +                      section_size =
 +                              2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
 +                      section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
 +              } else {
 +                      section_size = 2 * EXT_NVM_WORD2_LEN(
 +                                              le16_to_cpu(file_sec->word2));
 +                      section_id = EXT_NVM_WORD1_ID(
 +                                              le16_to_cpu(file_sec->word1));
 +              }
 +
 +              if (section_size > max_section_size) {
 +                      IWL_ERR(trans, "ERROR - section too large (%d)\n",
 +                              section_size);
 +                      ret = -EINVAL;
 +                      break;
 +              }
 +
 +              if (!section_size) {
 +                      IWL_ERR(trans, "ERROR - section empty\n");
 +                      ret = -EINVAL;
 +                      break;
 +              }
 +
 +              if (file_sec->data + section_size > eof) {
 +                      IWL_ERR(trans,
 +                              "ERROR - NVM file too short for section (%d bytes)\n",
 +                              section_size);
 +                      ret = -EINVAL;
 +                      break;
 +              }
 +
 +              if (WARN(section_id >= NVM_MAX_NUM_SECTIONS,
 +                       "Invalid NVM section ID %d\n", section_id)) {
 +                      ret = -EINVAL;
 +                      break;
 +              }
 +
 +              temp = kmemdup(file_sec->data, section_size, GFP_KERNEL);
 +              if (!temp) {
 +                      ret = -ENOMEM;
 +                      break;
 +              }
 +
 +              iwl_nvm_fixups(trans->hw_id, section_id, temp, section_size);
 +
 +              kfree(nvm_sections[section_id].data);
 +              nvm_sections[section_id].data = temp;
 +              nvm_sections[section_id].length = section_size;
 +
 +              /* advance to the next section */
 +              file_sec = (void *)(file_sec->data + section_size);
 +      }
 +out:
 +      release_firmware(fw_entry);
 +      return ret;
 +}
 +IWL_EXPORT_SYMBOL(iwl_read_external_nvm);
 +
 +struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
 +                               const struct iwl_fw *fw)
 +{
 +      struct iwl_nvm_get_info cmd = {};
 +      struct iwl_nvm_get_info_rsp *rsp;
 +      struct iwl_nvm_data *nvm;
 +      struct iwl_host_cmd hcmd = {
 +              .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
 +              .data = { &cmd, },
 +              .len = { sizeof(cmd) },
 +              .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO)
 +      };
 +      int  ret;
 +      bool lar_fw_supported = !iwlwifi_mod_params.lar_disable &&
 +                              fw_has_capa(&fw->ucode_capa,
 +                                          IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
 +      u32 mac_flags;
 +      u32 sbands_flags = 0;
 +
 +      ret = iwl_trans_send_cmd(trans, &hcmd);
 +      if (ret)
 +              return ERR_PTR(ret);
 +
 +      if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp),
 +               "Invalid payload len in NVM response from FW %d",
 +               iwl_rx_packet_payload_len(hcmd.resp_pkt))) {
 +              ret = -EINVAL;
 +              goto out;
 +      }
 +
 +      rsp = (void *)hcmd.resp_pkt->data;
 +      if (le32_to_cpu(rsp->general.flags) & NVM_GENERAL_FLAGS_EMPTY_OTP)
 +              IWL_INFO(trans, "OTP is empty\n");
 +
 +      nvm = kzalloc(sizeof(*nvm) +
 +                    sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS,
 +                    GFP_KERNEL);
 +      if (!nvm) {
 +              ret = -ENOMEM;
 +              goto out;
 +      }
 +
 +      iwl_set_hw_address_from_csr(trans, nvm);
 +      /* TODO: if platform NVM has MAC address - override it here */
 +
 +      if (!is_valid_ether_addr(nvm->hw_addr)) {
 +              IWL_ERR(trans, "no valid mac address was found\n");
 +              ret = -EINVAL;
 +              goto err_free;
 +      }
 +
 +      IWL_INFO(trans, "base HW address: %pM\n", nvm->hw_addr);
 +
 +      /* Initialize general data */
 +      nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version);
 +
 +      /* Initialize MAC sku data */
 +      mac_flags = le32_to_cpu(rsp->mac_sku.mac_sku_flags);
 +      nvm->sku_cap_11ac_enable =
 +              !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AC_ENABLED);
 +      nvm->sku_cap_11n_enable =
 +              !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11N_ENABLED);
 +      nvm->sku_cap_band_24ghz_enable =
 +              !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED);
 +      nvm->sku_cap_band_52ghz_enable =
 +              !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED);
 +      nvm->sku_cap_mimo_disabled =
 +              !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED);
 +
 +      /* Initialize PHY sku data */
 +      nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains);
 +      nvm->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains);
 +
 +      if (le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported) {
 +              nvm->lar_enabled = true;
 +              sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR;
 +      }
 +
 +      iwl_init_sbands(trans->dev, trans->cfg, nvm,
 +                      rsp->regulatory.channel_profile,
 +                      nvm->valid_tx_ant & fw->valid_tx_ant,
 +                      nvm->valid_rx_ant & fw->valid_rx_ant,
 +                      sbands_flags);
 +
 +      iwl_free_resp(&hcmd);
 +      return nvm;
 +
 +err_free:
 +      kfree(nvm);
 +out:
 +      iwl_free_resp(&hcmd);
 +      return ERR_PTR(ret);
 +}
 +IWL_EXPORT_SYMBOL(iwl_get_nvm);
@@@ -106,35 -108,7 +107,36 @@@ iwl_parse_nvm_data(struct iwl_trans *tr
   */
  struct ieee80211_regdomain *
  iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
-                      int num_of_ch, __le32 *channels, u16 fw_mcc);
+                      int num_of_ch, __le32 *channels, u16 fw_mcc,
+                      u16 geo_info);
  
 +/**
 + * struct iwl_nvm_section - describes an NVM section in memory.
 + *
 + * This struct holds an NVM section read from the NIC using NVM_ACCESS_CMD,
 + * and saved for later use by the driver. Not all NVM sections are saved
 + * this way, only the needed ones.
 + */
 +struct iwl_nvm_section {
 +      u16 length;
 +      const u8 *data;
 +};
 +
 +/**
 + * iwl_read_external_nvm - Reads external NVM from a file into nvm_sections
 + */
 +int iwl_read_external_nvm(struct iwl_trans *trans,
 +                        const char *nvm_file_name,
 +                        struct iwl_nvm_section *nvm_sections);
 +void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data,
 +                  unsigned int len);
 +
 +/**
 + * iwl_get_nvm - retrieve NVM data from firmware
 + *
 + * Allocates a new iwl_nvm_data structure, fills it with
 + * NVM data, and returns it to caller.
 + */
 +struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
 +                               const struct iwl_fw *fw);
  #endif /* __iwl_nvm_parse_h__ */