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

Commit 5593e334 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'qed-flash-upgrade-support'



Sudarsana Reddy Kalluru says:

====================
qed*: Flash upgrade support.

The patch series adds adapter flash upgrade support for qed/qede drivers.

Please consider applying it to net-next branch.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 50bc60cb ccfa110c
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -81,6 +81,13 @@ enum qed_coalescing_mode {
	QED_COAL_MODE_ENABLE
};

enum qed_nvm_cmd {
	QED_PUT_FILE_BEGIN = DRV_MSG_CODE_NVM_PUT_FILE_BEGIN,
	QED_PUT_FILE_DATA = DRV_MSG_CODE_NVM_PUT_FILE_DATA,
	QED_NVM_WRITE_NVRAM = DRV_MSG_CODE_NVM_WRITE_NVRAM,
	QED_GET_MCP_NVM_RESP = 0xFFFFFF00
};

struct qed_eth_cb_ops;
struct qed_dev_info;
union qed_mcp_protocol_stats;
@@ -437,6 +444,11 @@ enum BAR_ID {
	BAR_ID_1		/* Used for doorbells */
};

struct qed_nvm_image_info {
	u32 num_images;
	struct bist_nvm_image_att *image_att;
};

#define DRV_MODULE_VERSION		      \
	__stringify(QED_MAJOR_VERSION) "."    \
	__stringify(QED_MINOR_VERSION) "."    \
@@ -561,6 +573,9 @@ struct qed_hwfn {
	/* L2-related */
	struct qed_l2_info *p_l2_info;

	/* Nvm images number and attributes */
	struct qed_nvm_image_info nvm_info;

	struct qed_ptt *p_arfs_ptt;

	struct qed_simd_fp_handler	simd_proto_handler[64];
+23 −1
Original line number Diff line number Diff line
@@ -2932,6 +2932,12 @@ static int qed_get_dev_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
	return 0;
}

static void qed_nvm_info_free(struct qed_hwfn *p_hwfn)
{
	kfree(p_hwfn->nvm_info.image_att);
	p_hwfn->nvm_info.image_att = NULL;
}

static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
				 void __iomem *p_regview,
				 void __iomem *p_doorbells,
@@ -2995,12 +3001,25 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
			DP_NOTICE(p_hwfn, "Failed to initiate PF FLR\n");
	}

	/* NVRAM info initialization and population */
	if (IS_LEAD_HWFN(p_hwfn)) {
		rc = qed_mcp_nvm_info_populate(p_hwfn);
		if (rc) {
			DP_NOTICE(p_hwfn,
				  "Failed to populate nvm info shadow\n");
			goto err2;
		}
	}

	/* Allocate the init RT array and initialize the init-ops engine */
	rc = qed_init_alloc(p_hwfn);
	if (rc)
		goto err2;
		goto err3;

	return rc;
err3:
	if (IS_LEAD_HWFN(p_hwfn))
		qed_nvm_info_free(p_hwfn);
err2:
	if (IS_LEAD_HWFN(p_hwfn))
		qed_iov_free_hw_info(p_hwfn->cdev);
@@ -3056,6 +3075,7 @@ int qed_hw_prepare(struct qed_dev *cdev,
		if (rc) {
			if (IS_PF(cdev)) {
				qed_init_free(p_hwfn);
				qed_nvm_info_free(p_hwfn);
				qed_mcp_free(p_hwfn);
				qed_hw_hwfn_free(p_hwfn);
			}
@@ -3088,6 +3108,8 @@ void qed_hw_remove(struct qed_dev *cdev)
	}

	qed_iov_free_hw_info(cdev);

	qed_nvm_info_free(p_hwfn);
}

