Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2fed2b57 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "UPSTREAM: ath10k: search all IEs for variant before falling back"

parents 9ea3db25 887e460d
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -758,7 +758,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev)
	enum ath10k_hw_rev hw_rev;
	size_t size;
	int ret;
	u32 chip_id;
	struct ath10k_bus_params bus_params;

	of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev);
	if (!of_id) {
@@ -814,14 +814,15 @@ static int ath10k_ahb_probe(struct platform_device *pdev)

	ath10k_pci_ce_deinit(ar);

	chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
	if (chip_id == 0xffffffff) {
	bus_params.dev_type = ATH10K_DEV_TYPE_LL;
	bus_params.chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
	if (bus_params.chip_id == 0xffffffff) {
		ath10k_err(ar, "failed to get chip id\n");
		ret = -ENODEV;
		goto err_halt_device;
	}

	ret = ath10k_core_register(ar, chip_id);
	ret = ath10k_core_register(ar, &bus_params);
	if (ret) {
		ath10k_err(ar, "failed to register driver core: %d\n", ret);
		goto err_halt_device;
+277 −265
Original line number Diff line number Diff line
@@ -693,149 +693,6 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
	return 0;
}

static int ath10k_download_board_data(struct ath10k *ar, const void *data,
				      size_t data_len)
{
	u32 board_data_size = ar->hw_params.fw.board_size;
	u32 address;
	int ret;

	ret = ath10k_push_board_ext_data(ar, data, data_len);
	if (ret) {
		ath10k_err(ar, "could not push board ext data (%d)\n", ret);
		goto exit;
	}

	ret = ath10k_bmi_read32(ar, hi_board_data, &address);
	if (ret) {
		ath10k_err(ar, "could not read board data addr (%d)\n", ret);
		goto exit;
	}

	ret = ath10k_bmi_write_memory(ar, address, data,
				      min_t(u32, board_data_size,
					    data_len));
	if (ret) {
		ath10k_err(ar, "could not write board data (%d)\n", ret);
		goto exit;
	}

	ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
	if (ret) {
		ath10k_err(ar, "could not write board data bit (%d)\n", ret);
		goto exit;
	}

exit:
	return ret;
}

static int ath10k_download_cal_file(struct ath10k *ar,
				    const struct firmware *file)
{
	int ret;

	if (!file)
		return -ENOENT;

	if (IS_ERR(file))
		return PTR_ERR(file);

	ret = ath10k_download_board_data(ar, file->data, file->size);
	if (ret) {
		ath10k_err(ar, "failed to download cal_file data: %d\n", ret);
		return ret;
	}

	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");

	return 0;
}

static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name)
{
	struct device_node *node;
	int data_len;
	void *data;
	int ret;

	node = ar->dev->of_node;
	if (!node)
		/* Device Tree is optional, don't print any warnings if
		 * there's no node for ath10k.
		 */
		return -ENOENT;

	if (!of_get_property(node, dt_name, &data_len)) {
		/* The calibration data node is optional */
		return -ENOENT;
	}

	if (data_len != ar->hw_params.cal_data_len) {
		ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
			    data_len);
		ret = -EMSGSIZE;
		goto out;
	}

	data = kmalloc(data_len, GFP_KERNEL);
	if (!data) {
		ret = -ENOMEM;
		goto out;
	}

	ret = of_property_read_u8_array(node, dt_name, data, data_len);
	if (ret) {
		ath10k_warn(ar, "failed to read calibration data from DT: %d\n",
			    ret);
		goto out_free;
	}

	ret = ath10k_download_board_data(ar, data, data_len);
	if (ret) {
		ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",
			    ret);
		goto out_free;
	}

	ret = 0;

out_free:
	kfree(data);

out:
	return ret;
}

static int ath10k_download_cal_eeprom(struct ath10k *ar)
{
	size_t data_len;
	void *data = NULL;
	int ret;

	ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len);
	if (ret) {
		if (ret != -EOPNOTSUPP)
			ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n",
				    ret);
		goto out_free;
	}

	ret = ath10k_download_board_data(ar, data, data_len);
	if (ret) {
		ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n",
			    ret);
		goto out_free;
	}

	ret = 0;

