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

Commit 9f605acf authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bna'



Rasesh Mody says:

====================
bna: Update the Driver to v3.2.23.0

This patch set consists of feature additions like s/w timestamping support,
multi-buffer RX, firmware patch simplification, enhancements for RX filters,
RX processing changes, bug fixes and updates the firmware version to v3.2.3.0.
The patch set addressed the review commnets recieved.

This patch set updates the BNA driver to v3.2.23.0 and was tested against
net-next 3.12.0-rc6 kernel.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e3fec2f7 ae01320c
Loading
Loading
Loading
Loading
+611 −39
Original line number Diff line number Diff line
@@ -22,6 +22,14 @@

/* IOC local definitions */

#define bfa_ioc_state_disabled(__sm)			\
	(((__sm) == BFI_IOC_UNINIT) ||			\
	 ((__sm) == BFI_IOC_INITING) ||			\
	 ((__sm) == BFI_IOC_HWINIT) ||			\
	 ((__sm) == BFI_IOC_DISABLED) ||		\
	 ((__sm) == BFI_IOC_FAIL) ||			\
	 ((__sm) == BFI_IOC_CFG_DISABLED))

/* Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details. */

#define bfa_ioc_firmware_lock(__ioc)			\
@@ -42,6 +50,14 @@
			((__ioc)->ioc_hwif->ioc_sync_ack(__ioc))
#define bfa_ioc_sync_complete(__ioc)			\
			((__ioc)->ioc_hwif->ioc_sync_complete(__ioc))
#define bfa_ioc_set_cur_ioc_fwstate(__ioc, __fwstate)		\
			((__ioc)->ioc_hwif->ioc_set_fwstate(__ioc, __fwstate))
#define bfa_ioc_get_cur_ioc_fwstate(__ioc)		\
			((__ioc)->ioc_hwif->ioc_get_fwstate(__ioc))
#define bfa_ioc_set_alt_ioc_fwstate(__ioc, __fwstate)		\
		((__ioc)->ioc_hwif->ioc_set_alt_fwstate(__ioc, __fwstate))
#define bfa_ioc_get_alt_ioc_fwstate(__ioc)		\
			((__ioc)->ioc_hwif->ioc_get_alt_fwstate(__ioc))

#define bfa_ioc_mbox_cmd_pending(__ioc)		\
			(!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \
@@ -76,8 +92,8 @@ static void bfa_ioc_pf_disabled(struct bfa_ioc *ioc);
static void bfa_ioc_pf_failed(struct bfa_ioc *ioc);
static void bfa_ioc_pf_hwfailed(struct bfa_ioc *ioc);
static void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc);
static void bfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type,
			 u32 boot_param);
static enum bfa_status bfa_ioc_boot(struct bfa_ioc *ioc,
			enum bfi_fwboot_type boot_type, u32 boot_param);
static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr);
static void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc,
						char *serial_num);
@@ -860,7 +876,7 @@ bfa_iocpf_sm_disabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
		 */

	case IOCPF_E_TIMEOUT:
		writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
		break;

@@ -949,7 +965,7 @@ bfa_iocpf_sm_initfail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
	case IOCPF_E_SEMLOCKED:
		bfa_ioc_notify_fail(ioc);
		bfa_ioc_sync_leave(ioc);
		writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
		bfa_nw_ioc_hw_sem_release(ioc);
		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
		break;
@@ -1031,7 +1047,7 @@ bfa_iocpf_sm_fail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
		bfa_ioc_notify_fail(ioc);
		if (!iocpf->auto_recover) {
			bfa_ioc_sync_leave(ioc);
			writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate);
			bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
			bfa_nw_ioc_hw_sem_release(ioc);
			bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
		} else {
@@ -1131,6 +1147,25 @@ bfa_nw_ioc_sem_release(void __iomem *sem_reg)
	writel(1, sem_reg);
}

/* Invalidate fwver signature */
enum bfa_status
bfa_nw_ioc_fwsig_invalidate(struct bfa_ioc *ioc)
{
	u32	pgnum, pgoff;
	u32	loff = 0;
	enum bfi_ioc_state ioc_fwstate;

	ioc_fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
	if (!bfa_ioc_state_disabled(ioc_fwstate))
		return BFA_STATUS_ADAPTER_ENABLED;

	pgnum = bfa_ioc_smem_pgnum(ioc, loff);
	pgoff = PSS_SMEM_PGOFF(loff);
	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
	writel(BFI_IOC_FW_INV_SIGN, ioc->ioc_regs.smem_page_start + loff);
	return BFA_STATUS_OK;
}