static void qed_chain_free_next_ptr(struct qed_dev *cdev,
+6 −1
Original line number Diff line number Diff line
@@ -12268,8 +12268,11 @@ struct public_drv_mb {
#define DRV_MSG_CODE_VF_DISABLED_DONE		0xc0000000
#define DRV_MSG_CODE_CFG_VF_MSIX		0xc0010000
#define DRV_MSG_CODE_CFG_PF_VFS_MSIX		0xc0020000
#define DRV_MSG_CODE_NVM_PUT_FILE_BEGIN		0x00010000
#define DRV_MSG_CODE_NVM_PUT_FILE_DATA		0x00020000
#define DRV_MSG_CODE_NVM_GET_FILE_ATT		0x00030000
#define DRV_MSG_CODE_NVM_READ_NVRAM		0x00050000
#define DRV_MSG_CODE_NVM_WRITE_NVRAM		0x00060000
#define DRV_MSG_CODE_MCP_RESET			0x00090000
#define DRV_MSG_CODE_SET_VERSION		0x000f0000
#define DRV_MSG_CODE_MCP_HALT                   0x00100000
@@ -12323,7 +12326,6 @@ struct public_drv_mb {

#define DRV_MSG_CODE_FEATURE_SUPPORT		0x00300000
#define DRV_MSG_CODE_GET_MFW_FEATURE_SUPPORT	0x00310000

#define DRV_MSG_SEQ_NUMBER_MASK			0x0000ffff

	u32 drv_mb_param;
@@ -12435,7 +12437,10 @@ struct public_drv_mb {
#define FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE	0xb0010000

#define FW_MSG_CODE_NVM_OK			0x00010000
#define FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK	0x00400000
#define FW_MSG_CODE_PHY_OK			0x00110000
#define FW_MSG_CODE_OK				0x00160000
#define FW_MSG_CODE_ERROR			0x00170000

#define FW_MSG_CODE_OS_WOL_SUPPORTED            0x00800000
#define FW_MSG_CODE_OS_WOL_NOT_SUPPORTED        0x00810000
+338 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include <linux/etherdevice.h>
#include <linux/vmalloc.h>
#include <linux/crash_dump.h>
#include <linux/crc32.h>
#include <linux/qed/qed_if.h>
#include <linux/qed/qed_ll2_if.h>

@@ -1553,6 +1554,342 @@ static int qed_drain(struct qed_dev *cdev)
	return 0;
}

static u32 qed_nvm_flash_image_access_crc(struct qed_dev *cdev,
					  struct qed_nvm_image_att *nvm_image,
					  u32 *crc)
{
	u8 *buf = NULL;
	int rc, j;
	u32 val;

	/* Allocate a buffer for holding the nvram image */
	buf = kzalloc(nvm_image->length, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	/* Read image into buffer */
	rc = qed_mcp_nvm_read(cdev, nvm_image->start_addr,
			      buf, nvm_image->length);
	if (rc) {
		DP_ERR(cdev, "Failed reading image from nvm\n");
		goto out;
	}

	/* Convert the buffer into big-endian format (excluding the
	 * closing 4 bytes of CRC).
	 */
	for (j = 0; j < nvm_image->length - 4; j += 4) {
		val = cpu_to_be32(*(u32 *)&buf[j]);
		*(u32 *)&buf[j] = val;
	}

	/* Calc CRC for the "actual" image buffer, i.e. not including
	 * the last 4 CRC bytes.
	 */
	*crc = (~cpu_to_be32(crc32(0xffffffff, buf, nvm_image->length - 4)));

out:
	kfree(buf);

	return rc;
}

/* Binary file format -
 *     /----------------------------------------------------------------------\
 * 0B  |                       0x4 [command index]                            |
 * 4B  | image_type     | Options        |  Number of register settings       |
 * 8B  |                       Value                                          |
 * 12B |                       Mask                                           |
 * 16B |                       Offset                                         |
 *     \----------------------------------------------------------------------/
 * There can be several Value-Mask-Offset sets as specified by 'Number of...'.
 * Options - 0'b - Calculate & Update CRC for image
 */
static int qed_nvm_flash_image_access(struct qed_dev *cdev, const u8 **data,
				      bool *check_resp)
{
	struct qed_nvm_image_att nvm_image;
	struct qed_hwfn *p_hwfn;
	bool is_crc = false;
	u32 image_type;
	int rc = 0, i;
	u16 len;

	*data += 4;
	image_type = **data;
	p_hwfn = QED_LEADING_HWFN(cdev);
	for (i = 0; i < p_hwfn->nvm_info.num_images; i++)
		if (image_type == p_hwfn->nvm_info.image_att[i].image_type)
			break;
	if (i == p_hwfn->nvm_info.num_images) {
		DP_ERR(cdev, "Failed to find nvram image of type %08x\n",
		       image_type);
		return -ENOENT;
	}

	nvm_image.start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr;
	nvm_image.length = p_hwfn->nvm_info.image_att[i].len;

	DP_VERBOSE(cdev, NETIF_MSG_DRV,
		   "Read image %02x; type = %08x; NVM [%08x,...,%08x]\n",
		   **data, image_type, nvm_image.start_addr,
		   nvm_image.start_addr + nvm_image.length - 1);
	(*data)++;
	is_crc = !!(**data & BIT(0));
	(*data)++;
	len = *((u16 *)*data);
	*data += 2;
	if (is_crc) {
		u32 crc = 0;

		rc = qed_nvm_flash_image_access_crc(cdev, &nvm_image, &crc);
		if (rc) {
			DP_ERR(cdev, "Failed calculating CRC, rc = %d\n", rc);
			goto exit;
		}

		rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM,
				       (nvm_image.start_addr +
					nvm_image.length - 4), (u8 *)&crc, 4);
		if (rc)
			DP_ERR(cdev, "Failed writing to %08x, rc = %d\n",
			       nvm_image.start_addr + nvm_image.length - 4, rc);
		goto exit;
	}

	/* Iterate over the values for setting */
	while (len) {
		u32 offset, mask, value, cur_value;
		u8 buf[4];

		value = *((u32 *)*data);
		*data += 4;
		mask = *((u32 *)*data);
		*data += 4;
		offset = *((u32 *)*data);
		*data += 4;

		rc = qed_mcp_nvm_read(cdev, nvm_image.start_addr + offset, buf,
				      4);
		if (rc) {
			DP_ERR(cdev, "Failed reading from %08x\n",
			       nvm_image.start_addr + offset);
			goto exit;
		}

		cur_value = le32_to_cpu(*((__le32 *)buf));
		DP_VERBOSE(cdev, NETIF_MSG_DRV,
			   "NVM %08x: %08x -> %08x [Value %08x Mask %08x]\n",
			   nvm_image.start_addr + offset, cur_value,
			   (cur_value & ~mask) | (value & mask), value, mask);
		value = (value & mask) | (cur_value & ~mask);
		rc = qed_mcp_nvm_write(cdev, QED_NVM_WRITE_NVRAM,
				       nvm_image.start_addr + offset,
				       (u8 *)&value, 4);
		if (rc) {
			DP_ERR(cdev, "Failed writing to %08x\n",
			       nvm_image.start_addr + offset);
			goto exit;
		}

		len--;
	}
exit:
	return rc;
}

/* Binary file format -
 *     /----------------------------------------------------------------------\
 * 0B  |                       0x3 [command index]                            |
 * 4B  | b'0: check_response?   | b'1-31  reserved                            |
 * 8B  | File-type |                   reserved                               |
 *     \----------------------------------------------------------------------/
 *     Start a new file of the provided type
 */
static int qed_nvm_flash_image_file_start(struct qed_dev *cdev,
					  const u8 **data, bool *check_resp)
{
	int rc;

	*data += 4;
	*check_resp = !!(**data & BIT(0));
	*data += 4;

	DP_VERBOSE(cdev, NETIF_MSG_DRV,
		   "About to start a new file of type %02x\n", **data);
	rc = qed_mcp_nvm_put_file_begin(cdev, **data);
	*data += 4;

	return rc;
}

/* Binary file format -
 *     /----------------------------------------------------------------------\
 * 0B  |                       0x2 [command index]                            |
 * 4B  |                       Length in bytes                                |
 * 8B  | b'0: check_response?   | b'1-31  reserved                            |
 * 12B |                       Offset in bytes                                |
 * 16B |                       Data ...                                       |
 *     \----------------------------------------------------------------------/
 *     Write data as part of a file that was previously started. Data should be
 *     of length equal to that provided in the message
 */
static int qed_nvm_flash_image_file_data(struct qed_dev *cdev,
					 const u8 **data, bool *check_resp)
{
	u32 offset, len;
	int rc;

	*data += 4;
	len = *((u32 *)(*data));
	*data += 4;
	*check_resp = !!(**data & BIT(0));
	*data += 4;
	offset = *((u32 *)(*data));
	*data += 4;

	DP_VERBOSE(cdev, NETIF_MSG_DRV,
		   "About to write File-data: %08x bytes to offset %08x\n",
		   len, offset);

	rc = qed_mcp_nvm_write(cdev, QED_PUT_FILE_DATA, offset,
			       (char *)(*data), len);
	*data += len;

	return rc;
}

/* Binary file format [General header] -
 *     /----------------------------------------------------------------------\
 * 0B  |                       QED_NVM_SIGNATURE                              |
 * 4B  |                       Length in bytes                                |
 * 8B  | Highest command in this batchfile |          Reserved                |
 *     \----------------------------------------------------------------------/
 */
static int qed_nvm_flash_image_validate(struct qed_dev *cdev,
					const struct firmware *image,
					const u8 **data)
{
	u32 signature, len;

	/* Check minimum size */
	if (image->size < 12) {
		DP_ERR(cdev, "Image is too short [%08x]\n", (u32)image->size);
		return -EINVAL;
	}

	/* Check signature */
	signature = *((u32 *)(*data));
	if (signature != QED_NVM_SIGNATURE) {
		DP_ERR(cdev, "Wrong signature '%08x'\n", signature);
		return -EINVAL;
	}

	*data += 4;
	/* Validate internal size equals the image-size */
	len = *((u32 *)(*data));
	if (len != image->size) {
		DP_ERR(cdev, "Size mismatch: internal = %08x image = %08x\n",
		       len, (u32)image->size);
		return -EINVAL;
	}

	*data += 4;
	/* Make sure driver familiar with all commands necessary for this */
	if (*((u16 *)(*data)) >= QED_NVM_FLASH_CMD_NVM_MAX) {
		DP_ERR(cdev, "File contains unsupported commands [Need %04x]\n",
		       *((u16 *)(*data)));
		return -EINVAL;
	}

	*data += 4;

	return 0;
}

static int qed_nvm_flash(struct qed_dev *cdev, const char *name)
{
	const struct firmware *image;
	const u8 *data, *data_end;
	u32 cmd_type;
	int rc;

	rc = request_firmware(&image, name, &cdev->pdev->dev);
	if (rc) {
		DP_ERR(cdev, "Failed to find '%s'\n", name);
		return rc;
	}

	DP_VERBOSE(cdev, NETIF_MSG_DRV,
		   "Flashing '%s' - firmware's data at %p, size is %08x\n",
		   name, image->data, (u32)image->size);
	data = image->data;
	data_end = data + image->size;

	rc = qed_nvm_flash_image_validate(cdev, image, &data);
	if (rc)
		goto exit;

	while (data < data_end) {
		bool check_resp = false;

		/* Parse the actual command */
		cmd_type = *((u32 *)data);
		switch (cmd_type) {
		case QED_NVM_FLASH_CMD_FILE_DATA:
			rc = qed_nvm_flash_image_file_data(cdev, &data,
							   &check_resp);
			break;
		case QED_NVM_FLASH_CMD_FILE_START:
			rc = qed_nvm_flash_image_file_start(cdev, &data,
							    &check_resp);
			break;
		case QED_NVM_FLASH_CMD_NVM_CHANGE:
			rc = qed_nvm_flash_image_access(cdev, &data,
							&check_resp);
			break;
		default:
			DP_ERR(cdev, "Unknown command %08x\n", cmd_type);
			rc = -EINVAL;
			goto exit;
		}

		if (rc) {
			DP_ERR(cdev, "Command %08x failed\n", cmd_type);
			goto exit;
		}

		/* Check response if needed */
		if (check_resp) {
			u32 mcp_response = 0;

			if (qed_mcp_nvm_resp(cdev, (u8 *)&mcp_response)) {
				DP_ERR(cdev, "Failed getting MCP response\n");
				rc = -EINVAL;
				goto exit;
			}

			switch (mcp_response & FW_MSG_CODE_MASK) {
			case FW_MSG_CODE_OK:
			case FW_MSG_CODE_NVM_OK:
			case FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK:
			case FW_MSG_CODE_PHY_OK:
				break;
			default:
				DP_ERR(cdev, "MFW returns error: %08x\n",
				       mcp_response);
				rc = -EINVAL;
				goto exit;
			}
		}
	}

exit:
	release_firmware(image);

	return rc;
}

static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type,
			     u8 *buf, u16 len)
{
@@ -1719,6 +2056,7 @@ const struct qed_common_ops qed_common_ops_pass = {
	.dbg_all_data_size = &qed_dbg_all_data_size,
	.chain_alloc = &qed_chain_alloc,
	.chain_free = &qed_chain_free,
	.nvm_flash = &qed_nvm_flash,
	.nvm_get_image = &qed_nvm_get_image,
	.set_coalesce = &qed_set_coalesce,
	.set_led = &qed_set_led,
+192 −27
Original line number Diff line number Diff line
@@ -569,6 +569,31 @@ int qed_mcp_cmd(struct qed_hwfn *p_hwfn,
	return 0;
}

int qed_mcp_nvm_wr_cmd(struct qed_hwfn *p_hwfn,
		       struct qed_ptt *p_ptt,
		       u32 cmd,
		       u32 param,
		       u32 *o_mcp_resp,
		       u32 *o_mcp_param, u32 i_txn_size, u32 *i_buf)
{
	struct qed_mcp_mb_params mb_params;
	int rc;

	memset(&mb_params, 0, sizeof(mb_params));
	mb_params.cmd = cmd;
	mb_params.param = param;
	mb_params.p_data_src = i_buf;
	mb_params.data_src_size = (u8)i_txn_size;
	rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
	if (rc)
		return rc;

	*o_mcp_resp = mb_params.mcp_resp;
	*o_mcp_param = mb_params.mcp_param;

	return 0;
}

int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn,
		       struct qed_ptt *p_ptt,
		       u32 cmd,
@@ -2261,6 +2286,102 @@ int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len)
	return rc;
}

int qed_mcp_nvm_resp(struct qed_dev *cdev, u8 *p_buf)
{
	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
	struct qed_ptt *p_ptt;

	p_ptt = qed_ptt_acquire(p_hwfn);
	if (!p_ptt)
		return -EBUSY;

	memcpy(p_buf, &cdev->mcp_nvm_resp, sizeof(cdev->mcp_nvm_resp));
	qed_ptt_release(p_hwfn, p_ptt);

	return 0;
}

int qed_mcp_nvm_put_file_begin(struct qed_dev *cdev, u32 addr)
{
	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
	struct qed_ptt *p_ptt;
	u32 resp, param;
	int rc;

	p_ptt = qed_ptt_acquire(p_hwfn);
	if (!p_ptt)
		return -EBUSY;
	rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_NVM_PUT_FILE_BEGIN, addr,
			 &resp, &param);
	cdev->mcp_nvm_resp = resp;
	qed_ptt_release(p_hwfn, p_ptt);

	return rc;
}

int qed_mcp_nvm_write(struct qed_dev *cdev,
		      u32 cmd, u32 addr, u8 *p_buf, u32 len)
{
	u32 buf_idx = 0, buf_size, nvm_cmd, nvm_offset, resp = 0, param;
	struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
	struct qed_ptt *p_ptt;
	int rc = -EINVAL;

	p_ptt = qed_ptt_acquire(p_hwfn);
	if (!p_ptt)
		return -EBUSY;

	switch (cmd) {
	case QED_PUT_FILE_DATA:
		nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_DATA;
		break;
	case QED_NVM_WRITE_NVRAM:
		nvm_cmd = DRV_MSG_CODE_NVM_WRITE_NVRAM;
		break;
	default:
		DP_NOTICE(p_hwfn, "Invalid nvm write command 0x%x\n", cmd);
		rc = -EINVAL;
		goto out;
	}

	while (buf_idx < len) {
		buf_size = min_t(u32, (len - buf_idx), MCP_DRV_NVM_BUF_LEN);
		nvm_offset = ((buf_size << DRV_MB_PARAM_NVM_LEN_OFFSET) |
			      addr) + buf_idx;
		rc = qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, nvm_cmd, nvm_offset,
					&resp, &param, buf_size,
					(u32 *)&p_buf[buf_idx]);
		if (rc) {
			DP_NOTICE(cdev, "nvm write failed, rc = %d\n", rc);
			resp = FW_MSG_CODE_ERROR;
			break;
		}

		if (resp != FW_MSG_CODE_OK &&
		    resp != FW_MSG_CODE_NVM_OK &&
		    resp != FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK) {
			DP_NOTICE(cdev,
				  "nvm write failed, resp = 0x%08x\n", resp);
			rc = -EINVAL;
			break;
		}

		/* This can be a lengthy process, and it's possible scheduler
		 * isn't pre-emptable. Sleep a bit to prevent CPU hogging.
		 */
		if (buf_idx % 0x1000 > (buf_idx + buf_size) % 0x1000)
			usleep_range(1000, 2000);

		buf_idx += buf_size;
	}

	cdev->mcp_nvm_resp = resp;
out:
	qed_ptt_release(p_hwfn, p_ptt);

	return rc;
}