out_free:
	kfree(data);

	return ret;
}

static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)
{
	u32 result, address;
@@ -986,64 +843,6 @@ static int ath10k_core_check_dt(struct ath10k *ar)
	return 0;
}

static int ath10k_download_and_run_otp(struct ath10k *ar)
{
	u32 result, address = ar->hw_params.patch_load_addr;
	u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param;
	int ret;

	ret = ath10k_download_board_data(ar,
					 ar->running_fw->board_data,
					 ar->running_fw->board_len);
	if (ret) {
		ath10k_err(ar, "failed to download board data: %d\n", ret);
		return ret;
	}

	/* OTP is optional */

	if (!ar->running_fw->fw_file.otp_data ||
	    !ar->running_fw->fw_file.otp_len) {
		ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n",
			    ar->running_fw->fw_file.otp_data,
			    ar->running_fw->fw_file.otp_len);
		return 0;
	}

	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
		   address, ar->running_fw->fw_file.otp_len);

	ret = ath10k_bmi_fast_download(ar, address,
				       ar->running_fw->fw_file.otp_data,
				       ar->running_fw->fw_file.otp_len);
	if (ret) {
		ath10k_err(ar, "could not write otp (%d)\n", ret);
		return ret;
	}

	/* As of now pre-cal is valid for 10_4 variants */
	if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
	    ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
		bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;

	ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);
	if (ret) {
		ath10k_err(ar, "could not execute otp (%d)\n", ret);
		return ret;
	}

	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);

	if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
				   ar->running_fw->fw_file.fw_features)) &&
	    result != 0) {
		ath10k_err(ar, "otp calibration failed: %d", result);
		return -EINVAL;
	}

	return 0;
}

static int ath10k_download_fw(struct ath10k *ar)
{
	u32 address, data_len;
@@ -1236,14 +1035,61 @@ static int ath10k_core_parse_bd_ie_board(struct ath10k *ar,
	return ret;
}

static int ath10k_core_search_bd(struct ath10k *ar,
				 const char *boardname,
				 const u8 *data,
				 size_t len)
{
	size_t ie_len;
	struct ath10k_fw_ie *hdr;
	int ret = -ENOENT, ie_id;

	while (len > sizeof(struct ath10k_fw_ie)) {
		hdr = (struct ath10k_fw_ie *)data;
		ie_id = le32_to_cpu(hdr->id);
		ie_len = le32_to_cpu(hdr->len);

		len -= sizeof(*hdr);
		data = hdr->data;

		if (len < ALIGN(ie_len, 4)) {
			ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n",
				   ie_id, ie_len, len);
			return -EINVAL;
		}

		switch (ie_id) {
		case ATH10K_BD_IE_BOARD:
			ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,
							    boardname);
			if (ret == -ENOENT)
				/* no match found, continue */
				break;

			/* either found or error, so stop searching */
			goto out;
		}

		/* jump over the padding */
		ie_len = ALIGN(ie_len, 4);

		len -= ie_len;
		data += ie_len;
	}

out:
	/* return result of parse_bd_ie_board() or -ENOENT */
	return ret;
}