/* Clear fwver hdr */
static void
bfa_ioc_fwver_clear(struct bfa_ioc *ioc)
@@ -1162,7 +1197,7 @@ bfa_ioc_hw_sem_init(struct bfa_ioc *ioc)
		r32 = readl(ioc->ioc_regs.ioc_init_sem_reg);
	}

	fwstate = readl(ioc->ioc_regs.ioc_fwstate);
	fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
	if (fwstate == BFI_IOC_UNINIT) {
		writel(1, ioc->ioc_regs.ioc_init_sem_reg);
		return;
@@ -1176,8 +1211,8 @@ bfa_ioc_hw_sem_init(struct bfa_ioc *ioc)
	}

	bfa_ioc_fwver_clear(ioc);
	writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate);
	writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate);
	bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_UNINIT);
	bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_UNINIT);

	/*
	 * Try to lock and then unlock the semaphore.
@@ -1309,22 +1344,510 @@ bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
	}
}

/* Returns TRUE if same. */
static bool
bfa_ioc_fwver_md5_check(struct bfi_ioc_image_hdr *fwhdr_1,
			struct bfi_ioc_image_hdr *fwhdr_2)
{
	int i;

	for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
		if (fwhdr_1->md5sum[i] != fwhdr_2->md5sum[i])
			return false;
	}

	return true;
}

/* Returns TRUE if major minor and maintainence are same.
 * If patch version are same, check for MD5 Checksum to be same.
 */
static bool
bfa_ioc_fw_ver_compatible(struct bfi_ioc_image_hdr *drv_fwhdr,
			  struct bfi_ioc_image_hdr *fwhdr_to_cmp)
{
	if (drv_fwhdr->signature != fwhdr_to_cmp->signature)
		return false;
	if (drv_fwhdr->fwver.major != fwhdr_to_cmp->fwver.major)
		return false;
	if (drv_fwhdr->fwver.minor != fwhdr_to_cmp->fwver.minor)
		return false;
	if (drv_fwhdr->fwver.maint != fwhdr_to_cmp->fwver.maint)
		return false;
	if (drv_fwhdr->fwver.patch == fwhdr_to_cmp->fwver.patch &&
	    drv_fwhdr->fwver.phase == fwhdr_to_cmp->fwver.phase &&
	    drv_fwhdr->fwver.build == fwhdr_to_cmp->fwver.build)
		return bfa_ioc_fwver_md5_check(drv_fwhdr, fwhdr_to_cmp);

	return true;
}

static bool
bfa_ioc_flash_fwver_valid(struct bfi_ioc_image_hdr *flash_fwhdr)
{
	if (flash_fwhdr->fwver.major == 0 || flash_fwhdr->fwver.major == 0xFF)
		return false;

	return true;
}

static bool
fwhdr_is_ga(struct bfi_ioc_image_hdr *fwhdr)
{
	if (fwhdr->fwver.phase == 0 &&
	    fwhdr->fwver.build == 0)
		return false;

	return true;
}

/* Returns TRUE if both are compatible and patch of fwhdr_to_cmp is better. */
static enum bfi_ioc_img_ver_cmp
bfa_ioc_fw_ver_patch_cmp(struct bfi_ioc_image_hdr *base_fwhdr,
			 struct bfi_ioc_image_hdr *fwhdr_to_cmp)
{
	if (bfa_ioc_fw_ver_compatible(base_fwhdr, fwhdr_to_cmp) == false)
		return BFI_IOC_IMG_VER_INCOMP;

	if (fwhdr_to_cmp->fwver.patch > base_fwhdr->fwver.patch)
		return BFI_IOC_IMG_VER_BETTER;
	else if (fwhdr_to_cmp->fwver.patch < base_fwhdr->fwver.patch)
		return BFI_IOC_IMG_VER_OLD;

	/* GA takes priority over internal builds of the same patch stream.
	 * At this point major minor maint and patch numbers are same.
	 */
	if (fwhdr_is_ga(base_fwhdr) == true)
		if (fwhdr_is_ga(fwhdr_to_cmp))
			return BFI_IOC_IMG_VER_SAME;
		else
			return BFI_IOC_IMG_VER_OLD;
	else
		if (fwhdr_is_ga(fwhdr_to_cmp))
			return BFI_IOC_IMG_VER_BETTER;

	if (fwhdr_to_cmp->fwver.phase > base_fwhdr->fwver.phase)
		return BFI_IOC_IMG_VER_BETTER;
	else if (fwhdr_to_cmp->fwver.phase < base_fwhdr->fwver.phase)
		return BFI_IOC_IMG_VER_OLD;

