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

Commit efde6648 authored by Xinming Hu's avatar Xinming Hu Committed by Kalle Valo
Browse files

mwifiex: pcie: extract wifi part from combo firmware during function level reset



A separate wifi-only firmware was download during pcie function level
reset. It is in fact the tail part of wifi/bt combo firmware. Per
Brian's and Dmitry's suggestion, this patch extract the wifi part from
combo firmware.

After that, the mrvl/pcie8997_wlan_v4.bin image in linux-firmware repo
is redundant (though I guess we keep it around to support older
kernels).

Signed-off-by: default avatarXinming Hu <huxm@marvell.com>
Signed-off-by: default avatarGanapathi Bhat <gbhat@marvell.com>
Signed-off-by: default avatarCathy Luo <cluo@marvell.com>
Signed-off-by: default avatarBrian Norris <briannorris@chromium.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 127ee1db
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -43,6 +43,24 @@ struct tx_packet_hdr {
	struct rfc_1042_hdr rfc1042_hdr;
} __packed;

struct mwifiex_fw_header {
	__le32 dnld_cmd;
	__le32 base_addr;
	__le32 data_length;
	__le32 crc;
} __packed;

struct mwifiex_fw_data {
	struct mwifiex_fw_header header;
	__le32 seq_num;
	u8 data[1];
} __packed;

#define MWIFIEX_FW_DNLD_CMD_1 0x1
#define MWIFIEX_FW_DNLD_CMD_5 0x5
#define MWIFIEX_FW_DNLD_CMD_6 0x6
#define MWIFIEX_FW_DNLD_CMD_7 0x7

#define B_SUPPORTED_RATES               5
#define G_SUPPORTED_RATES               9
#define BG_SUPPORTED_RATES              13
+107 −7
Original line number Diff line number Diff line
@@ -1956,6 +1956,94 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
	return ret;
}

/* Combo firmware image is a combination of
 * (1) combo crc heaer, start with CMD5
 * (2) bluetooth image, start with CMD7, end with CMD6, data wrapped in CMD1.
 * (3) wifi image.
 *
 * This function bypass the header and bluetooth part, return
 * the offset of tail wifi-only part.
 */

static int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter,
				   const void *firmware, u32 firmware_len) {
	const struct mwifiex_fw_data *fwdata;
	u32 offset = 0, data_len, dnld_cmd;
	int ret = 0;
	bool cmd7_before = false;

	while (1) {
		/* Check for integer and buffer overflow */
		if (offset + sizeof(fwdata->header) < sizeof(fwdata->header) ||
		    offset + sizeof(fwdata->header) >= firmware_len) {
			mwifiex_dbg(adapter, ERROR,
				    "extract wifi-only fw failure!\n");
			ret = -1;
			goto done;
		}

		fwdata = firmware + offset;
		dnld_cmd = le32_to_cpu(fwdata->header.dnld_cmd);
		data_len = le32_to_cpu(fwdata->header.data_length);

		/* Skip past header */
		offset += sizeof(fwdata->header);

		switch (dnld_cmd) {
		case MWIFIEX_FW_DNLD_CMD_1:
			if (!cmd7_before) {
				mwifiex_dbg(adapter, ERROR,
					    "no cmd7 before cmd1!\n");
				ret = -1;
				goto done;
			}
			if (offset + data_len < data_len) {
				mwifiex_dbg(adapter, ERROR, "bad FW parse\n");
				ret = -1;
				goto done;
			}
			offset += data_len;
			break;
		case MWIFIEX_FW_DNLD_CMD_5:
			/* Check for integer overflow */
			if (offset + data_len < data_len) {
				mwifiex_dbg(adapter, ERROR, "bad FW parse\n");
				ret = -1;
				goto done;
			}
			offset += data_len;
			break;
		case MWIFIEX_FW_DNLD_CMD_6:
			/* Check for integer overflow */
			if (offset + data_len < data_len) {
				mwifiex_dbg(adapter, ERROR, "bad FW parse\n");
				ret = -1;
				goto done;
			}
			offset += data_len;
			if (offset >= firmware_len) {
				mwifiex_dbg(adapter, ERROR,
					    "extract wifi-only fw failure!\n");
				ret = -1;
			} else {
				ret = offset;
			}
			goto done;
		case MWIFIEX_FW_DNLD_CMD_7:
			cmd7_before = true;
			break;
		default:
			mwifiex_dbg(adapter, ERROR, "unknown dnld_cmd %d\n",
				    dnld_cmd);
			ret = -1;
			goto done;
		}
	}

done:
	return ret;
}

/*
 * This function downloads the firmware to the card.
 *
@@ -1971,7 +2059,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
	u32 firmware_len = fw->fw_len;
	u32 offset = 0;
	struct sk_buff *skb;
	u32 txlen, tx_blocks = 0, tries, len;
	u32 txlen, tx_blocks = 0, tries, len, val;
	u32 block_retry_cnt = 0;
	struct pcie_service_card *card = adapter->card;
	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
@@ -1998,6 +2086,24 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
		goto done;
	}

	ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_13_REG, &val);
	if (ret) {
		mwifiex_dbg(adapter, FATAL, "Failed to read scratch register 13\n");
		goto done;
	}

	/* PCIE FLR case: extract wifi part from combo firmware*/
	if (val == MWIFIEX_PCIE_FLR_HAPPENS) {
		ret = mwifiex_extract_wifi_fw(adapter, firmware, firmware_len);
		if (ret < 0) {
			mwifiex_dbg(adapter, ERROR, "Failed to extract wifi fw\n");
			goto done;
		}
		offset = ret;
		mwifiex_dbg(adapter, MSG,
			    "info: dnld wifi firmware from %d bytes\n", offset);
	}

	/* Perform firmware data transfer */
	do {
		u32 ireg_intr = 0;
@@ -3070,12 +3176,6 @@ static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter)
	struct pci_dev *pdev = card->dev;
	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;

	/* Bluetooth is not on pcie interface. Download Wifi only firmware
	 * during pcie FLR, so that bluetooth part of firmware which is
	 * already running doesn't get affected.
	 */
	strcpy(adapter->fw_name, PCIE8997_DEFAULT_WIFIFW_NAME);

	/* tx_buf_size might be changed to 3584 by firmware during
	 * data transfer, we should reset it to default size.
	 */
+2 −1
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@
#define PCIE8897_B0_FW_NAME "mrvl/pcie8897_uapsta.bin"
#define PCIEUART8997_FW_NAME_V4 "mrvl/pcieuart8997_combo_v4.bin"
#define PCIEUSB8997_FW_NAME_V4 "mrvl/pcieusb8997_combo_v4.bin"
#define PCIE8997_DEFAULT_WIFIFW_NAME "mrvl/pcie8997_wlan_v4.bin"

#define PCIE_VENDOR_ID_MARVELL              (0x11ab)
#define PCIE_VENDOR_ID_V2_MARVELL           (0x1b4b)
@@ -120,6 +119,8 @@
#define MWIFIEX_SLEEP_COOKIE_SIZE			4
#define MWIFIEX_MAX_DELAY_COUNT				100

#define MWIFIEX_PCIE_FLR_HAPPENS 0xFEDCBABA

struct mwifiex_pcie_card_reg {
	u16 cmd_addr_lo;
	u16 cmd_addr_hi;