Subject: linux-next: manual merge of the wireless-drivers-next tree with the wireless-drivers tree

From: Stephen Rothwell <[email-masked]>
Date: Thu, 26 Apr 2018 11:09:17 +1000

Hi all,

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.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

-- 
Cheers,
Stephen Rothwell

diff --cc drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index ca0174680af9,6d33c14579d9..000000000000
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@@ -978,42 -943,302 +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);