	if (fwhdr_to_cmp->fwver.build > base_fwhdr->fwver.build)
		return BFI_IOC_IMG_VER_BETTER;
	else if (fwhdr_to_cmp->fwver.build < base_fwhdr->fwver.build)
		return BFI_IOC_IMG_VER_OLD;

	/* All Version Numbers are equal.
	 * Md5 check to be done as a part of compatibility check.
	 */
	return BFI_IOC_IMG_VER_SAME;
}

/* register definitions */
#define FLI_CMD_REG			0x0001d000
#define FLI_WRDATA_REG			0x0001d00c
#define FLI_RDDATA_REG			0x0001d010
#define FLI_ADDR_REG			0x0001d004
#define FLI_DEV_STATUS_REG		0x0001d014

#define BFA_FLASH_FIFO_SIZE		128	/* fifo size */
#define BFA_FLASH_CHECK_MAX		10000	/* max # of status check */
#define BFA_FLASH_BLOCKING_OP_MAX	1000000	/* max # of blocking op check */
#define BFA_FLASH_WIP_MASK		0x01	/* write in progress bit mask */

#define NFC_STATE_RUNNING		0x20000001
#define NFC_STATE_PAUSED		0x00004560
#define NFC_VER_VALID			0x147

enum bfa_flash_cmd {
	BFA_FLASH_FAST_READ	= 0x0b,	/* fast read */
	BFA_FLASH_WRITE_ENABLE	= 0x06,	/* write enable */
	BFA_FLASH_SECTOR_ERASE	= 0xd8,	/* sector erase */
	BFA_FLASH_WRITE		= 0x02,	/* write */
	BFA_FLASH_READ_STATUS	= 0x05,	/* read status */
};

/* hardware error definition */
enum bfa_flash_err {
	BFA_FLASH_NOT_PRESENT	= -1,	/*!< flash not present */
	BFA_FLASH_UNINIT	= -2,	/*!< flash not initialized */
	BFA_FLASH_BAD		= -3,	/*!< flash bad */
	BFA_FLASH_BUSY		= -4,	/*!< flash busy */
	BFA_FLASH_ERR_CMD_ACT	= -5,	/*!< command active never cleared */
	BFA_FLASH_ERR_FIFO_CNT	= -6,	/*!< fifo count never cleared */
	BFA_FLASH_ERR_WIP	= -7,	/*!< write-in-progress never cleared */
	BFA_FLASH_ERR_TIMEOUT	= -8,	/*!< fli timeout */
	BFA_FLASH_ERR_LEN	= -9,	/*!< invalid length */
};

/* flash command register data structure */
union bfa_flash_cmd_reg {
	struct {
#ifdef __BIG_ENDIAN
		u32	act:1;
		u32	rsv:1;
		u32	write_cnt:9;
		u32	read_cnt:9;
		u32	addr_cnt:4;
		u32	cmd:8;
#else
		u32	cmd:8;
		u32	addr_cnt:4;
		u32	read_cnt:9;
		u32	write_cnt:9;
		u32	rsv:1;
		u32	act:1;
#endif
	} r;
	u32	i;
};

/* flash device status register data structure */
union bfa_flash_dev_status_reg {
	struct {
#ifdef __BIG_ENDIAN
		u32	rsv:21;
		u32	fifo_cnt:6;
		u32	busy:1;
		u32	init_status:1;
		u32	present:1;
		u32	bad:1;
		u32	good:1;
#else
		u32	good:1;
		u32	bad:1;
		u32	present:1;
		u32	init_status:1;
		u32	busy:1;
		u32	fifo_cnt:6;
		u32	rsv:21;
#endif
	} r;
	u32	i;
};

/* flash address register data structure */
union bfa_flash_addr_reg {
	struct {
#ifdef __BIG_ENDIAN
		u32	addr:24;
		u32	dummy:8;
#else
		u32	dummy:8;
		u32	addr:24;
#endif
	} r;
	u32	i;
};

/* Flash raw private functions */
static void
bfa_flash_set_cmd(void __iomem *pci_bar, u8 wr_cnt,
		  u8 rd_cnt, u8 ad_cnt, u8 op)
{
	union bfa_flash_cmd_reg cmd;

	cmd.i = 0;
	cmd.r.act = 1;
	cmd.r.write_cnt = wr_cnt;
	cmd.r.read_cnt = rd_cnt;
	cmd.r.addr_cnt = ad_cnt;
	cmd.r.cmd = op;
	writel(cmd.i, (pci_bar + FLI_CMD_REG));
}

static void
bfa_flash_set_addr(void __iomem *pci_bar, u32 address)
{
	union bfa_flash_addr_reg addr;

	addr.r.addr = address & 0x00ffffff;
	addr.r.dummy = 0;
	writel(addr.i, (pci_bar + FLI_ADDR_REG));
}

