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

Commit 900a6596 authored by Dimitris Michailidis's avatar Dimitris Michailidis Committed by David S. Miller
Browse files

cxgb4: dynamically determine flash size and FW image location



Handle the larger flash memories on newer boards:

- get the size and number of sectors by probing the flash
- writes and erases can take longer, adjust the timeouts for these operations
- the FW image can be at different locations depending on flash size,
  find its location dynamically as well.

Signed-off-by: default avatarDimitris Michailidis <dm@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bb9c03d8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -219,6 +219,10 @@ struct adapter_params {
	struct vpd_params vpd;
	struct pci_params pci;

	unsigned int sf_size;             /* serial flash size in bytes */
	unsigned int sf_nsec;             /* # of flash sectors */
	unsigned int sf_fw_start;         /* start of FW image in flash */

	unsigned int fw_vers;
	unsigned int tp_vers;
	u8 api_vers[7];
+54 −21
Original line number Diff line number Diff line
@@ -449,12 +449,10 @@ enum {
	SF_RD_STATUS    = 5,          /* read status register */
	SF_WR_ENABLE    = 6,          /* enable writes */
	SF_RD_DATA_FAST = 0xb,        /* read flash */
	SF_RD_ID        = 0x9f,       /* read ID */
	SF_ERASE_SECTOR = 0xd8,       /* erase sector */

	FW_START_SEC = 8,             /* first flash sector for FW */
	FW_END_SEC = 15,              /* last flash sector for FW */
	FW_IMG_START = FW_START_SEC * SF_SEC_SIZE,
	FW_MAX_SIZE = (FW_END_SEC - FW_START_SEC + 1) * SF_SEC_SIZE,
	FW_MAX_SIZE = 512 * 1024,
};

/**
@@ -558,7 +556,7 @@ static int t4_read_flash(struct adapter *adapter, unsigned int addr,
{
	int ret;

	if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
	if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3))
		return -EINVAL;

	addr = swab32(addr) | SF_RD_DATA_FAST;
@@ -596,7 +594,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr,
	u32 buf[64];
	unsigned int i, c, left, val, offset = addr & 0xff;

	if (addr >= SF_SIZE || offset + n > SF_PAGE_SIZE)
	if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE)
		return -EINVAL;

	val = swab32(addr) | SF_PROG_PAGE;
@@ -614,7 +612,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr,
		if (ret)
			goto unlock;
	}
	ret = flash_wait_op(adapter, 5, 1);
	ret = flash_wait_op(adapter, 8, 1);
	if (ret)
		goto unlock;

@@ -647,9 +645,8 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr,
 */
static int get_fw_version(struct adapter *adapter, u32 *vers)
{
	return t4_read_flash(adapter,
			     FW_IMG_START + offsetof(struct fw_hdr, fw_ver), 1,
			     vers, 0);
	return t4_read_flash(adapter, adapter->params.sf_fw_start +
			     offsetof(struct fw_hdr, fw_ver), 1, vers, 0);
}

/**
@@ -661,8 +658,8 @@ static int get_fw_version(struct adapter *adapter, u32 *vers)
 */
static int get_tp_version(struct adapter *adapter, u32 *vers)
{
	return t4_read_flash(adapter, FW_IMG_START + offsetof(struct fw_hdr,
							      tp_microcode_ver),
	return t4_read_flash(adapter, adapter->params.sf_fw_start +
			     offsetof(struct fw_hdr, tp_microcode_ver),
			     1, vers, 0);
}

@@ -684,8 +681,8 @@ int t4_check_fw_version(struct adapter *adapter)
	if (!ret)
		ret = get_tp_version(adapter, &adapter->params.tp_vers);
	if (!ret)
		ret = t4_read_flash(adapter,
			FW_IMG_START + offsetof(struct fw_hdr, intfver_nic),
		ret = t4_read_flash(adapter, adapter->params.sf_fw_start +
				    offsetof(struct fw_hdr, intfver_nic),
				    2, api_vers, 1);
	if (ret)
		return ret;
@@ -726,7 +723,7 @@ static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
		if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 ||
		    (ret = sf1_write(adapter, 4, 0, 1,
				     SF_ERASE_SECTOR | (start << 8))) != 0 ||
		    (ret = flash_wait_op(adapter, 5, 500)) != 0) {
		    (ret = flash_wait_op(adapter, 14, 500)) != 0) {
			dev_err(adapter->pdev_dev,
				"erase of flash sector %d failed, error %d\n",
				start, ret);
@@ -754,6 +751,9 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
	u8 first_page[SF_PAGE_SIZE];
	const u32 *p = (const u32 *)fw_data;
	const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data;
	unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
	unsigned int fw_img_start = adap->params.sf_fw_start;
	unsigned int fw_start_sec = fw_img_start / sf_sec_size;

	if (!size) {
		dev_err(adap->pdev_dev, "FW image has no data\n");
@@ -784,8 +784,8 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
		return -EINVAL;
	}

	i = DIV_ROUND_UP(size, SF_SEC_SIZE);        /* # of sectors spanned */
	ret = t4_flash_erase_sectors(adap, FW_START_SEC, FW_START_SEC + i - 1);
	i = DIV_ROUND_UP(size, sf_sec_size);        /* # of sectors spanned */
	ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1);
	if (ret)
		goto out;

@@ -796,11 +796,11 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
	 */
	memcpy(first_page, fw_data, SF_PAGE_SIZE);
	((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff);
	ret = t4_write_flash(adap, FW_IMG_START, SF_PAGE_SIZE, first_page);
	ret = t4_write_flash(adap, fw_img_start, SF_PAGE_SIZE, first_page);
	if (ret)
		goto out;

	addr = FW_IMG_START;
	addr = fw_img_start;
	for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
		addr += SF_PAGE_SIZE;
		fw_data += SF_PAGE_SIZE;
@@ -810,7 +810,7 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
	}

	ret = t4_write_flash(adap,
			     FW_IMG_START + offsetof(struct fw_hdr, fw_ver),
			     fw_img_start + offsetof(struct fw_hdr, fw_ver),
			     sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver);
out:
	if (ret)
@@ -3053,6 +3053,33 @@ static int __devinit wait_dev_ready(struct adapter *adap)
	return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO;
}

static int __devinit get_flash_params(struct adapter *adap)
{
	int ret;
	u32 info;

	ret = sf1_write(adap, 1, 1, 0, SF_RD_ID);
	if (!ret)
		ret = sf1_read(adap, 3, 0, 1, &info);
	t4_write_reg(adap, SF_OP, 0);                    /* unlock SF */
	if (ret)
		return ret;

	if ((info & 0xff) != 0x20)             /* not a Numonix flash */
		return -EINVAL;
	info >>= 16;                           /* log2 of size */
	if (info >= 0x14 && info < 0x18)
		adap->params.sf_nsec = 1 << (info - 16);
	else if (info == 0x18)
		adap->params.sf_nsec = 64;
	else
		return -EINVAL;
	adap->params.sf_size = 1 << info;
	adap->params.sf_fw_start =
		t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK;
	return 0;
}

/**
 *	t4_prep_adapter - prepare SW and HW for operation
 *	@adapter: the adapter
@@ -3073,6 +3100,12 @@ int __devinit t4_prep_adapter(struct adapter *adapter)
	get_pci_mode(adapter, &adapter->params.pci);
	adapter->params.rev = t4_read_reg(adapter, PL_REV);

	ret = get_flash_params(adapter);
	if (ret < 0) {
		dev_err(adapter->pdev_dev, "error %d identifying flash\n", ret);
		return ret;
	}

	ret = get_vpd_params(adapter, &adapter->params.vpd);
	if (ret < 0)
		return ret;
+0 −2
Original line number Diff line number Diff line
@@ -57,8 +57,6 @@ enum {

enum {
	SF_PAGE_SIZE = 256,           /* serial flash page size */
	SF_SEC_SIZE = 64 * 1024,      /* serial flash sector size */
	SF_SIZE = SF_SEC_SIZE * 16,   /* serial flash size */
};

enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */
+3 −0
Original line number Diff line number Diff line
@@ -326,6 +326,9 @@

#define EDC_1_BASE_ADDR 0x7980

#define CIM_BOOT_CFG 0x7b00
#define  BOOTADDR_MASK 0xffffff00U

#define CIM_PF_MAILBOX_DATA 0x240
#define CIM_PF_MAILBOX_CTRL 0x280
#define  MBMSGVALID     0x00000008U