static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
					      const char *boardname,
					      const char *fallback_boardname,
					      const char *filename)
{
	size_t len, magic_len, ie_len;
	struct ath10k_fw_ie *hdr;
	size_t len, magic_len;
	const u8 *data;
	int ret, ie_id;
	int ret;

	ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
							ar->hw_params.fw.dir,
@@ -1281,69 +1127,23 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
	data += magic_len;
	len -= magic_len;

	while (len > sizeof(struct ath10k_fw_ie)) {
		hdr = (struct ath10k_fw_ie *)data;
		ie_id = le32_to_cpu(hdr->id);
		ie_len = le32_to_cpu(hdr->len);

		len -= sizeof(*hdr);
		data = hdr->data;

		if (len < ALIGN(ie_len, 4)) {
			ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n",
				   ie_id, ie_len, len);
			ret = -EINVAL;
			goto err;
		}

		switch (ie_id) {
		case ATH10K_BD_IE_BOARD:
			ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,
							    boardname);
			if (ret == -ENOENT && ar->id.bdf_ext[0] != '\0') {
				/* try default bdf if variant was not found */
				char *s, *v = ",variant=";
				char boardname2[100];

				strlcpy(boardname2, boardname,
					sizeof(boardname2));

				s = strstr(boardname2, v);
				if (s)
					*s = '\0';  /* strip ",variant=%s" */

				ret = ath10k_core_parse_bd_ie_board(ar, data,
								    ie_len,
								    boardname2);
			}

			if (ret == -ENOENT)
				/* no match found, continue */
				break;
			else if (ret)
				/* there was an error, bail out */
				goto err;

			/* board data found */
			goto out;
		}

		/* jump over the padding */
		ie_len = ALIGN(ie_len, 4);
	/* attempt to find boardname in the IE list */
	ret = ath10k_core_search_bd(ar, boardname, data, len);

		len -= ie_len;
		data += ie_len;
	}
	/* if we didn't find it and have a fallback name, try that */
	if (ret == -ENOENT && fallback_boardname)
		ret = ath10k_core_search_bd(ar, fallback_boardname, data, len);

out:
	if (!ar->normal_mode_fw.board_data || !ar->normal_mode_fw.board_len) {
	if (ret == -ENOENT) {
		ath10k_err(ar,
			   "failed to fetch board data for %s from %s/%s\n",
			   boardname, ar->hw_params.fw.dir, filename);
		ret = -ENODATA;
		goto err;
	}

	if (ret)
		goto err;

	return 0;

err:
@@ -1352,12 +1152,12 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
}

static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
					 size_t name_len)
					 size_t name_len, bool with_variant)
{
	/* strlen(',variant=') + strlen(ar->id.bdf_ext) */
	char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 };

	if (ar->id.bdf_ext[0] != '\0')
	if (with_variant && ar->id.bdf_ext[0] != '\0')
		scnprintf(variant, sizeof(variant), ",variant=%s",
			  ar->id.bdf_ext);

@@ -1391,17 +1191,26 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name,

static int ath10k_core_fetch_board_file(struct ath10k *ar)
{
	char boardname[100];
	char boardname[100], fallback_boardname[100];
	int ret;

	ret = ath10k_core_create_board_name(ar, boardname, sizeof(boardname));
	ret = ath10k_core_create_board_name(ar, boardname,
					    sizeof(boardname), true);
	if (ret) {
		ath10k_err(ar, "failed to create board name: %d", ret);
		return ret;
	}

	ret = ath10k_core_create_board_name(ar, fallback_boardname,
					    sizeof(boardname), false);
	if (ret) {
		ath10k_err(ar, "failed to create fallback board name: %d", ret);
		return ret;
	}

	ar->bd_api = 2;
	ret = ath10k_core_fetch_board_data_api_n(ar, boardname,
						 fallback_boardname,
						 ATH10K_BOARD_API2_FILE);
	if (!ret)
		goto success;
@@ -1419,6 +1228,207 @@ static int ath10k_core_fetch_board_file(struct ath10k *ar)
	return 0;
}

static int ath10k_download_board_data(struct ath10k *ar, const void *data,
				      size_t data_len)
{
	u32 board_data_size = ar->hw_params.fw.board_size;
	u32 address;
	int ret;

	ret = ath10k_push_board_ext_data(ar, data, data_len);
	if (ret) {
		ath10k_err(ar, "could not push board ext data (%d)\n", ret);
		goto exit;
	}

	ret = ath10k_bmi_read32(ar, hi_board_data, &address);
	if (ret) {
		ath10k_err(ar, "could not read board data addr (%d)\n", ret);
		goto exit;
	}

	ret = ath10k_bmi_write_memory(ar, address, data,
				      min_t(u32, board_data_size,
					    data_len));
	if (ret) {
		ath10k_err(ar, "could not write board data (%d)\n", ret);
		goto exit;
	}

	ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
	if (ret) {
		ath10k_err(ar, "could not write board data bit (%d)\n", ret);
		goto exit;
	}

exit:
	return ret;
}