static int
bfa_flash_cmd_act_check(void __iomem *pci_bar)
{
	union bfa_flash_cmd_reg cmd;

	cmd.i = readl(pci_bar + FLI_CMD_REG);

	if (cmd.r.act)
		return BFA_FLASH_ERR_CMD_ACT;

	return 0;
}

/* Flush FLI data fifo. */
static u32
bfa_flash_fifo_flush(void __iomem *pci_bar)
{
	u32 i;
	u32 t;
	union bfa_flash_dev_status_reg dev_status;

	dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);

	if (!dev_status.r.fifo_cnt)
		return 0;

	/* fifo counter in terms of words */
	for (i = 0; i < dev_status.r.fifo_cnt; i++)
		t = readl(pci_bar + FLI_RDDATA_REG);

	/* Check the device status. It may take some time. */
	for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) {
		dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);
		if (!dev_status.r.fifo_cnt)
			break;
	}

	if (dev_status.r.fifo_cnt)
		return BFA_FLASH_ERR_FIFO_CNT;

	return 0;
}

/* Read flash status. */
static u32
bfa_flash_status_read(void __iomem *pci_bar)
{
	union bfa_flash_dev_status_reg	dev_status;
	u32				status;
	u32			ret_status;
	int				i;

	status = bfa_flash_fifo_flush(pci_bar);
	if (status < 0)
		return status;

	bfa_flash_set_cmd(pci_bar, 0, 4, 0, BFA_FLASH_READ_STATUS);

	for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) {
		status = bfa_flash_cmd_act_check(pci_bar);
		if (!status)
			break;
	}

	if (status)
		return status;

	dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);
	if (!dev_status.r.fifo_cnt)
		return BFA_FLASH_BUSY;

	ret_status = readl(pci_bar + FLI_RDDATA_REG);
	ret_status >>= 24;

	status = bfa_flash_fifo_flush(pci_bar);
	if (status < 0)
		return status;

	return ret_status;
}

/* Start flash read operation. */
static u32
bfa_flash_read_start(void __iomem *pci_bar, u32 offset, u32 len,
		     char *buf)
{
	u32 status;

	/* len must be mutiple of 4 and not exceeding fifo size */
	if (len == 0 || len > BFA_FLASH_FIFO_SIZE || (len & 0x03) != 0)
		return BFA_FLASH_ERR_LEN;

	/* check status */
	status = bfa_flash_status_read(pci_bar);
	if (status == BFA_FLASH_BUSY)
		status = bfa_flash_status_read(pci_bar);

	if (status < 0)
		return status;

	/* check if write-in-progress bit is cleared */
	if (status & BFA_FLASH_WIP_MASK)
		return BFA_FLASH_ERR_WIP;

	bfa_flash_set_addr(pci_bar, offset);

	bfa_flash_set_cmd(pci_bar, 0, (u8)len, 4, BFA_FLASH_FAST_READ);

	return 0;
}

/* Check flash read operation. */
static u32
bfa_flash_read_check(void __iomem *pci_bar)
{
	if (bfa_flash_cmd_act_check(pci_bar))
		return 1;

	return 0;
}

/* End flash read operation. */
static void
bfa_flash_read_end(void __iomem *pci_bar, u32 len, char *buf)
{
	u32 i;

	/* read data fifo up to 32 words */
	for (i = 0; i < len; i += 4) {
		u32 w = readl(pci_bar + FLI_RDDATA_REG);
		*((u32 *)(buf + i)) = swab32(w);
	}

	bfa_flash_fifo_flush(pci_bar);
}

/* Perform flash raw read. */

#define FLASH_BLOCKING_OP_MAX   500
#define FLASH_SEM_LOCK_REG	0x18820

static int
bfa_raw_sem_get(void __iomem *bar)
{
	int	locked;

	locked = readl((bar + FLASH_SEM_LOCK_REG));

	return !locked;
}

static enum bfa_status
bfa_flash_sem_get(void __iomem *bar)
{
	u32 n = FLASH_BLOCKING_OP_MAX;

	while (!bfa_raw_sem_get(bar)) {
		if (--n <= 0)
			return BFA_STATUS_BADFLASH;
		udelay(10000);
	}
	return BFA_STATUS_OK;
}

static void
bfa_flash_sem_put(void __iomem *bar)
{
	writel(0, (bar + FLASH_SEM_LOCK_REG));
}