int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
	u32 drv_mb_param = 0, rsp, param;
@@ -2303,7 +2424,7 @@ int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
	return rc;
}

int qed_mcp_bist_nvm_test_get_num_images(struct qed_hwfn *p_hwfn,
int qed_mcp_bist_nvm_get_num_images(struct qed_hwfn *p_hwfn,
				    struct qed_ptt *p_ptt,
				    u32 *num_images)
{
@@ -2324,7 +2445,7 @@ int qed_mcp_bist_nvm_test_get_num_images(struct qed_hwfn *p_hwfn,
	return rc;
}

int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn,
int qed_mcp_bist_nvm_get_image_att(struct qed_hwfn *p_hwfn,
				   struct qed_ptt *p_ptt,
				   struct bist_nvm_image_att *p_image_att,
				   u32 image_index)
@@ -2351,16 +2472,71 @@ int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn,
	return rc;
}

int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn)
{
	struct qed_nvm_image_info *nvm_info = &p_hwfn->nvm_info;
	struct qed_ptt *p_ptt;
	int rc;
	u32 i;

	p_ptt = qed_ptt_acquire(p_hwfn);
	if (!p_ptt) {
		DP_ERR(p_hwfn, "failed to acquire ptt\n");
		return -EBUSY;
	}

	/* Acquire from MFW the amount of available images */
	nvm_info->num_images = 0;
	rc = qed_mcp_bist_nvm_get_num_images(p_hwfn,
					     p_ptt, &nvm_info->num_images);
	if (rc == -EOPNOTSUPP) {
		DP_INFO(p_hwfn, "DRV_MSG_CODE_BIST_TEST is not supported\n");
		goto out;
	} else if (rc || !nvm_info->num_images) {
		DP_ERR(p_hwfn, "Failed getting number of images\n");
		goto err0;
	}

	nvm_info->image_att = kmalloc(nvm_info->num_images *
				      sizeof(struct bist_nvm_image_att),
				      GFP_KERNEL);
	if (!nvm_info->image_att) {
		rc = -ENOMEM;
		goto err0;
	}

	/* Iterate over images and get their attributes */
	for (i = 0; i < nvm_info->num_images; i++) {
		rc = qed_mcp_bist_nvm_get_image_att(p_hwfn, p_ptt,
						    &nvm_info->image_att[i], i);
		if (rc) {
			DP_ERR(p_hwfn,
			       "Failed getting image index %d attributes\n", i);
			goto err1;
		}

		DP_VERBOSE(p_hwfn, QED_MSG_SP, "image index %d, size %x\n", i,
			   nvm_info->image_att[i].len);
	}
out:
	qed_ptt_release(p_hwfn, p_ptt);
	return 0;

err1:
	kfree(nvm_info->image_att);
err0:
	qed_ptt_release(p_hwfn, p_ptt);
	return rc;
}

