Commit 5fb1beec authored by Bert Kenward's avatar Bert Kenward Committed by David S. Miller
Browse files

sfc: extend MTD support for newer hardware



The X2 family of NICs (based on the SFC9250) have additional
MTD partitions for firmware and configuration. This includes
partitions that are read-only.

The NICs also have extended versions of the NVRAM interface,
allowing more detailed status information to be returned.

Signed-off-by: default avatarBert Kenward <bkenward@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cea3bfb3
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -6041,10 +6041,11 @@ static const struct efx_ef10_nvram_type_info efx_ef10_nvram_types[] = {
	{ NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 0,   3, "sfc_exp_rom_cfg" },
	{ NVRAM_PARTITION_TYPE_LICENSE,		   0,    0, "sfc_license" },
	{ NVRAM_PARTITION_TYPE_PHY_MIN,		   0xff, 0, "sfc_phy_fw" },
	/* MUM and SUC firmware share the same partition type */
	{ NVRAM_PARTITION_TYPE_MUM_FIRMWARE,	   0,    0, "sfc_mumfw" },
	{ NVRAM_PARTITION_TYPE_EXPANSION_UEFI,	   0,    0, "sfc_uefi" },
	{ NVRAM_PARTITION_TYPE_STATUS,		   0,    0, "sfc_status" }
	{ NVRAM_PARTITION_TYPE_DYNCONFIG_DEFAULTS, 0,    0, "sfc_dynamic_cfg_dflt" },
	{ NVRAM_PARTITION_TYPE_ROMCONFIG_DEFAULTS, 0,    0, "sfc_exp_rom_cfg_dflt" },
	{ NVRAM_PARTITION_TYPE_STATUS,		   0,    0, "sfc_status" },
};

static int efx_ef10_mtd_probe_partition(struct efx_nic *efx,
@@ -6071,8 +6072,15 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx,
	rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected);
	if (rc)
		return rc;
	if (protected &&
	    (type != NVRAM_PARTITION_TYPE_DYNCONFIG_DEFAULTS &&
	     type != NVRAM_PARTITION_TYPE_ROMCONFIG_DEFAULTS))
		/* Hide protected partitions that don't provide defaults. */
		return -ENODEV;

	if (protected)
		return -ENODEV; /* hide it */
		/* Protected partitions are read only. */
		erase_size = 0;

	part->nvram_type = type;

+49 −7
Original line number Diff line number Diff line
@@ -2074,22 +2074,26 @@ fail:

static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
{
	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_IN_LEN);
	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN);
	int rc;

	MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type);
	MCDI_POPULATE_DWORD_1(inbuf, NVRAM_UPDATE_START_V2_IN_FLAGS,
			      NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT,
			      1);

	BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0);

	rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf),
			  NULL, 0, NULL);

	return rc;
}

static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
			       loff_t offset, u8 *buffer, size_t length)
{
	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_LEN);
	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_V2_LEN);
	MCDI_DECLARE_BUF(outbuf,
			 MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX));
	size_t outlen;
@@ -2098,6 +2102,8 @@ static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
	MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type);
	MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset);
	MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length);
	MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_V2_MODE,
		       MC_CMD_NVRAM_READ_IN_V2_DEFAULT);

	rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf),
			  outbuf, sizeof(outbuf), &outlen);
@@ -2147,15 +2153,51 @@ static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,

static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
{
	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN);
	int rc;
	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN);
	MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN);
	size_t outlen;
	int rc, rc2;

	MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type);

	BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0);
	/* Always set this flag. Old firmware ignores it */
	MCDI_POPULATE_DWORD_1(inbuf, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
			      NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT,
			      1);

	rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
			  NULL, 0, NULL);
			  outbuf, sizeof(outbuf), &outlen);
	if (!rc && outlen >= MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
		rc2 = MCDI_DWORD(outbuf, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
		if (rc2 != MC_CMD_NVRAM_VERIFY_RC_SUCCESS)
			netif_err(efx, drv, efx->net_dev,
				  "NVRAM update failed verification with code 0x%x\n",
				  rc2);
		switch (rc2) {
		case MC_CMD_NVRAM_VERIFY_RC_SUCCESS:
			break;
		case MC_CMD_NVRAM_VERIFY_RC_CMS_CHECK_FAILED:
		case MC_CMD_NVRAM_VERIFY_RC_MESSAGE_DIGEST_CHECK_FAILED:
		case MC_CMD_NVRAM_VERIFY_RC_SIGNATURE_CHECK_FAILED:
		case MC_CMD_NVRAM_VERIFY_RC_TRUSTED_APPROVERS_CHECK_FAILED:
		case MC_CMD_NVRAM_VERIFY_RC_SIGNATURE_CHAIN_CHECK_FAILED:
			rc = -EIO;
			break;
		case MC_CMD_NVRAM_VERIFY_RC_INVALID_CMS_FORMAT:
		case MC_CMD_NVRAM_VERIFY_RC_BAD_MESSAGE_DIGEST:
			rc = -EINVAL;
			break;
		case MC_CMD_NVRAM_VERIFY_RC_NO_VALID_SIGNATURES:
		case MC_CMD_NVRAM_VERIFY_RC_NO_TRUSTED_APPROVERS:
		case MC_CMD_NVRAM_VERIFY_RC_NO_SIGNATURE_MATCH:
			rc = -EPERM;
			break;
		default:
			netif_err(efx, drv, efx->net_dev,
				  "Unknown response to NVRAM_UPDATE_FINISH\n");
			rc = -EIO;
		}
	}

	return rc;
}

+3 −0
Original line number Diff line number Diff line
@@ -66,6 +66,9 @@ int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts,

		part->mtd.writesize = 1;

		if (!(part->mtd.flags & MTD_NO_ERASE))
			part->mtd.flags |= MTD_WRITEABLE;

		part->mtd.owner = THIS_MODULE;
		part->mtd.priv = efx;
		part->mtd.name = part->name;