static enum bfa_status
bfa_flash_raw_read(void __iomem *pci_bar, u32 offset, char *buf,
		   u32 len)
{
	u32 n, status;
	u32 off, l, s, residue, fifo_sz;

	residue = len;
	off = 0;
	fifo_sz = BFA_FLASH_FIFO_SIZE;
	status = bfa_flash_sem_get(pci_bar);
	if (status != BFA_STATUS_OK)
		return status;

	while (residue) {
		s = offset + off;
		n = s / fifo_sz;
		l = (n + 1) * fifo_sz - s;
		if (l > residue)
			l = residue;

		status = bfa_flash_read_start(pci_bar, offset + off, l,
								&buf[off]);
		if (status < 0) {
			bfa_flash_sem_put(pci_bar);
			return BFA_STATUS_FAILED;
		}

		n = BFA_FLASH_BLOCKING_OP_MAX;
		while (bfa_flash_read_check(pci_bar)) {
			if (--n <= 0) {
				bfa_flash_sem_put(pci_bar);
				return BFA_STATUS_FAILED;
			}
		}

		bfa_flash_read_end(pci_bar, l, &buf[off]);

		residue -= l;
		off += l;
	}
	bfa_flash_sem_put(pci_bar);

	return BFA_STATUS_OK;
}

u32
bfa_nw_ioc_flash_img_get_size(struct bfa_ioc *ioc)
{
	return BFI_FLASH_IMAGE_SZ/sizeof(u32);
}

#define BFA_FLASH_PART_FWIMG_ADDR	0x100000 /* fw image address */

enum bfa_status
bfa_nw_ioc_flash_img_get_chnk(struct bfa_ioc *ioc, u32 off,
			      u32 *fwimg)
{
	return bfa_flash_raw_read(ioc->pcidev.pci_bar_kva,
			BFA_FLASH_PART_FWIMG_ADDR + (off * sizeof(u32)),
			(char *)fwimg, BFI_FLASH_CHUNK_SZ);
}

static enum bfi_ioc_img_ver_cmp
bfa_ioc_flash_fwver_cmp(struct bfa_ioc *ioc,
			struct bfi_ioc_image_hdr *base_fwhdr)
{
	struct bfi_ioc_image_hdr *flash_fwhdr;
	enum bfa_status status;
	u32 fwimg[BFI_FLASH_CHUNK_SZ_WORDS];

	status = bfa_nw_ioc_flash_img_get_chnk(ioc, 0, fwimg);
	if (status != BFA_STATUS_OK)
		return BFI_IOC_IMG_VER_INCOMP;

	flash_fwhdr = (struct bfi_ioc_image_hdr *)fwimg;
	if (bfa_ioc_flash_fwver_valid(flash_fwhdr))
		return bfa_ioc_fw_ver_patch_cmp(base_fwhdr, flash_fwhdr);
	else
		return BFI_IOC_IMG_VER_INCOMP;
}

/**
 * Returns TRUE if driver is willing to work with current smem f/w version.
 */
bool
bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
{
	struct bfi_ioc_image_hdr *drv_fwhdr;
	int i;
	enum bfi_ioc_img_ver_cmp smem_flash_cmp, drv_smem_cmp;

	drv_fwhdr = (struct bfi_ioc_image_hdr *)
		bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);

	for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
		if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i])
	/* If smem is incompatible or old, driver should not work with it. */
	drv_smem_cmp = bfa_ioc_fw_ver_patch_cmp(drv_fwhdr, fwhdr);
	if (drv_smem_cmp == BFI_IOC_IMG_VER_INCOMP ||
	    drv_smem_cmp == BFI_IOC_IMG_VER_OLD) {
		return false;
	}

	/* IF Flash has a better F/W than smem do not work with smem.
	 * If smem f/w == flash f/w, as smem f/w not old | incmp, work with it.
	 * If Flash is old or incomp work with smem iff smem f/w == drv f/w.
	 */
	smem_flash_cmp = bfa_ioc_flash_fwver_cmp(ioc, fwhdr);

	if (smem_flash_cmp == BFI_IOC_IMG_VER_BETTER)
		return false;
	else if (smem_flash_cmp == BFI_IOC_IMG_VER_SAME)
		return true;
	else
		return (drv_smem_cmp == BFI_IOC_IMG_VER_SAME) ?
			true : false;
}