static int ath10k_download_and_run_otp(struct ath10k *ar)
{
	u32 result, address = ar->hw_params.patch_load_addr;
	u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param;
	int ret;

	ret = ath10k_download_board_data(ar,
					 ar->running_fw->board_data,
					 ar->running_fw->board_len);
	if (ret) {
		ath10k_err(ar, "failed to download board data: %d\n", ret);
		return ret;
	}

	/* OTP is optional */

	if (!ar->running_fw->fw_file.otp_data ||
	    !ar->running_fw->fw_file.otp_len) {
		ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n",
			    ar->running_fw->fw_file.otp_data,
			    ar->running_fw->fw_file.otp_len);
		return 0;
	}

	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
		   address, ar->running_fw->fw_file.otp_len);

	ret = ath10k_bmi_fast_download(ar, address,
				       ar->running_fw->fw_file.otp_data,
				       ar->running_fw->fw_file.otp_len);
	if (ret) {
		ath10k_err(ar, "could not write otp (%d)\n", ret);
		return ret;
	}

	/* As of now pre-cal is valid for 10_4 variants */
	if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
	    ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
		bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;

	ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);
	if (ret) {
		ath10k_err(ar, "could not execute otp (%d)\n", ret);
		return ret;
	}

	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);

	if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
				   ar->running_fw->fw_file.fw_features)) &&
	    result != 0) {
		ath10k_err(ar, "otp calibration failed: %d", result);
		return -EINVAL;
	}

	return 0;
}

static int ath10k_download_cal_file(struct ath10k *ar,
				    const struct firmware *file)
{
	int ret;

	if (!file)
		return -ENOENT;

	if (IS_ERR(file))
		return PTR_ERR(file);

	ret = ath10k_download_board_data(ar, file->data, file->size);
	if (ret) {
		ath10k_err(ar, "failed to download cal_file data: %d\n", ret);
		return ret;
	}

	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");

	return 0;
}

static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name)
{
	struct device_node *node;
	int data_len;
	void *data;
	int ret;

	node = ar->dev->of_node;
	if (!node)
		/* Device Tree is optional, don't print any warnings if
		 * there's no node for ath10k.
		 */
		return -ENOENT;

	if (!of_get_property(node, dt_name, &data_len)) {
		/* The calibration data node is optional */
		return -ENOENT;
	}

	if (data_len != ar->hw_params.cal_data_len) {
		ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
			    data_len);
		ret = -EMSGSIZE;
		goto out;
	}

	data = kmalloc(data_len, GFP_KERNEL);
	if (!data) {
		ret = -ENOMEM;
		goto out;
	}

	ret = of_property_read_u8_array(node, dt_name, data, data_len);
	if (ret) {
		ath10k_warn(ar, "failed to read calibration data from DT: %d\n",
			    ret);
		goto out_free;
	}

	ret = ath10k_download_board_data(ar, data, data_len);
	if (ret) {
		ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",
			    ret);
		goto out_free;
	}

	ret = 0;

out_free:
	kfree(data);

out:
	return ret;
}

static int ath10k_download_cal_eeprom(struct ath10k *ar)
{
	size_t data_len;
	void *data = NULL;
	int ret;

	ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len);
	if (ret) {
		if (ret != -EOPNOTSUPP)
			ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n",
				    ret);
		goto out_free;
	}

	ret = ath10k_download_board_data(ar, data, data_len);
	if (ret) {
		ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n",
			    ret);
		goto out_free;
	}

	ret = 0;

out_free:
	kfree(data);

	return ret;
}

int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
				     struct ath10k_fw_file *fw_file)
{
@@ -2637,9 +2647,11 @@ static void ath10k_core_register_work(struct work_struct *work)
	return;
}