static int
qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn,
			  struct qed_ptt *p_ptt,
			  enum qed_nvm_images image_id,
			  struct qed_nvm_image_att *p_image_att)
{
	struct bist_nvm_image_att mfw_image_att;
	enum nvm_image_type type;
	u32 num_images, i;
	int rc;
	u32 i;

	/* Translate image_id into MFW definitions */
	switch (image_id) {
@@ -2376,29 +2552,18 @@ qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn,
		return -EINVAL;
	}

	/* Learn number of images, then traverse and see if one fits */
	rc = qed_mcp_bist_nvm_test_get_num_images(p_hwfn, p_ptt, &num_images);
	if (rc || !num_images)
		return -EINVAL;

	for (i = 0; i < num_images; i++) {
		rc = qed_mcp_bist_nvm_test_get_image_att(p_hwfn, p_ptt,
							 &mfw_image_att, i);
		if (rc)
			return rc;

		if (type == mfw_image_att.image_type)
	for (i = 0; i < p_hwfn->nvm_info.num_images; i++)
		if (type == p_hwfn->nvm_info.image_att[i].image_type)
			break;
	}
	if (i == num_images) {
	if (i == p_hwfn->nvm_info.num_images) {
		DP_VERBOSE(p_hwfn, QED_MSG_STORAGE,
			   "Failed to find nvram image of type %08x\n",
			   image_id);
		return -EINVAL;
		return -ENOENT;
	}

	p_image_att->start_addr = mfw_image_att.nvm_start_addr;
	p_image_att->length = mfw_image_att.len;
	p_image_att->start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr;
	p_image_att->length = p_hwfn->nvm_info.image_att[i].len;

	return 0;
}
Loading