/* Return true if current running version is valid. Firmware signature and
@@ -1333,15 +1856,9 @@ bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
static bool
bfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env)
{
	struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr;
	struct bfi_ioc_image_hdr fwhdr;

	bfa_nw_ioc_fwver_get(ioc, &fwhdr);
	drv_fwhdr = (struct bfi_ioc_image_hdr *)
		bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);

	if (fwhdr.signature != drv_fwhdr->signature)
		return false;

	if (swab32(fwhdr.bootenv) != boot_env)
		return false;

@@ -1366,7 +1883,7 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
	bool fwvalid;
	u32 boot_env;

	ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate);
	ioc_fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);

	if (force)
		ioc_fwstate = BFI_IOC_UNINIT;
@@ -1380,8 +1897,10 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
		false : bfa_ioc_fwver_valid(ioc, boot_env);

	if (!fwvalid) {
		bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env);
		if (bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env) ==
								BFA_STATUS_OK)
			bfa_ioc_poll_fwinit(ioc);

		return;
	}

@@ -1411,7 +1930,8 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
	/**
	 * Initialize the h/w for any other states.
	 */
	bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env);
	if (bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env) ==
							BFA_STATUS_OK)
		bfa_ioc_poll_fwinit(ioc);
}

@@ -1517,7 +2037,7 @@ bfa_ioc_hb_stop(struct bfa_ioc *ioc)
}

/* Initiate a full firmware download. */
static void
static enum bfa_status
bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
		    u32 boot_env)
{
@@ -1527,19 +2047,48 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
	u32 chunkno = 0;
	u32 i;
	u32 asicmode;
	u32 fwimg_size;
	u32 fwimg_buf[BFI_FLASH_CHUNK_SZ_WORDS];
	enum bfa_status status;

	fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), chunkno);
	if (boot_env == BFI_FWBOOT_ENV_OS &&
	    boot_type == BFI_FWBOOT_TYPE_FLASH) {
		fwimg_size = BFI_FLASH_IMAGE_SZ/sizeof(u32);

		status = bfa_nw_ioc_flash_img_get_chnk(ioc,
			BFA_IOC_FLASH_CHUNK_ADDR(chunkno), fwimg_buf);
		if (status != BFA_STATUS_OK)
			return status;

		fwimg = fwimg_buf;
	} else {
		fwimg_size = bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc));
		fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc),
					BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
	}

	pgnum = bfa_ioc_smem_pgnum(ioc, loff);

	writel(pgnum, ioc->ioc_regs.host_page_num_fn);

	for (i = 0; i < bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)); i++) {
	for (i = 0; i < fwimg_size; i++) {
		if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {
			chunkno = BFA_IOC_FLASH_CHUNK_NO(i);
			fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc),
			if (boot_env == BFI_FWBOOT_ENV_OS &&
			    boot_type == BFI_FWBOOT_TYPE_FLASH) {
				status = bfa_nw_ioc_flash_img_get_chnk(ioc,
					BFA_IOC_FLASH_CHUNK_ADDR(chunkno),
					fwimg_buf);
				if (status != BFA_STATUS_OK)
					return status;

				fwimg = fwimg_buf;
			} else {
				fwimg = bfa_cb_image_get_chunk(
					bfa_ioc_asic_gen(ioc),
					BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
			}
		}

		/**
		 * write smem
@@ -1566,6 +2115,10 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
	/*
	 * Set boot type, env and device mode at the end.
	*/
	if (boot_env == BFI_FWBOOT_ENV_OS &&
	    boot_type == BFI_FWBOOT_TYPE_FLASH) {
		boot_type = BFI_FWBOOT_TYPE_NORMAL;
	}
	asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode,
					ioc->port0_mode, ioc->port1_mode);
	writel(asicmode, ((ioc->ioc_regs.smem_page_start)
@@ -1574,6 +2127,7 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
			+ (BFI_FWBOOT_TYPE_OFF)));
	writel(boot_env, ((ioc->ioc_regs.smem_page_start)
			+ (BFI_FWBOOT_ENV_OFF)));
	return BFA_STATUS_OK;
}

static void
@@ -1846,29 +2400,47 @@ bfa_ioc_pll_init(struct bfa_ioc *ioc)
/* Interface used by diag module to do firmware boot with memory test
 * as the entry vector.
 */