int ath10k_core_register(struct ath10k *ar, u32 chip_id)
int ath10k_core_register(struct ath10k *ar,
			 const struct ath10k_bus_params *bus_params)
{
	ar->chip_id = chip_id;
	ar->chip_id = bus_params->chip_id;
	ar->dev_type = bus_params->dev_type;
	queue_work(ar->workqueue, &ar->register_work);

	return 0;
+13 −1
Original line number Diff line number Diff line
@@ -769,6 +769,16 @@ struct ath10k_per_peer_tx_stats {
	u32	reserved2;
};

enum ath10k_dev_type {
	ATH10K_DEV_TYPE_LL,
	ATH10K_DEV_TYPE_HL,
};

struct ath10k_bus_params {
	u32 chip_id;
	enum ath10k_dev_type dev_type;
};

struct ath10k {
	struct ath_common ath_common;
	struct ieee80211_hw *hw;
@@ -779,6 +789,7 @@ struct ath10k {
	enum ath10k_hw_rev hw_rev;
	u16 dev_id;
	u32 chip_id;
	enum ath10k_dev_type dev_type;
	u32 target_version;
	u8 fw_version_major;
	u32 fw_version_minor;
@@ -1051,7 +1062,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
		      const struct ath10k_fw_components *fw_components);
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
void ath10k_core_stop(struct ath10k *ar);
int ath10k_core_register(struct ath10k *ar, u32 chip_id);
int ath10k_core_register(struct ath10k *ar,
			 const struct ath10k_bus_params *bus_params);
void ath10k_core_unregister(struct ath10k *ar);

#endif /* _CORE_H_ */
+7 −6
Original line number Diff line number Diff line
@@ -3420,7 +3420,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
	struct ath10k *ar;
	struct ath10k_pci *ar_pci;
	enum ath10k_hw_rev hw_rev;
	u32 chip_id;
	struct ath10k_bus_params bus_params;
	bool pci_ps;
	int (*pci_soft_reset)(struct ath10k *ar);
	int (*pci_hard_reset)(struct ath10k *ar);
@@ -3556,19 +3556,20 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
		goto err_free_irq;
	}

	chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
	if (chip_id == 0xffffffff) {
	bus_params.dev_type = ATH10K_DEV_TYPE_LL;
	bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
	if (bus_params.chip_id == 0xffffffff) {
		ath10k_err(ar, "failed to get chip id\n");
		goto err_free_irq;
	}

	if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) {
	if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) {
		ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
			   pdev->device, chip_id);
			   pdev->device, bus_params.chip_id);
		goto err_free_irq;
	}

	ret = ath10k_core_register(ar, chip_id);
	ret = ath10k_core_register(ar, &bus_params);
	if (ret) {
		ath10k_err(ar, "failed to register driver core: %d\n", ret);
		goto err_free_irq;
+5 −3
Original line number Diff line number Diff line
@@ -1942,7 +1942,8 @@ static int ath10k_sdio_probe(struct sdio_func *func,
	struct ath10k_sdio *ar_sdio;
	struct ath10k *ar;
	enum ath10k_hw_rev hw_rev;
	u32 chip_id, dev_id_base;
	u32 dev_id_base;
	struct ath10k_bus_params bus_params;
	int ret, i;

	/* Assumption: All SDIO based chipsets (so far) are QCA6174 based.
@@ -2036,9 +2037,10 @@ static int ath10k_sdio_probe(struct sdio_func *func,
		goto err_free_wq;
	}

	bus_params.dev_type = ATH10K_DEV_TYPE_HL;
	/* TODO: don't know yet how to get chip_id with SDIO */
	chip_id = 0;
	ret = ath10k_core_register(ar, chip_id);
	bus_params.chip_id = 0;
	ret = ath10k_core_register(ar, &bus_params);
	if (ret) {
		ath10k_err(ar, "failed to register driver core: %d\n", ret);
		goto err_free_wq;
Loading