static void
static enum bfa_status
bfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type,
		u32 boot_env)
{
	struct bfi_ioc_image_hdr *drv_fwhdr;
	enum bfa_status status;
	bfa_ioc_stats(ioc, ioc_boots);

	if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
		return;
		return BFA_STATUS_FAILED;
	if (boot_env == BFI_FWBOOT_ENV_OS &&
	    boot_type == BFI_FWBOOT_TYPE_NORMAL) {
		drv_fwhdr = (struct bfi_ioc_image_hdr *)
			bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);
		/* Work with Flash iff flash f/w is better than driver f/w.
		 * Otherwise push drivers firmware.
		 */
		if (bfa_ioc_flash_fwver_cmp(ioc, drv_fwhdr) ==
			BFI_IOC_IMG_VER_BETTER)
			boot_type = BFI_FWBOOT_TYPE_FLASH;
	}

	/**
	 * Initialize IOC state of all functions on a chip reset.
	 */
	if (boot_type == BFI_FWBOOT_TYPE_MEMTEST) {
		writel(BFI_IOC_MEMTEST, ioc->ioc_regs.ioc_fwstate);
		writel(BFI_IOC_MEMTEST, ioc->ioc_regs.alt_ioc_fwstate);
		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_MEMTEST);
		bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_MEMTEST);
	} else {
		writel(BFI_IOC_INITING, ioc->ioc_regs.ioc_fwstate);
		writel(BFI_IOC_INITING, ioc->ioc_regs.alt_ioc_fwstate);
		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_INITING);
		bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_INITING);
	}

	bfa_ioc_msgflush(ioc);
	bfa_ioc_download_fw(ioc, boot_type, boot_env);
	status = bfa_ioc_download_fw(ioc, boot_type, boot_env);
	if (status == BFA_STATUS_OK)
		bfa_ioc_lpu_start(ioc);
	else
		bfa_nw_iocpf_timeout(ioc);

	return status;
}

/* Enable/disable IOC failure auto recovery. */
@@ -2473,7 +3045,7 @@ bfa_nw_iocpf_sem_timeout(void *ioc_arg)
static void
bfa_ioc_poll_fwinit(struct bfa_ioc *ioc)
{
	u32 fwstate = readl(ioc->ioc_regs.ioc_fwstate);
	u32 fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);

	if (fwstate == BFI_IOC_DISABLED) {
		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);
+8 −0
Original line number Diff line number Diff line
@@ -215,6 +215,13 @@ struct bfa_ioc_hwif {
	void		(*ioc_sync_ack)		(struct bfa_ioc *ioc);
	bool		(*ioc_sync_complete)	(struct bfa_ioc *ioc);
	bool		(*ioc_lpu_read_stat)	(struct bfa_ioc *ioc);
	void		(*ioc_set_fwstate)	(struct bfa_ioc *ioc,
					enum bfi_ioc_state fwstate);
	enum bfi_ioc_state (*ioc_get_fwstate) (struct bfa_ioc *ioc);
	void		(*ioc_set_alt_fwstate)	(struct bfa_ioc *ioc,
					enum bfi_ioc_state fwstate);
	enum bfi_ioc_state (*ioc_get_alt_fwstate) (struct bfa_ioc *ioc);

};

#define bfa_ioc_pcifn(__ioc)		((__ioc)->pcidev.pci_func)
@@ -291,6 +298,7 @@ void bfa_nw_ioc_error_isr(struct bfa_ioc *ioc);
bool bfa_nw_ioc_is_disabled(struct bfa_ioc *ioc);
bool bfa_nw_ioc_is_operational(struct bfa_ioc *ioc);
void bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr);
enum bfa_status bfa_nw_ioc_fwsig_invalidate(struct bfa_ioc *ioc);
void bfa_nw_ioc_notify_register(struct bfa_ioc *ioc,
	struct bfa_ioc_notify *notify);
bool bfa_nw_ioc_sem_get(void __iomem *sem_reg);
+40 −0
Original line number Diff line number Diff line
@@ -48,6 +48,12 @@ static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc);
static void bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc);
static void bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc);
static bool bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc);
static void bfa_ioc_ct_set_cur_ioc_fwstate(
			struct bfa_ioc *ioc, enum bfi_ioc_state fwstate);
static enum bfi_ioc_state bfa_ioc_ct_get_cur_ioc_fwstate(struct bfa_ioc *ioc);
static void bfa_ioc_ct_set_alt_ioc_fwstate(
			struct bfa_ioc *ioc, enum bfi_ioc_state fwstate);
static enum bfi_ioc_state bfa_ioc_ct_get_alt_ioc_fwstate(struct bfa_ioc *ioc);
static enum bfa_status bfa_ioc_ct_pll_init(void __iomem *rb,
				enum bfi_asic_mode asic_mode);
static enum bfa_status bfa_ioc_ct2_pll_init(void __iomem *rb,
@@ -68,6 +74,10 @@ static const struct bfa_ioc_hwif nw_hwif_ct = {
	.ioc_sync_leave	     = bfa_ioc_ct_sync_leave,
	.ioc_sync_ack	     = bfa_ioc_ct_sync_ack,
	.ioc_sync_complete   = bfa_ioc_ct_sync_complete,
	.ioc_set_fwstate     = bfa_ioc_ct_set_cur_ioc_fwstate,
	.ioc_get_fwstate     = bfa_ioc_ct_get_cur_ioc_fwstate,
	.ioc_set_alt_fwstate     = bfa_ioc_ct_set_alt_ioc_fwstate,
	.ioc_get_alt_fwstate     = bfa_ioc_ct_get_alt_ioc_fwstate,
};

static const struct bfa_ioc_hwif nw_hwif_ct2 = {
@@ -85,6 +95,10 @@ static const struct bfa_ioc_hwif nw_hwif_ct2 = {
	.ioc_sync_leave	     = bfa_ioc_ct_sync_leave,
	.ioc_sync_ack	     = bfa_ioc_ct_sync_ack,
	.ioc_sync_complete   = bfa_ioc_ct_sync_complete,
	.ioc_set_fwstate     = bfa_ioc_ct_set_cur_ioc_fwstate,
	.ioc_get_fwstate     = bfa_ioc_ct_get_cur_ioc_fwstate,
	.ioc_set_alt_fwstate     = bfa_ioc_ct_set_alt_ioc_fwstate,
	.ioc_get_alt_fwstate     = bfa_ioc_ct_get_alt_ioc_fwstate,
};

/* Called from bfa_ioc_attach() to map asic specific calls. */
@@ -565,6 +579,32 @@ bfa_ioc_ct_sync_complete(struct bfa_ioc *ioc)
	return false;
}

static void
bfa_ioc_ct_set_cur_ioc_fwstate(struct bfa_ioc *ioc,
			       enum bfi_ioc_state fwstate)
{
	writel(fwstate, ioc->ioc_regs.ioc_fwstate);
}

static enum bfi_ioc_state
bfa_ioc_ct_get_cur_ioc_fwstate(struct bfa_ioc *ioc)
{
	return (enum bfi_ioc_state)readl(ioc->ioc_regs.ioc_fwstate);
}

static void
bfa_ioc_ct_set_alt_ioc_fwstate(struct bfa_ioc *ioc,
			       enum bfi_ioc_state fwstate)
{
	writel(fwstate, ioc->ioc_regs.alt_ioc_fwstate);
}

static enum bfi_ioc_state
bfa_ioc_ct_get_alt_ioc_fwstate(struct bfa_ioc *ioc)
{
	return (enum bfi_ioc_state)readl(ioc->ioc_regs.alt_ioc_fwstate);
}

static enum bfa_status
bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode asic_mode)
{
+32 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
/* BFI FW image type */
#define	BFI_FLASH_CHUNK_SZ			256	/*!< Flash chunk size */
#define	BFI_FLASH_CHUNK_SZ_WORDS	(BFI_FLASH_CHUNK_SZ/sizeof(u32))
#define BFI_FLASH_IMAGE_SZ		0x100000

/* Msg header common to all msgs */
struct bfi_mhdr {
@@ -233,7 +234,29 @@ struct bfi_ioc_getattr_reply {
#define BFI_IOC_TRC_HDR_SZ	32

#define BFI_IOC_FW_SIGNATURE	(0xbfadbfad)
#define BFI_IOC_FW_INV_SIGN	(0xdeaddead)
#define BFI_IOC_MD5SUM_SZ	4

struct bfi_ioc_fwver {
#ifdef __BIG_ENDIAN
	u8 patch;
	u8 maint;
	u8 minor;
	u8 major;
	u8 rsvd[2];
	u8 build;
	u8 phase;
#else
	u8 major;
	u8 minor;
	u8 maint;
	u8 patch;
	u8 phase;
	u8 build;
	u8 rsvd[2];
#endif
};

struct bfi_ioc_image_hdr {
	u32	signature;	/*!< constant signature */
	u8	asic_gen;	/*!< asic generation */
@@ -242,10 +265,18 @@ struct bfi_ioc_image_hdr {
	u8	port1_mode;	/*!< device mode for port 1 */
	u32	exec;		/*!< exec vector	*/
	u32	bootenv;	/*!< firmware boot env */
	u32	rsvd_b[4];
	u32	rsvd_b[2];
	struct bfi_ioc_fwver fwver;
	u32	md5sum[BFI_IOC_MD5SUM_SZ];
};

enum bfi_ioc_img_ver_cmp {
	BFI_IOC_IMG_VER_INCOMP,
	BFI_IOC_IMG_VER_OLD,
	BFI_IOC_IMG_VER_SAME,
	BFI_IOC_IMG_VER_BETTER
};

#define BFI_FWBOOT_DEVMODE_OFF		4
#define BFI_FWBOOT_TYPE_OFF		8
#define BFI_FWBOOT_ENV_OFF		12
+2 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading