162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Linux network driver for QLogic BR-series Converged Network Adapter.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
762306a36Sopenharmony_ci * Copyright (c) 2014-2015 QLogic Corporation
862306a36Sopenharmony_ci * All rights reserved
962306a36Sopenharmony_ci * www.qlogic.com
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "bfa_ioc.h"
1362306a36Sopenharmony_ci#include "bfi_reg.h"
1462306a36Sopenharmony_ci#include "bfa_defs.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* IOC local definitions */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details. */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define bfa_ioc_firmware_lock(__ioc)			\
2162306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc))
2262306a36Sopenharmony_ci#define bfa_ioc_firmware_unlock(__ioc)			\
2362306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
2462306a36Sopenharmony_ci#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
2562306a36Sopenharmony_ci#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
2662306a36Sopenharmony_ci#define bfa_ioc_notify_fail(__ioc)			\
2762306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_notify_fail(__ioc))
2862306a36Sopenharmony_ci#define bfa_ioc_sync_start(__ioc)               \
2962306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_start(__ioc))
3062306a36Sopenharmony_ci#define bfa_ioc_sync_join(__ioc)			\
3162306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_join(__ioc))
3262306a36Sopenharmony_ci#define bfa_ioc_sync_leave(__ioc)			\
3362306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_leave(__ioc))
3462306a36Sopenharmony_ci#define bfa_ioc_sync_ack(__ioc)				\
3562306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_ack(__ioc))
3662306a36Sopenharmony_ci#define bfa_ioc_sync_complete(__ioc)			\
3762306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_complete(__ioc))
3862306a36Sopenharmony_ci#define bfa_ioc_set_cur_ioc_fwstate(__ioc, __fwstate)		\
3962306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_set_fwstate(__ioc, __fwstate))
4062306a36Sopenharmony_ci#define bfa_ioc_get_cur_ioc_fwstate(__ioc)		\
4162306a36Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_get_fwstate(__ioc))
4262306a36Sopenharmony_ci#define bfa_ioc_set_alt_ioc_fwstate(__ioc, __fwstate)		\
4362306a36Sopenharmony_ci		((__ioc)->ioc_hwif->ioc_set_alt_fwstate(__ioc, __fwstate))
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic bool bfa_nw_auto_recover = true;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/*
4862306a36Sopenharmony_ci * forward declarations
4962306a36Sopenharmony_ci */
5062306a36Sopenharmony_cistatic void bfa_ioc_hw_sem_init(struct bfa_ioc *ioc);
5162306a36Sopenharmony_cistatic void bfa_ioc_hw_sem_get(struct bfa_ioc *ioc);
5262306a36Sopenharmony_cistatic void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc);
5362306a36Sopenharmony_cistatic void bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force);
5462306a36Sopenharmony_cistatic void bfa_ioc_poll_fwinit(struct bfa_ioc *ioc);
5562306a36Sopenharmony_cistatic void bfa_ioc_send_enable(struct bfa_ioc *ioc);
5662306a36Sopenharmony_cistatic void bfa_ioc_send_disable(struct bfa_ioc *ioc);
5762306a36Sopenharmony_cistatic void bfa_ioc_send_getattr(struct bfa_ioc *ioc);
5862306a36Sopenharmony_cistatic void bfa_ioc_hb_monitor(struct bfa_ioc *ioc);
5962306a36Sopenharmony_cistatic void bfa_ioc_hb_stop(struct bfa_ioc *ioc);
6062306a36Sopenharmony_cistatic void bfa_ioc_reset(struct bfa_ioc *ioc, bool force);
6162306a36Sopenharmony_cistatic void bfa_ioc_mbox_poll(struct bfa_ioc *ioc);
6262306a36Sopenharmony_cistatic void bfa_ioc_mbox_flush(struct bfa_ioc *ioc);
6362306a36Sopenharmony_cistatic void bfa_ioc_recover(struct bfa_ioc *ioc);
6462306a36Sopenharmony_cistatic void bfa_ioc_event_notify(struct bfa_ioc *, enum bfa_ioc_event);
6562306a36Sopenharmony_cistatic void bfa_ioc_disable_comp(struct bfa_ioc *ioc);
6662306a36Sopenharmony_cistatic void bfa_ioc_lpu_stop(struct bfa_ioc *ioc);
6762306a36Sopenharmony_cistatic void bfa_nw_ioc_debug_save_ftrc(struct bfa_ioc *ioc);
6862306a36Sopenharmony_cistatic void bfa_ioc_fail_notify(struct bfa_ioc *ioc);
6962306a36Sopenharmony_cistatic void bfa_ioc_pf_enabled(struct bfa_ioc *ioc);
7062306a36Sopenharmony_cistatic void bfa_ioc_pf_disabled(struct bfa_ioc *ioc);
7162306a36Sopenharmony_cistatic void bfa_ioc_pf_failed(struct bfa_ioc *ioc);
7262306a36Sopenharmony_cistatic void bfa_ioc_pf_hwfailed(struct bfa_ioc *ioc);
7362306a36Sopenharmony_cistatic void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc);
7462306a36Sopenharmony_cistatic enum bfa_status bfa_ioc_boot(struct bfa_ioc *ioc,
7562306a36Sopenharmony_ci			enum bfi_fwboot_type boot_type, u32 boot_param);
7662306a36Sopenharmony_cistatic u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr);
7762306a36Sopenharmony_cistatic void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc,
7862306a36Sopenharmony_ci						char *serial_num);
7962306a36Sopenharmony_cistatic void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc,
8062306a36Sopenharmony_ci						char *fw_ver);
8162306a36Sopenharmony_cistatic void bfa_ioc_get_pci_chip_rev(struct bfa_ioc *ioc,
8262306a36Sopenharmony_ci						char *chip_rev);
8362306a36Sopenharmony_cistatic void bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc,
8462306a36Sopenharmony_ci						char *optrom_ver);
8562306a36Sopenharmony_cistatic void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc,
8662306a36Sopenharmony_ci						char *manufacturer);
8762306a36Sopenharmony_cistatic void bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model);
8862306a36Sopenharmony_cistatic u64 bfa_ioc_get_pwwn(struct bfa_ioc *ioc);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* IOC state machine definitions/declarations */
9162306a36Sopenharmony_cienum ioc_event {
9262306a36Sopenharmony_ci	IOC_E_RESET		= 1,	/*!< IOC reset request		*/
9362306a36Sopenharmony_ci	IOC_E_ENABLE		= 2,	/*!< IOC enable request		*/
9462306a36Sopenharmony_ci	IOC_E_DISABLE		= 3,	/*!< IOC disable request	*/
9562306a36Sopenharmony_ci	IOC_E_DETACH		= 4,	/*!< driver detach cleanup	*/
9662306a36Sopenharmony_ci	IOC_E_ENABLED		= 5,	/*!< f/w enabled		*/
9762306a36Sopenharmony_ci	IOC_E_FWRSP_GETATTR	= 6,	/*!< IOC get attribute response	*/
9862306a36Sopenharmony_ci	IOC_E_DISABLED		= 7,	/*!< f/w disabled		*/
9962306a36Sopenharmony_ci	IOC_E_PFFAILED		= 8,	/*!< failure notice by iocpf sm	*/
10062306a36Sopenharmony_ci	IOC_E_HBFAIL		= 9,	/*!< heartbeat failure		*/
10162306a36Sopenharmony_ci	IOC_E_HWERROR		= 10,	/*!< hardware error interrupt	*/
10262306a36Sopenharmony_ci	IOC_E_TIMEOUT		= 11,	/*!< timeout			*/
10362306a36Sopenharmony_ci	IOC_E_HWFAILED		= 12,	/*!< PCI mapping failure notice	*/
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc, enum ioc_event);
10762306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc, enum ioc_event);
10862306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc, enum ioc_event);
10962306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc, enum ioc_event);
11062306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc, enum ioc_event);
11162306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc, enum ioc_event);
11262306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc, enum ioc_event);
11362306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc, enum ioc_event);
11462306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc, enum ioc_event);
11562306a36Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc, enum ioc_event);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic struct ioc_sm_table_s ioc_sm_table[] = {
11862306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT},
11962306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},
12062306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING},
12162306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
12262306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
12362306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_fail_retry), BFA_IOC_INITFAIL},
12462306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL},
12562306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
12662306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
12762306a36Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL},
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/*
13162306a36Sopenharmony_ci * Forward declareations for iocpf state machine
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_cistatic void bfa_iocpf_enable(struct bfa_ioc *ioc);
13462306a36Sopenharmony_cistatic void bfa_iocpf_disable(struct bfa_ioc *ioc);
13562306a36Sopenharmony_cistatic void bfa_iocpf_fail(struct bfa_ioc *ioc);
13662306a36Sopenharmony_cistatic void bfa_iocpf_initfail(struct bfa_ioc *ioc);
13762306a36Sopenharmony_cistatic void bfa_iocpf_getattrfail(struct bfa_ioc *ioc);
13862306a36Sopenharmony_cistatic void bfa_iocpf_stop(struct bfa_ioc *ioc);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* IOCPF state machine events */
14162306a36Sopenharmony_cienum iocpf_event {
14262306a36Sopenharmony_ci	IOCPF_E_ENABLE		= 1,	/*!< IOCPF enable request	*/
14362306a36Sopenharmony_ci	IOCPF_E_DISABLE		= 2,	/*!< IOCPF disable request	*/
14462306a36Sopenharmony_ci	IOCPF_E_STOP		= 3,	/*!< stop on driver detach	*/
14562306a36Sopenharmony_ci	IOCPF_E_FWREADY		= 4,	/*!< f/w initialization done	*/
14662306a36Sopenharmony_ci	IOCPF_E_FWRSP_ENABLE	= 5,	/*!< enable f/w response	*/
14762306a36Sopenharmony_ci	IOCPF_E_FWRSP_DISABLE	= 6,	/*!< disable f/w response	*/
14862306a36Sopenharmony_ci	IOCPF_E_FAIL		= 7,	/*!< failure notice by ioc sm	*/
14962306a36Sopenharmony_ci	IOCPF_E_INITFAIL	= 8,	/*!< init fail notice by ioc sm	*/
15062306a36Sopenharmony_ci	IOCPF_E_GETATTRFAIL	= 9,	/*!< init fail notice by ioc sm	*/
15162306a36Sopenharmony_ci	IOCPF_E_SEMLOCKED	= 10,   /*!< h/w semaphore is locked	*/
15262306a36Sopenharmony_ci	IOCPF_E_TIMEOUT		= 11,   /*!< f/w response timeout	*/
15362306a36Sopenharmony_ci	IOCPF_E_SEM_ERROR	= 12,   /*!< h/w sem mapping error	*/
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/* IOCPF states */
15762306a36Sopenharmony_cienum bfa_iocpf_state {
15862306a36Sopenharmony_ci	BFA_IOCPF_RESET		= 1,	/*!< IOC is in reset state */
15962306a36Sopenharmony_ci	BFA_IOCPF_SEMWAIT	= 2,	/*!< Waiting for IOC h/w semaphore */
16062306a36Sopenharmony_ci	BFA_IOCPF_HWINIT	= 3,	/*!< IOC h/w is being initialized */
16162306a36Sopenharmony_ci	BFA_IOCPF_READY		= 4,	/*!< IOCPF is initialized */
16262306a36Sopenharmony_ci	BFA_IOCPF_INITFAIL	= 5,	/*!< IOCPF failed */
16362306a36Sopenharmony_ci	BFA_IOCPF_FAIL		= 6,	/*!< IOCPF failed */
16462306a36Sopenharmony_ci	BFA_IOCPF_DISABLING	= 7,	/*!< IOCPF is being disabled */
16562306a36Sopenharmony_ci	BFA_IOCPF_DISABLED	= 8,	/*!< IOCPF is disabled */
16662306a36Sopenharmony_ci	BFA_IOCPF_FWMISMATCH	= 9,	/*!< IOC f/w different from drivers */
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, reset, struct bfa_iocpf, enum iocpf_event);
17062306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, fwcheck, struct bfa_iocpf, enum iocpf_event);
17162306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, mismatch, struct bfa_iocpf, enum iocpf_event);
17262306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, semwait, struct bfa_iocpf, enum iocpf_event);
17362306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, hwinit, struct bfa_iocpf, enum iocpf_event);
17462306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, enabling, struct bfa_iocpf, enum iocpf_event);
17562306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, ready, struct bfa_iocpf, enum iocpf_event);
17662306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, initfail_sync, struct bfa_iocpf,
17762306a36Sopenharmony_ci						enum iocpf_event);
17862306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, initfail, struct bfa_iocpf, enum iocpf_event);
17962306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, fail_sync, struct bfa_iocpf, enum iocpf_event);
18062306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, fail, struct bfa_iocpf, enum iocpf_event);
18162306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, disabling, struct bfa_iocpf, enum iocpf_event);
18262306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, disabling_sync, struct bfa_iocpf,
18362306a36Sopenharmony_ci						enum iocpf_event);
18462306a36Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf, enum iocpf_event);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic struct iocpf_sm_table_s iocpf_sm_table[] = {
18762306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET},
18862306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH},
18962306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH},
19062306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_semwait), BFA_IOCPF_SEMWAIT},
19162306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_hwinit), BFA_IOCPF_HWINIT},
19262306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_enabling), BFA_IOCPF_HWINIT},
19362306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_ready), BFA_IOCPF_READY},
19462306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_initfail_sync), BFA_IOCPF_INITFAIL},
19562306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_initfail), BFA_IOCPF_INITFAIL},
19662306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_fail_sync), BFA_IOCPF_FAIL},
19762306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_fail), BFA_IOCPF_FAIL},
19862306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_disabling), BFA_IOCPF_DISABLING},
19962306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_disabling_sync), BFA_IOCPF_DISABLING},
20062306a36Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_disabled), BFA_IOCPF_DISABLED},
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/* IOC State Machine */
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci/* Beginning state. IOC uninit state. */
20662306a36Sopenharmony_cistatic void
20762306a36Sopenharmony_cibfa_ioc_sm_uninit_entry(struct bfa_ioc *ioc)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/* IOC is in uninit state. */
21262306a36Sopenharmony_cistatic void
21362306a36Sopenharmony_cibfa_ioc_sm_uninit(struct bfa_ioc *ioc, enum ioc_event event)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	switch (event) {
21662306a36Sopenharmony_ci	case IOC_E_RESET:
21762306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
21862306a36Sopenharmony_ci		break;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	default:
22162306a36Sopenharmony_ci		bfa_sm_fault(event);
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/* Reset entry actions -- initialize state machine */
22662306a36Sopenharmony_cistatic void
22762306a36Sopenharmony_cibfa_ioc_sm_reset_entry(struct bfa_ioc *ioc)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	bfa_fsm_set_state(&ioc->iocpf, bfa_iocpf_sm_reset);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/* IOC is in reset state. */
23362306a36Sopenharmony_cistatic void
23462306a36Sopenharmony_cibfa_ioc_sm_reset(struct bfa_ioc *ioc, enum ioc_event event)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	switch (event) {
23762306a36Sopenharmony_ci	case IOC_E_ENABLE:
23862306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
23962306a36Sopenharmony_ci		break;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	case IOC_E_DISABLE:
24262306a36Sopenharmony_ci		bfa_ioc_disable_comp(ioc);
24362306a36Sopenharmony_ci		break;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	case IOC_E_DETACH:
24662306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
24762306a36Sopenharmony_ci		break;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	default:
25062306a36Sopenharmony_ci		bfa_sm_fault(event);
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic void
25562306a36Sopenharmony_cibfa_ioc_sm_enabling_entry(struct bfa_ioc *ioc)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	bfa_iocpf_enable(ioc);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci/* Host IOC function is being enabled, awaiting response from firmware.
26162306a36Sopenharmony_ci * Semaphore is acquired.
26262306a36Sopenharmony_ci */
26362306a36Sopenharmony_cistatic void
26462306a36Sopenharmony_cibfa_ioc_sm_enabling(struct bfa_ioc *ioc, enum ioc_event event)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	switch (event) {
26762306a36Sopenharmony_ci	case IOC_E_ENABLED:
26862306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
26962306a36Sopenharmony_ci		break;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	case IOC_E_PFFAILED:
27262306a36Sopenharmony_ci		fallthrough;
27362306a36Sopenharmony_ci	case IOC_E_HWERROR:
27462306a36Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
27562306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
27662306a36Sopenharmony_ci		if (event != IOC_E_PFFAILED)
27762306a36Sopenharmony_ci			bfa_iocpf_initfail(ioc);
27862306a36Sopenharmony_ci		break;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	case IOC_E_HWFAILED:
28162306a36Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
28262306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
28362306a36Sopenharmony_ci		break;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	case IOC_E_DISABLE:
28662306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
28762306a36Sopenharmony_ci		break;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	case IOC_E_DETACH:
29062306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
29162306a36Sopenharmony_ci		bfa_iocpf_stop(ioc);
29262306a36Sopenharmony_ci		break;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	case IOC_E_ENABLE:
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	default:
29862306a36Sopenharmony_ci		bfa_sm_fault(event);
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/* Semaphore should be acquired for version check. */
30362306a36Sopenharmony_cistatic void
30462306a36Sopenharmony_cibfa_ioc_sm_getattr_entry(struct bfa_ioc *ioc)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	mod_timer(&ioc->ioc_timer, jiffies +
30762306a36Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_TOV));
30862306a36Sopenharmony_ci	bfa_ioc_send_getattr(ioc);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/* IOC configuration in progress. Timer is active. */
31262306a36Sopenharmony_cistatic void
31362306a36Sopenharmony_cibfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	switch (event) {
31662306a36Sopenharmony_ci	case IOC_E_FWRSP_GETATTR:
31762306a36Sopenharmony_ci		del_timer(&ioc->ioc_timer);
31862306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
31962306a36Sopenharmony_ci		break;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	case IOC_E_PFFAILED:
32262306a36Sopenharmony_ci	case IOC_E_HWERROR:
32362306a36Sopenharmony_ci		del_timer(&ioc->ioc_timer);
32462306a36Sopenharmony_ci		fallthrough;
32562306a36Sopenharmony_ci	case IOC_E_TIMEOUT:
32662306a36Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
32762306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
32862306a36Sopenharmony_ci		if (event != IOC_E_PFFAILED)
32962306a36Sopenharmony_ci			bfa_iocpf_getattrfail(ioc);
33062306a36Sopenharmony_ci		break;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	case IOC_E_DISABLE:
33362306a36Sopenharmony_ci		del_timer(&ioc->ioc_timer);
33462306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
33562306a36Sopenharmony_ci		break;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	case IOC_E_ENABLE:
33862306a36Sopenharmony_ci		break;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	default:
34162306a36Sopenharmony_ci		bfa_sm_fault(event);
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic void
34662306a36Sopenharmony_cibfa_ioc_sm_op_entry(struct bfa_ioc *ioc)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
34962306a36Sopenharmony_ci	bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED);
35062306a36Sopenharmony_ci	bfa_ioc_hb_monitor(ioc);
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic void
35462306a36Sopenharmony_cibfa_ioc_sm_op(struct bfa_ioc *ioc, enum ioc_event event)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	switch (event) {
35762306a36Sopenharmony_ci	case IOC_E_ENABLE:
35862306a36Sopenharmony_ci		break;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	case IOC_E_DISABLE:
36162306a36Sopenharmony_ci		bfa_ioc_hb_stop(ioc);
36262306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
36362306a36Sopenharmony_ci		break;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	case IOC_E_PFFAILED:
36662306a36Sopenharmony_ci	case IOC_E_HWERROR:
36762306a36Sopenharmony_ci		bfa_ioc_hb_stop(ioc);
36862306a36Sopenharmony_ci		fallthrough;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	case IOC_E_HBFAIL:
37162306a36Sopenharmony_ci		if (ioc->iocpf.auto_recover)
37262306a36Sopenharmony_ci			bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
37362306a36Sopenharmony_ci		else
37462306a36Sopenharmony_ci			bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		bfa_ioc_fail_notify(ioc);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		if (event != IOC_E_PFFAILED)
37962306a36Sopenharmony_ci			bfa_iocpf_fail(ioc);
38062306a36Sopenharmony_ci		break;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	default:
38362306a36Sopenharmony_ci		bfa_sm_fault(event);
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic void
38862306a36Sopenharmony_cibfa_ioc_sm_disabling_entry(struct bfa_ioc *ioc)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	bfa_iocpf_disable(ioc);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci/* IOC is being disabled */
39462306a36Sopenharmony_cistatic void
39562306a36Sopenharmony_cibfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	switch (event) {
39862306a36Sopenharmony_ci	case IOC_E_DISABLED:
39962306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
40062306a36Sopenharmony_ci		break;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	case IOC_E_HWERROR:
40362306a36Sopenharmony_ci		/*
40462306a36Sopenharmony_ci		 * No state change.  Will move to disabled state
40562306a36Sopenharmony_ci		 * after iocpf sm completes failure processing and
40662306a36Sopenharmony_ci		 * moves to disabled state.
40762306a36Sopenharmony_ci		 */
40862306a36Sopenharmony_ci		bfa_iocpf_fail(ioc);
40962306a36Sopenharmony_ci		break;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	case IOC_E_HWFAILED:
41262306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
41362306a36Sopenharmony_ci		bfa_ioc_disable_comp(ioc);
41462306a36Sopenharmony_ci		break;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	default:
41762306a36Sopenharmony_ci		bfa_sm_fault(event);
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/* IOC disable completion entry. */
42262306a36Sopenharmony_cistatic void
42362306a36Sopenharmony_cibfa_ioc_sm_disabled_entry(struct bfa_ioc *ioc)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	bfa_ioc_disable_comp(ioc);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic void
42962306a36Sopenharmony_cibfa_ioc_sm_disabled(struct bfa_ioc *ioc, enum ioc_event event)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	switch (event) {
43262306a36Sopenharmony_ci	case IOC_E_ENABLE:
43362306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
43462306a36Sopenharmony_ci		break;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	case IOC_E_DISABLE:
43762306a36Sopenharmony_ci		ioc->cbfn->disable_cbfn(ioc->bfa);
43862306a36Sopenharmony_ci		break;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	case IOC_E_DETACH:
44162306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
44262306a36Sopenharmony_ci		bfa_iocpf_stop(ioc);
44362306a36Sopenharmony_ci		break;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	default:
44662306a36Sopenharmony_ci		bfa_sm_fault(event);
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void
45162306a36Sopenharmony_cibfa_ioc_sm_fail_retry_entry(struct bfa_ioc *ioc)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/* Hardware initialization retry. */
45662306a36Sopenharmony_cistatic void
45762306a36Sopenharmony_cibfa_ioc_sm_fail_retry(struct bfa_ioc *ioc, enum ioc_event event)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	switch (event) {
46062306a36Sopenharmony_ci	case IOC_E_ENABLED:
46162306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
46262306a36Sopenharmony_ci		break;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	case IOC_E_PFFAILED:
46562306a36Sopenharmony_ci	case IOC_E_HWERROR:
46662306a36Sopenharmony_ci		/**
46762306a36Sopenharmony_ci		 * Initialization retry failed.
46862306a36Sopenharmony_ci		 */
46962306a36Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
47062306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
47162306a36Sopenharmony_ci		if (event != IOC_E_PFFAILED)
47262306a36Sopenharmony_ci			bfa_iocpf_initfail(ioc);
47362306a36Sopenharmony_ci		break;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	case IOC_E_HWFAILED:
47662306a36Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
47762306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
47862306a36Sopenharmony_ci		break;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	case IOC_E_ENABLE:
48162306a36Sopenharmony_ci		break;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	case IOC_E_DISABLE:
48462306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
48562306a36Sopenharmony_ci		break;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	case IOC_E_DETACH:
48862306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
48962306a36Sopenharmony_ci		bfa_iocpf_stop(ioc);
49062306a36Sopenharmony_ci		break;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	default:
49362306a36Sopenharmony_ci		bfa_sm_fault(event);
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic void
49862306a36Sopenharmony_cibfa_ioc_sm_fail_entry(struct bfa_ioc *ioc)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci/* IOC failure. */
50362306a36Sopenharmony_cistatic void
50462306a36Sopenharmony_cibfa_ioc_sm_fail(struct bfa_ioc *ioc, enum ioc_event event)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	switch (event) {
50762306a36Sopenharmony_ci	case IOC_E_ENABLE:
50862306a36Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
50962306a36Sopenharmony_ci		break;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	case IOC_E_DISABLE:
51262306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
51362306a36Sopenharmony_ci		break;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	case IOC_E_DETACH:
51662306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
51762306a36Sopenharmony_ci		bfa_iocpf_stop(ioc);
51862306a36Sopenharmony_ci		break;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	case IOC_E_HWERROR:
52162306a36Sopenharmony_ci		/* HB failure notification, ignore. */
52262306a36Sopenharmony_ci		break;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	default:
52562306a36Sopenharmony_ci		bfa_sm_fault(event);
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic void
53062306a36Sopenharmony_cibfa_ioc_sm_hwfail_entry(struct bfa_ioc *ioc)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci/* IOC failure. */
53562306a36Sopenharmony_cistatic void
53662306a36Sopenharmony_cibfa_ioc_sm_hwfail(struct bfa_ioc *ioc, enum ioc_event event)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	switch (event) {
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	case IOC_E_ENABLE:
54162306a36Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
54262306a36Sopenharmony_ci		break;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	case IOC_E_DISABLE:
54562306a36Sopenharmony_ci		ioc->cbfn->disable_cbfn(ioc->bfa);
54662306a36Sopenharmony_ci		break;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	case IOC_E_DETACH:
54962306a36Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
55062306a36Sopenharmony_ci		break;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	default:
55362306a36Sopenharmony_ci		bfa_sm_fault(event);
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/* IOCPF State Machine */
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci/* Reset entry actions -- initialize state machine */
56062306a36Sopenharmony_cistatic void
56162306a36Sopenharmony_cibfa_iocpf_sm_reset_entry(struct bfa_iocpf *iocpf)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	iocpf->fw_mismatch_notified = false;
56462306a36Sopenharmony_ci	iocpf->auto_recover = bfa_nw_auto_recover;
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci/* Beginning state. IOC is in reset state. */
56862306a36Sopenharmony_cistatic void
56962306a36Sopenharmony_cibfa_iocpf_sm_reset(struct bfa_iocpf *iocpf, enum iocpf_event event)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	switch (event) {
57262306a36Sopenharmony_ci	case IOCPF_E_ENABLE:
57362306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck);
57462306a36Sopenharmony_ci		break;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	case IOCPF_E_STOP:
57762306a36Sopenharmony_ci		break;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	default:
58062306a36Sopenharmony_ci		bfa_sm_fault(event);
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci/* Semaphore should be acquired for version check. */
58562306a36Sopenharmony_cistatic void
58662306a36Sopenharmony_cibfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf *iocpf)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	bfa_ioc_hw_sem_init(iocpf->ioc);
58962306a36Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci/* Awaiting h/w semaphore to continue with version check. */
59362306a36Sopenharmony_cistatic void
59462306a36Sopenharmony_cibfa_iocpf_sm_fwcheck(struct bfa_iocpf *iocpf, enum iocpf_event event)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	switch (event) {
59962306a36Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
60062306a36Sopenharmony_ci		if (bfa_ioc_firmware_lock(ioc)) {
60162306a36Sopenharmony_ci			if (bfa_ioc_sync_start(ioc)) {
60262306a36Sopenharmony_ci				bfa_ioc_sync_join(ioc);
60362306a36Sopenharmony_ci				bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
60462306a36Sopenharmony_ci			} else {
60562306a36Sopenharmony_ci				bfa_ioc_firmware_unlock(ioc);
60662306a36Sopenharmony_ci				bfa_nw_ioc_hw_sem_release(ioc);
60762306a36Sopenharmony_ci				mod_timer(&ioc->sem_timer, jiffies +
60862306a36Sopenharmony_ci					msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
60962306a36Sopenharmony_ci			}
61062306a36Sopenharmony_ci		} else {
61162306a36Sopenharmony_ci			bfa_nw_ioc_hw_sem_release(ioc);
61262306a36Sopenharmony_ci			bfa_fsm_set_state(iocpf, bfa_iocpf_sm_mismatch);
61362306a36Sopenharmony_ci		}
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
61762306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
61862306a36Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
61962306a36Sopenharmony_ci		break;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
62262306a36Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
62362306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
62462306a36Sopenharmony_ci		bfa_ioc_pf_disabled(ioc);
62562306a36Sopenharmony_ci		break;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	case IOCPF_E_STOP:
62862306a36Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
62962306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
63062306a36Sopenharmony_ci		break;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	default:
63362306a36Sopenharmony_ci		bfa_sm_fault(event);
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci/* Notify enable completion callback */
63862306a36Sopenharmony_cistatic void
63962306a36Sopenharmony_cibfa_iocpf_sm_mismatch_entry(struct bfa_iocpf *iocpf)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	/* Call only the first time sm enters fwmismatch state. */
64262306a36Sopenharmony_ci	if (!iocpf->fw_mismatch_notified)
64362306a36Sopenharmony_ci		bfa_ioc_pf_fwmismatch(iocpf->ioc);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	iocpf->fw_mismatch_notified = true;
64662306a36Sopenharmony_ci	mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
64762306a36Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_TOV));
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci/* Awaiting firmware version match. */
65162306a36Sopenharmony_cistatic void
65262306a36Sopenharmony_cibfa_iocpf_sm_mismatch(struct bfa_iocpf *iocpf, enum iocpf_event event)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	switch (event) {
65762306a36Sopenharmony_ci	case IOCPF_E_TIMEOUT:
65862306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck);
65962306a36Sopenharmony_ci		break;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
66262306a36Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
66362306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
66462306a36Sopenharmony_ci		bfa_ioc_pf_disabled(ioc);
66562306a36Sopenharmony_ci		break;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	case IOCPF_E_STOP:
66862306a36Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
66962306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
67062306a36Sopenharmony_ci		break;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	default:
67362306a36Sopenharmony_ci		bfa_sm_fault(event);
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci/* Request for semaphore. */
67862306a36Sopenharmony_cistatic void
67962306a36Sopenharmony_cibfa_iocpf_sm_semwait_entry(struct bfa_iocpf *iocpf)
68062306a36Sopenharmony_ci{
68162306a36Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci/* Awaiting semaphore for h/w initialzation. */
68562306a36Sopenharmony_cistatic void
68662306a36Sopenharmony_cibfa_iocpf_sm_semwait(struct bfa_iocpf *iocpf, enum iocpf_event event)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	switch (event) {
69162306a36Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
69262306a36Sopenharmony_ci		if (bfa_ioc_sync_complete(ioc)) {
69362306a36Sopenharmony_ci			bfa_ioc_sync_join(ioc);
69462306a36Sopenharmony_ci			bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
69562306a36Sopenharmony_ci		} else {
69662306a36Sopenharmony_ci			bfa_nw_ioc_hw_sem_release(ioc);
69762306a36Sopenharmony_ci			mod_timer(&ioc->sem_timer, jiffies +
69862306a36Sopenharmony_ci				msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
69962306a36Sopenharmony_ci		}
70062306a36Sopenharmony_ci		break;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
70362306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
70462306a36Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
70562306a36Sopenharmony_ci		break;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
70862306a36Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
70962306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
71062306a36Sopenharmony_ci		break;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	default:
71362306a36Sopenharmony_ci		bfa_sm_fault(event);
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic void
71862306a36Sopenharmony_cibfa_iocpf_sm_hwinit_entry(struct bfa_iocpf *iocpf)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	iocpf->poll_time = 0;
72162306a36Sopenharmony_ci	bfa_ioc_reset(iocpf->ioc, false);
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci/* Hardware is being initialized. Interrupts are enabled.
72562306a36Sopenharmony_ci * Holding hardware semaphore lock.
72662306a36Sopenharmony_ci */
72762306a36Sopenharmony_cistatic void
72862306a36Sopenharmony_cibfa_iocpf_sm_hwinit(struct bfa_iocpf *iocpf, enum iocpf_event event)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	switch (event) {
73362306a36Sopenharmony_ci	case IOCPF_E_FWREADY:
73462306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_enabling);
73562306a36Sopenharmony_ci		break;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	case IOCPF_E_TIMEOUT:
73862306a36Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
73962306a36Sopenharmony_ci		bfa_ioc_pf_failed(ioc);
74062306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
74162306a36Sopenharmony_ci		break;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
74462306a36Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
74562306a36Sopenharmony_ci		bfa_ioc_sync_leave(ioc);
74662306a36Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
74762306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
74862306a36Sopenharmony_ci		break;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	default:
75162306a36Sopenharmony_ci		bfa_sm_fault(event);
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic void
75662306a36Sopenharmony_cibfa_iocpf_sm_enabling_entry(struct bfa_iocpf *iocpf)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
75962306a36Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_TOV));
76062306a36Sopenharmony_ci	/**
76162306a36Sopenharmony_ci	 * Enable Interrupts before sending fw IOC ENABLE cmd.
76262306a36Sopenharmony_ci	 */
76362306a36Sopenharmony_ci	iocpf->ioc->cbfn->reset_cbfn(iocpf->ioc->bfa);
76462306a36Sopenharmony_ci	bfa_ioc_send_enable(iocpf->ioc);
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci/* Host IOC function is being enabled, awaiting response from firmware.
76862306a36Sopenharmony_ci * Semaphore is acquired.
76962306a36Sopenharmony_ci */
77062306a36Sopenharmony_cistatic void
77162306a36Sopenharmony_cibfa_iocpf_sm_enabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	switch (event) {
77662306a36Sopenharmony_ci	case IOCPF_E_FWRSP_ENABLE:
77762306a36Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
77862306a36Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
77962306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_ready);
78062306a36Sopenharmony_ci		break;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	case IOCPF_E_INITFAIL:
78362306a36Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
78462306a36Sopenharmony_ci		fallthrough;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	case IOCPF_E_TIMEOUT:
78762306a36Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
78862306a36Sopenharmony_ci		if (event == IOCPF_E_TIMEOUT)
78962306a36Sopenharmony_ci			bfa_ioc_pf_failed(ioc);
79062306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
79162306a36Sopenharmony_ci		break;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
79462306a36Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
79562306a36Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
79662306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
79762306a36Sopenharmony_ci		break;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	default:
80062306a36Sopenharmony_ci		bfa_sm_fault(event);
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cistatic void
80562306a36Sopenharmony_cibfa_iocpf_sm_ready_entry(struct bfa_iocpf *iocpf)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	bfa_ioc_pf_enabled(iocpf->ioc);
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cistatic void
81162306a36Sopenharmony_cibfa_iocpf_sm_ready(struct bfa_iocpf *iocpf, enum iocpf_event event)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	switch (event) {
81462306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
81562306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
81662306a36Sopenharmony_ci		break;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	case IOCPF_E_GETATTRFAIL:
81962306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
82062306a36Sopenharmony_ci		break;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	case IOCPF_E_FAIL:
82362306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
82462306a36Sopenharmony_ci		break;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	default:
82762306a36Sopenharmony_ci		bfa_sm_fault(event);
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_cistatic void
83262306a36Sopenharmony_cibfa_iocpf_sm_disabling_entry(struct bfa_iocpf *iocpf)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
83562306a36Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_TOV));
83662306a36Sopenharmony_ci	bfa_ioc_send_disable(iocpf->ioc);
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci/* IOC is being disabled */
84062306a36Sopenharmony_cistatic void
84162306a36Sopenharmony_cibfa_iocpf_sm_disabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	switch (event) {
84662306a36Sopenharmony_ci	case IOCPF_E_FWRSP_DISABLE:
84762306a36Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
84862306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
84962306a36Sopenharmony_ci		break;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	case IOCPF_E_FAIL:
85262306a36Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
85362306a36Sopenharmony_ci		fallthrough;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	case IOCPF_E_TIMEOUT:
85662306a36Sopenharmony_ci		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
85762306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
85862306a36Sopenharmony_ci		break;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	case IOCPF_E_FWRSP_ENABLE:
86162306a36Sopenharmony_ci		break;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	default:
86462306a36Sopenharmony_ci		bfa_sm_fault(event);
86562306a36Sopenharmony_ci	}
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cistatic void
86962306a36Sopenharmony_cibfa_iocpf_sm_disabling_sync_entry(struct bfa_iocpf *iocpf)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci/* IOC hb ack request is being removed. */
87562306a36Sopenharmony_cistatic void
87662306a36Sopenharmony_cibfa_iocpf_sm_disabling_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	switch (event) {
88162306a36Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
88262306a36Sopenharmony_ci		bfa_ioc_sync_leave(ioc);
88362306a36Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
88462306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
88562306a36Sopenharmony_ci		break;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
88862306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
88962306a36Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
89062306a36Sopenharmony_ci		break;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	case IOCPF_E_FAIL:
89362306a36Sopenharmony_ci		break;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	default:
89662306a36Sopenharmony_ci		bfa_sm_fault(event);
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci/* IOC disable completion entry. */
90162306a36Sopenharmony_cistatic void
90262306a36Sopenharmony_cibfa_iocpf_sm_disabled_entry(struct bfa_iocpf *iocpf)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	bfa_ioc_mbox_flush(iocpf->ioc);
90562306a36Sopenharmony_ci	bfa_ioc_pf_disabled(iocpf->ioc);
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_cistatic void
90962306a36Sopenharmony_cibfa_iocpf_sm_disabled(struct bfa_iocpf *iocpf, enum iocpf_event event)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	switch (event) {
91462306a36Sopenharmony_ci	case IOCPF_E_ENABLE:
91562306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
91662306a36Sopenharmony_ci		break;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	case IOCPF_E_STOP:
91962306a36Sopenharmony_ci		bfa_ioc_firmware_unlock(ioc);
92062306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
92162306a36Sopenharmony_ci		break;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	default:
92462306a36Sopenharmony_ci		bfa_sm_fault(event);
92562306a36Sopenharmony_ci	}
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_cistatic void
92962306a36Sopenharmony_cibfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf *iocpf)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	bfa_nw_ioc_debug_save_ftrc(iocpf->ioc);
93262306a36Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci/* Hardware initialization failed. */
93662306a36Sopenharmony_cistatic void
93762306a36Sopenharmony_cibfa_iocpf_sm_initfail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	switch (event) {
94262306a36Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
94362306a36Sopenharmony_ci		bfa_ioc_notify_fail(ioc);
94462306a36Sopenharmony_ci		bfa_ioc_sync_leave(ioc);
94562306a36Sopenharmony_ci		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
94662306a36Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
94762306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
94862306a36Sopenharmony_ci		break;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
95162306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
95262306a36Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
95362306a36Sopenharmony_ci		break;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
95662306a36Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
95762306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
95862306a36Sopenharmony_ci		break;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	case IOCPF_E_STOP:
96162306a36Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
96262306a36Sopenharmony_ci		bfa_ioc_firmware_unlock(ioc);
96362306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
96462306a36Sopenharmony_ci		break;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	case IOCPF_E_FAIL:
96762306a36Sopenharmony_ci		break;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	default:
97062306a36Sopenharmony_ci		bfa_sm_fault(event);
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_cistatic void
97562306a36Sopenharmony_cibfa_iocpf_sm_initfail_entry(struct bfa_iocpf *iocpf)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci/* Hardware initialization failed. */
98062306a36Sopenharmony_cistatic void
98162306a36Sopenharmony_cibfa_iocpf_sm_initfail(struct bfa_iocpf *iocpf, enum iocpf_event event)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	switch (event) {
98662306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
98762306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
98862306a36Sopenharmony_ci		break;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	case IOCPF_E_STOP:
99162306a36Sopenharmony_ci		bfa_ioc_firmware_unlock(ioc);
99262306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
99362306a36Sopenharmony_ci		break;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	default:
99662306a36Sopenharmony_ci		bfa_sm_fault(event);
99762306a36Sopenharmony_ci	}
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_cistatic void
100162306a36Sopenharmony_cibfa_iocpf_sm_fail_sync_entry(struct bfa_iocpf *iocpf)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	/**
100462306a36Sopenharmony_ci	 * Mark IOC as failed in hardware and stop firmware.
100562306a36Sopenharmony_ci	 */
100662306a36Sopenharmony_ci	bfa_ioc_lpu_stop(iocpf->ioc);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	/**
100962306a36Sopenharmony_ci	 * Flush any queued up mailbox requests.
101062306a36Sopenharmony_ci	 */
101162306a36Sopenharmony_ci	bfa_ioc_mbox_flush(iocpf->ioc);
101262306a36Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci/* IOC is in failed state. */
101662306a36Sopenharmony_cistatic void
101762306a36Sopenharmony_cibfa_iocpf_sm_fail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	switch (event) {
102262306a36Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
102362306a36Sopenharmony_ci		bfa_ioc_sync_ack(ioc);
102462306a36Sopenharmony_ci		bfa_ioc_notify_fail(ioc);
102562306a36Sopenharmony_ci		if (!iocpf->auto_recover) {
102662306a36Sopenharmony_ci			bfa_ioc_sync_leave(ioc);
102762306a36Sopenharmony_ci			bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
102862306a36Sopenharmony_ci			bfa_nw_ioc_hw_sem_release(ioc);
102962306a36Sopenharmony_ci			bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
103062306a36Sopenharmony_ci		} else {
103162306a36Sopenharmony_ci			if (bfa_ioc_sync_complete(ioc))
103262306a36Sopenharmony_ci				bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
103362306a36Sopenharmony_ci			else {
103462306a36Sopenharmony_ci				bfa_nw_ioc_hw_sem_release(ioc);
103562306a36Sopenharmony_ci				bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
103662306a36Sopenharmony_ci			}
103762306a36Sopenharmony_ci		}
103862306a36Sopenharmony_ci		break;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
104162306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
104262306a36Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
104362306a36Sopenharmony_ci		break;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
104662306a36Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
104762306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
104862306a36Sopenharmony_ci		break;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	case IOCPF_E_FAIL:
105162306a36Sopenharmony_ci		break;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	default:
105462306a36Sopenharmony_ci		bfa_sm_fault(event);
105562306a36Sopenharmony_ci	}
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_cistatic void
105962306a36Sopenharmony_cibfa_iocpf_sm_fail_entry(struct bfa_iocpf *iocpf)
106062306a36Sopenharmony_ci{
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci/* IOC is in failed state. */
106462306a36Sopenharmony_cistatic void
106562306a36Sopenharmony_cibfa_iocpf_sm_fail(struct bfa_iocpf *iocpf, enum iocpf_event event)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	switch (event) {
106862306a36Sopenharmony_ci	case IOCPF_E_DISABLE:
106962306a36Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
107062306a36Sopenharmony_ci		break;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	default:
107362306a36Sopenharmony_ci		bfa_sm_fault(event);
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci/* BFA IOC private functions */
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci/* Notify common modules registered for notification. */
108062306a36Sopenharmony_cistatic void
108162306a36Sopenharmony_cibfa_ioc_event_notify(struct bfa_ioc *ioc, enum bfa_ioc_event event)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	struct bfa_ioc_notify *notify;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	list_for_each_entry(notify, &ioc->notify_q, qe)
108662306a36Sopenharmony_ci		notify->cbfn(notify->cbarg, event);
108762306a36Sopenharmony_ci}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_cistatic void
109062306a36Sopenharmony_cibfa_ioc_disable_comp(struct bfa_ioc *ioc)
109162306a36Sopenharmony_ci{
109262306a36Sopenharmony_ci	ioc->cbfn->disable_cbfn(ioc->bfa);
109362306a36Sopenharmony_ci	bfa_ioc_event_notify(ioc, BFA_IOC_E_DISABLED);
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cibool
109762306a36Sopenharmony_cibfa_nw_ioc_sem_get(void __iomem *sem_reg)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	u32 r32;
110062306a36Sopenharmony_ci	int cnt = 0;
110162306a36Sopenharmony_ci#define BFA_SEM_SPINCNT	3000
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	r32 = readl(sem_reg);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	while ((r32 & 1) && (cnt < BFA_SEM_SPINCNT)) {
110662306a36Sopenharmony_ci		cnt++;
110762306a36Sopenharmony_ci		udelay(2);
110862306a36Sopenharmony_ci		r32 = readl(sem_reg);
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	if (!(r32 & 1))
111262306a36Sopenharmony_ci		return true;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	return false;
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_civoid
111862306a36Sopenharmony_cibfa_nw_ioc_sem_release(void __iomem *sem_reg)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	readl(sem_reg);
112162306a36Sopenharmony_ci	writel(1, sem_reg);
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci/* Clear fwver hdr */
112562306a36Sopenharmony_cistatic void
112662306a36Sopenharmony_cibfa_ioc_fwver_clear(struct bfa_ioc *ioc)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	u32 pgnum, loff = 0;
112962306a36Sopenharmony_ci	int i;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);
113262306a36Sopenharmony_ci	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32)); i++) {
113562306a36Sopenharmony_ci		writel(0, ioc->ioc_regs.smem_page_start + loff);
113662306a36Sopenharmony_ci		loff += sizeof(u32);
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic void
114262306a36Sopenharmony_cibfa_ioc_hw_sem_init(struct bfa_ioc *ioc)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct bfi_ioc_image_hdr fwhdr;
114562306a36Sopenharmony_ci	u32 fwstate, r32;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	/* Spin on init semaphore to serialize. */
114862306a36Sopenharmony_ci	r32 = readl(ioc->ioc_regs.ioc_init_sem_reg);
114962306a36Sopenharmony_ci	while (r32 & 0x1) {
115062306a36Sopenharmony_ci		udelay(20);
115162306a36Sopenharmony_ci		r32 = readl(ioc->ioc_regs.ioc_init_sem_reg);
115262306a36Sopenharmony_ci	}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
115562306a36Sopenharmony_ci	if (fwstate == BFI_IOC_UNINIT) {
115662306a36Sopenharmony_ci		writel(1, ioc->ioc_regs.ioc_init_sem_reg);
115762306a36Sopenharmony_ci		return;
115862306a36Sopenharmony_ci	}
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	bfa_nw_ioc_fwver_get(ioc, &fwhdr);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL) {
116362306a36Sopenharmony_ci		writel(1, ioc->ioc_regs.ioc_init_sem_reg);
116462306a36Sopenharmony_ci		return;
116562306a36Sopenharmony_ci	}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	bfa_ioc_fwver_clear(ioc);
116862306a36Sopenharmony_ci	bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_UNINIT);
116962306a36Sopenharmony_ci	bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_UNINIT);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	/*
117262306a36Sopenharmony_ci	 * Try to lock and then unlock the semaphore.
117362306a36Sopenharmony_ci	 */
117462306a36Sopenharmony_ci	readl(ioc->ioc_regs.ioc_sem_reg);
117562306a36Sopenharmony_ci	writel(1, ioc->ioc_regs.ioc_sem_reg);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	/* Unlock init semaphore */
117862306a36Sopenharmony_ci	writel(1, ioc->ioc_regs.ioc_init_sem_reg);
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_cistatic void
118262306a36Sopenharmony_cibfa_ioc_hw_sem_get(struct bfa_ioc *ioc)
118362306a36Sopenharmony_ci{
118462306a36Sopenharmony_ci	u32	r32;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/**
118762306a36Sopenharmony_ci	 * First read to the semaphore register will return 0, subsequent reads
118862306a36Sopenharmony_ci	 * will return 1. Semaphore is released by writing 1 to the register
118962306a36Sopenharmony_ci	 */
119062306a36Sopenharmony_ci	r32 = readl(ioc->ioc_regs.ioc_sem_reg);
119162306a36Sopenharmony_ci	if (r32 == ~0) {
119262306a36Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEM_ERROR);
119362306a36Sopenharmony_ci		return;
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci	if (!(r32 & 1)) {
119662306a36Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED);
119762306a36Sopenharmony_ci		return;
119862306a36Sopenharmony_ci	}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	mod_timer(&ioc->sem_timer, jiffies +
120162306a36Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_civoid
120562306a36Sopenharmony_cibfa_nw_ioc_hw_sem_release(struct bfa_ioc *ioc)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	writel(1, ioc->ioc_regs.ioc_sem_reg);
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_cistatic void
121162306a36Sopenharmony_cibfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc)
121262306a36Sopenharmony_ci{
121362306a36Sopenharmony_ci	del_timer(&ioc->sem_timer);
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci/* Initialize LPU local memory (aka secondary memory / SRAM) */
121762306a36Sopenharmony_cistatic void
121862306a36Sopenharmony_cibfa_ioc_lmem_init(struct bfa_ioc *ioc)
121962306a36Sopenharmony_ci{
122062306a36Sopenharmony_ci	u32	pss_ctl;
122162306a36Sopenharmony_ci	int		i;
122262306a36Sopenharmony_ci#define PSS_LMEM_INIT_TIME  10000
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
122562306a36Sopenharmony_ci	pss_ctl &= ~__PSS_LMEM_RESET;
122662306a36Sopenharmony_ci	pss_ctl |= __PSS_LMEM_INIT_EN;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	/*
122962306a36Sopenharmony_ci	 * i2c workaround 12.5khz clock
123062306a36Sopenharmony_ci	 */
123162306a36Sopenharmony_ci	pss_ctl |= __PSS_I2C_CLK_DIV(3UL);
123262306a36Sopenharmony_ci	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	/**
123562306a36Sopenharmony_ci	 * wait for memory initialization to be complete
123662306a36Sopenharmony_ci	 */
123762306a36Sopenharmony_ci	i = 0;
123862306a36Sopenharmony_ci	do {
123962306a36Sopenharmony_ci		pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
124062306a36Sopenharmony_ci		i++;
124162306a36Sopenharmony_ci	} while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	/**
124462306a36Sopenharmony_ci	 * If memory initialization is not successful, IOC timeout will catch
124562306a36Sopenharmony_ci	 * such failures.
124662306a36Sopenharmony_ci	 */
124762306a36Sopenharmony_ci	BUG_ON(!(pss_ctl & __PSS_LMEM_INIT_DONE));
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
125062306a36Sopenharmony_ci	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_cistatic void
125462306a36Sopenharmony_cibfa_ioc_lpu_start(struct bfa_ioc *ioc)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	u32	pss_ctl;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	/**
125962306a36Sopenharmony_ci	 * Take processor out of reset.
126062306a36Sopenharmony_ci	 */
126162306a36Sopenharmony_ci	pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
126262306a36Sopenharmony_ci	pss_ctl &= ~__PSS_LPU0_RESET;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
126562306a36Sopenharmony_ci}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_cistatic void
126862306a36Sopenharmony_cibfa_ioc_lpu_stop(struct bfa_ioc *ioc)
126962306a36Sopenharmony_ci{
127062306a36Sopenharmony_ci	u32	pss_ctl;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	/**
127362306a36Sopenharmony_ci	 * Put processors in reset.
127462306a36Sopenharmony_ci	 */
127562306a36Sopenharmony_ci	pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
127662306a36Sopenharmony_ci	pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci/* Get driver and firmware versions. */
128262306a36Sopenharmony_civoid
128362306a36Sopenharmony_cibfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	u32	pgnum;
128662306a36Sopenharmony_ci	u32	loff = 0;
128762306a36Sopenharmony_ci	int		i;
128862306a36Sopenharmony_ci	u32	*fwsig = (u32 *) fwhdr;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	pgnum = bfa_ioc_smem_pgnum(ioc, loff);
129162306a36Sopenharmony_ci	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32));
129462306a36Sopenharmony_ci	     i++) {
129562306a36Sopenharmony_ci		fwsig[i] =
129662306a36Sopenharmony_ci			swab32(readl(loff + ioc->ioc_regs.smem_page_start));
129762306a36Sopenharmony_ci		loff += sizeof(u32);
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_cistatic bool
130262306a36Sopenharmony_cibfa_ioc_fwver_md5_check(struct bfi_ioc_image_hdr *fwhdr_1,
130362306a36Sopenharmony_ci			struct bfi_ioc_image_hdr *fwhdr_2)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	int i;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
130862306a36Sopenharmony_ci		if (fwhdr_1->md5sum[i] != fwhdr_2->md5sum[i])
130962306a36Sopenharmony_ci			return false;
131062306a36Sopenharmony_ci	}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	return true;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci/* Returns TRUE if major minor and maintenance are same.
131662306a36Sopenharmony_ci * If patch version are same, check for MD5 Checksum to be same.
131762306a36Sopenharmony_ci */
131862306a36Sopenharmony_cistatic bool
131962306a36Sopenharmony_cibfa_ioc_fw_ver_compatible(struct bfi_ioc_image_hdr *drv_fwhdr,
132062306a36Sopenharmony_ci			  struct bfi_ioc_image_hdr *fwhdr_to_cmp)
132162306a36Sopenharmony_ci{
132262306a36Sopenharmony_ci	if (drv_fwhdr->signature != fwhdr_to_cmp->signature)
132362306a36Sopenharmony_ci		return false;
132462306a36Sopenharmony_ci	if (drv_fwhdr->fwver.major != fwhdr_to_cmp->fwver.major)
132562306a36Sopenharmony_ci		return false;
132662306a36Sopenharmony_ci	if (drv_fwhdr->fwver.minor != fwhdr_to_cmp->fwver.minor)
132762306a36Sopenharmony_ci		return false;
132862306a36Sopenharmony_ci	if (drv_fwhdr->fwver.maint != fwhdr_to_cmp->fwver.maint)
132962306a36Sopenharmony_ci		return false;
133062306a36Sopenharmony_ci	if (drv_fwhdr->fwver.patch == fwhdr_to_cmp->fwver.patch &&
133162306a36Sopenharmony_ci	    drv_fwhdr->fwver.phase == fwhdr_to_cmp->fwver.phase &&
133262306a36Sopenharmony_ci	    drv_fwhdr->fwver.build == fwhdr_to_cmp->fwver.build)
133362306a36Sopenharmony_ci		return bfa_ioc_fwver_md5_check(drv_fwhdr, fwhdr_to_cmp);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	return true;
133662306a36Sopenharmony_ci}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_cistatic bool
133962306a36Sopenharmony_cibfa_ioc_flash_fwver_valid(struct bfi_ioc_image_hdr *flash_fwhdr)
134062306a36Sopenharmony_ci{
134162306a36Sopenharmony_ci	if (flash_fwhdr->fwver.major == 0 || flash_fwhdr->fwver.major == 0xFF)
134262306a36Sopenharmony_ci		return false;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	return true;
134562306a36Sopenharmony_ci}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_cistatic bool
134862306a36Sopenharmony_cifwhdr_is_ga(struct bfi_ioc_image_hdr *fwhdr)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	if (fwhdr->fwver.phase == 0 &&
135162306a36Sopenharmony_ci	    fwhdr->fwver.build == 0)
135262306a36Sopenharmony_ci		return false;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	return true;
135562306a36Sopenharmony_ci}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci/* Returns TRUE if both are compatible and patch of fwhdr_to_cmp is better. */
135862306a36Sopenharmony_cistatic enum bfi_ioc_img_ver_cmp
135962306a36Sopenharmony_cibfa_ioc_fw_ver_patch_cmp(struct bfi_ioc_image_hdr *base_fwhdr,
136062306a36Sopenharmony_ci			 struct bfi_ioc_image_hdr *fwhdr_to_cmp)
136162306a36Sopenharmony_ci{
136262306a36Sopenharmony_ci	if (!bfa_ioc_fw_ver_compatible(base_fwhdr, fwhdr_to_cmp))
136362306a36Sopenharmony_ci		return BFI_IOC_IMG_VER_INCOMP;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	if (fwhdr_to_cmp->fwver.patch > base_fwhdr->fwver.patch)
136662306a36Sopenharmony_ci		return BFI_IOC_IMG_VER_BETTER;
136762306a36Sopenharmony_ci	else if (fwhdr_to_cmp->fwver.patch < base_fwhdr->fwver.patch)
136862306a36Sopenharmony_ci		return BFI_IOC_IMG_VER_OLD;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	/* GA takes priority over internal builds of the same patch stream.
137162306a36Sopenharmony_ci	 * At this point major minor maint and patch numbers are same.
137262306a36Sopenharmony_ci	 */
137362306a36Sopenharmony_ci	if (fwhdr_is_ga(base_fwhdr))
137462306a36Sopenharmony_ci		if (fwhdr_is_ga(fwhdr_to_cmp))
137562306a36Sopenharmony_ci			return BFI_IOC_IMG_VER_SAME;
137662306a36Sopenharmony_ci		else
137762306a36Sopenharmony_ci			return BFI_IOC_IMG_VER_OLD;
137862306a36Sopenharmony_ci	else
137962306a36Sopenharmony_ci		if (fwhdr_is_ga(fwhdr_to_cmp))
138062306a36Sopenharmony_ci			return BFI_IOC_IMG_VER_BETTER;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	if (fwhdr_to_cmp->fwver.phase > base_fwhdr->fwver.phase)
138362306a36Sopenharmony_ci		return BFI_IOC_IMG_VER_BETTER;
138462306a36Sopenharmony_ci	else if (fwhdr_to_cmp->fwver.phase < base_fwhdr->fwver.phase)
138562306a36Sopenharmony_ci		return BFI_IOC_IMG_VER_OLD;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	if (fwhdr_to_cmp->fwver.build > base_fwhdr->fwver.build)
138862306a36Sopenharmony_ci		return BFI_IOC_IMG_VER_BETTER;
138962306a36Sopenharmony_ci	else if (fwhdr_to_cmp->fwver.build < base_fwhdr->fwver.build)
139062306a36Sopenharmony_ci		return BFI_IOC_IMG_VER_OLD;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	/* All Version Numbers are equal.
139362306a36Sopenharmony_ci	 * Md5 check to be done as a part of compatibility check.
139462306a36Sopenharmony_ci	 */
139562306a36Sopenharmony_ci	return BFI_IOC_IMG_VER_SAME;
139662306a36Sopenharmony_ci}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci/* register definitions */
139962306a36Sopenharmony_ci#define FLI_CMD_REG			0x0001d000
140062306a36Sopenharmony_ci#define FLI_WRDATA_REG			0x0001d00c
140162306a36Sopenharmony_ci#define FLI_RDDATA_REG			0x0001d010
140262306a36Sopenharmony_ci#define FLI_ADDR_REG			0x0001d004
140362306a36Sopenharmony_ci#define FLI_DEV_STATUS_REG		0x0001d014
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci#define BFA_FLASH_FIFO_SIZE		128	/* fifo size */
140662306a36Sopenharmony_ci#define BFA_FLASH_CHECK_MAX		10000	/* max # of status check */
140762306a36Sopenharmony_ci#define BFA_FLASH_BLOCKING_OP_MAX	1000000	/* max # of blocking op check */
140862306a36Sopenharmony_ci#define BFA_FLASH_WIP_MASK		0x01	/* write in progress bit mask */
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci#define NFC_STATE_RUNNING		0x20000001
141162306a36Sopenharmony_ci#define NFC_STATE_PAUSED		0x00004560
141262306a36Sopenharmony_ci#define NFC_VER_VALID			0x147
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_cienum bfa_flash_cmd {
141562306a36Sopenharmony_ci	BFA_FLASH_FAST_READ	= 0x0b,	/* fast read */
141662306a36Sopenharmony_ci	BFA_FLASH_WRITE_ENABLE	= 0x06,	/* write enable */
141762306a36Sopenharmony_ci	BFA_FLASH_SECTOR_ERASE	= 0xd8,	/* sector erase */
141862306a36Sopenharmony_ci	BFA_FLASH_WRITE		= 0x02,	/* write */
141962306a36Sopenharmony_ci	BFA_FLASH_READ_STATUS	= 0x05,	/* read status */
142062306a36Sopenharmony_ci};
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci/* hardware error definition */
142362306a36Sopenharmony_cienum bfa_flash_err {
142462306a36Sopenharmony_ci	BFA_FLASH_NOT_PRESENT	= -1,	/*!< flash not present */
142562306a36Sopenharmony_ci	BFA_FLASH_UNINIT	= -2,	/*!< flash not initialized */
142662306a36Sopenharmony_ci	BFA_FLASH_BAD		= -3,	/*!< flash bad */
142762306a36Sopenharmony_ci	BFA_FLASH_BUSY		= -4,	/*!< flash busy */
142862306a36Sopenharmony_ci	BFA_FLASH_ERR_CMD_ACT	= -5,	/*!< command active never cleared */
142962306a36Sopenharmony_ci	BFA_FLASH_ERR_FIFO_CNT	= -6,	/*!< fifo count never cleared */
143062306a36Sopenharmony_ci	BFA_FLASH_ERR_WIP	= -7,	/*!< write-in-progress never cleared */
143162306a36Sopenharmony_ci	BFA_FLASH_ERR_TIMEOUT	= -8,	/*!< fli timeout */
143262306a36Sopenharmony_ci	BFA_FLASH_ERR_LEN	= -9,	/*!< invalid length */
143362306a36Sopenharmony_ci};
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci/* flash command register data structure */
143662306a36Sopenharmony_ciunion bfa_flash_cmd_reg {
143762306a36Sopenharmony_ci	struct {
143862306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
143962306a36Sopenharmony_ci		u32	act:1;
144062306a36Sopenharmony_ci		u32	rsv:1;
144162306a36Sopenharmony_ci		u32	write_cnt:9;
144262306a36Sopenharmony_ci		u32	read_cnt:9;
144362306a36Sopenharmony_ci		u32	addr_cnt:4;
144462306a36Sopenharmony_ci		u32	cmd:8;
144562306a36Sopenharmony_ci#else
144662306a36Sopenharmony_ci		u32	cmd:8;
144762306a36Sopenharmony_ci		u32	addr_cnt:4;
144862306a36Sopenharmony_ci		u32	read_cnt:9;
144962306a36Sopenharmony_ci		u32	write_cnt:9;
145062306a36Sopenharmony_ci		u32	rsv:1;
145162306a36Sopenharmony_ci		u32	act:1;
145262306a36Sopenharmony_ci#endif
145362306a36Sopenharmony_ci	} r;
145462306a36Sopenharmony_ci	u32	i;
145562306a36Sopenharmony_ci};
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci/* flash device status register data structure */
145862306a36Sopenharmony_ciunion bfa_flash_dev_status_reg {
145962306a36Sopenharmony_ci	struct {
146062306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
146162306a36Sopenharmony_ci		u32	rsv:21;
146262306a36Sopenharmony_ci		u32	fifo_cnt:6;
146362306a36Sopenharmony_ci		u32	busy:1;
146462306a36Sopenharmony_ci		u32	init_status:1;
146562306a36Sopenharmony_ci		u32	present:1;
146662306a36Sopenharmony_ci		u32	bad:1;
146762306a36Sopenharmony_ci		u32	good:1;
146862306a36Sopenharmony_ci#else
146962306a36Sopenharmony_ci		u32	good:1;
147062306a36Sopenharmony_ci		u32	bad:1;
147162306a36Sopenharmony_ci		u32	present:1;
147262306a36Sopenharmony_ci		u32	init_status:1;
147362306a36Sopenharmony_ci		u32	busy:1;
147462306a36Sopenharmony_ci		u32	fifo_cnt:6;
147562306a36Sopenharmony_ci		u32	rsv:21;
147662306a36Sopenharmony_ci#endif
147762306a36Sopenharmony_ci	} r;
147862306a36Sopenharmony_ci	u32	i;
147962306a36Sopenharmony_ci};
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci/* flash address register data structure */
148262306a36Sopenharmony_ciunion bfa_flash_addr_reg {
148362306a36Sopenharmony_ci	struct {
148462306a36Sopenharmony_ci#ifdef __BIG_ENDIAN
148562306a36Sopenharmony_ci		u32	addr:24;
148662306a36Sopenharmony_ci		u32	dummy:8;
148762306a36Sopenharmony_ci#else
148862306a36Sopenharmony_ci		u32	dummy:8;
148962306a36Sopenharmony_ci		u32	addr:24;
149062306a36Sopenharmony_ci#endif
149162306a36Sopenharmony_ci	} r;
149262306a36Sopenharmony_ci	u32	i;
149362306a36Sopenharmony_ci};
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci/* Flash raw private functions */
149662306a36Sopenharmony_cistatic void
149762306a36Sopenharmony_cibfa_flash_set_cmd(void __iomem *pci_bar, u8 wr_cnt,
149862306a36Sopenharmony_ci		  u8 rd_cnt, u8 ad_cnt, u8 op)
149962306a36Sopenharmony_ci{
150062306a36Sopenharmony_ci	union bfa_flash_cmd_reg cmd;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	cmd.i = 0;
150362306a36Sopenharmony_ci	cmd.r.act = 1;
150462306a36Sopenharmony_ci	cmd.r.write_cnt = wr_cnt;
150562306a36Sopenharmony_ci	cmd.r.read_cnt = rd_cnt;
150662306a36Sopenharmony_ci	cmd.r.addr_cnt = ad_cnt;
150762306a36Sopenharmony_ci	cmd.r.cmd = op;
150862306a36Sopenharmony_ci	writel(cmd.i, (pci_bar + FLI_CMD_REG));
150962306a36Sopenharmony_ci}
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_cistatic void
151262306a36Sopenharmony_cibfa_flash_set_addr(void __iomem *pci_bar, u32 address)
151362306a36Sopenharmony_ci{
151462306a36Sopenharmony_ci	union bfa_flash_addr_reg addr;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	addr.r.addr = address & 0x00ffffff;
151762306a36Sopenharmony_ci	addr.r.dummy = 0;
151862306a36Sopenharmony_ci	writel(addr.i, (pci_bar + FLI_ADDR_REG));
151962306a36Sopenharmony_ci}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_cistatic int
152262306a36Sopenharmony_cibfa_flash_cmd_act_check(void __iomem *pci_bar)
152362306a36Sopenharmony_ci{
152462306a36Sopenharmony_ci	union bfa_flash_cmd_reg cmd;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	cmd.i = readl(pci_bar + FLI_CMD_REG);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (cmd.r.act)
152962306a36Sopenharmony_ci		return BFA_FLASH_ERR_CMD_ACT;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	return 0;
153262306a36Sopenharmony_ci}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci/* Flush FLI data fifo. */
153562306a36Sopenharmony_cistatic int
153662306a36Sopenharmony_cibfa_flash_fifo_flush(void __iomem *pci_bar)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	u32 i;
153962306a36Sopenharmony_ci	union bfa_flash_dev_status_reg dev_status;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	if (!dev_status.r.fifo_cnt)
154462306a36Sopenharmony_ci		return 0;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	/* fifo counter in terms of words */
154762306a36Sopenharmony_ci	for (i = 0; i < dev_status.r.fifo_cnt; i++)
154862306a36Sopenharmony_ci		readl(pci_bar + FLI_RDDATA_REG);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	/* Check the device status. It may take some time. */
155162306a36Sopenharmony_ci	for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) {
155262306a36Sopenharmony_ci		dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);
155362306a36Sopenharmony_ci		if (!dev_status.r.fifo_cnt)
155462306a36Sopenharmony_ci			break;
155562306a36Sopenharmony_ci	}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	if (dev_status.r.fifo_cnt)
155862306a36Sopenharmony_ci		return BFA_FLASH_ERR_FIFO_CNT;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	return 0;
156162306a36Sopenharmony_ci}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci/* Read flash status. */
156462306a36Sopenharmony_cistatic int
156562306a36Sopenharmony_cibfa_flash_status_read(void __iomem *pci_bar)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	union bfa_flash_dev_status_reg	dev_status;
156862306a36Sopenharmony_ci	int				status;
156962306a36Sopenharmony_ci	u32			ret_status;
157062306a36Sopenharmony_ci	int				i;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	status = bfa_flash_fifo_flush(pci_bar);
157362306a36Sopenharmony_ci	if (status < 0)
157462306a36Sopenharmony_ci		return status;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	bfa_flash_set_cmd(pci_bar, 0, 4, 0, BFA_FLASH_READ_STATUS);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) {
157962306a36Sopenharmony_ci		status = bfa_flash_cmd_act_check(pci_bar);
158062306a36Sopenharmony_ci		if (!status)
158162306a36Sopenharmony_ci			break;
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	if (status)
158562306a36Sopenharmony_ci		return status;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);
158862306a36Sopenharmony_ci	if (!dev_status.r.fifo_cnt)
158962306a36Sopenharmony_ci		return BFA_FLASH_BUSY;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	ret_status = readl(pci_bar + FLI_RDDATA_REG);
159262306a36Sopenharmony_ci	ret_status >>= 24;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	status = bfa_flash_fifo_flush(pci_bar);
159562306a36Sopenharmony_ci	if (status < 0)
159662306a36Sopenharmony_ci		return status;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	return ret_status;
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci/* Start flash read operation. */
160262306a36Sopenharmony_cistatic int
160362306a36Sopenharmony_cibfa_flash_read_start(void __iomem *pci_bar, u32 offset, u32 len,
160462306a36Sopenharmony_ci		     char *buf)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	int status;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	/* len must be mutiple of 4 and not exceeding fifo size */
160962306a36Sopenharmony_ci	if (len == 0 || len > BFA_FLASH_FIFO_SIZE || (len & 0x03) != 0)
161062306a36Sopenharmony_ci		return BFA_FLASH_ERR_LEN;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	/* check status */
161362306a36Sopenharmony_ci	status = bfa_flash_status_read(pci_bar);
161462306a36Sopenharmony_ci	if (status == BFA_FLASH_BUSY)
161562306a36Sopenharmony_ci		status = bfa_flash_status_read(pci_bar);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	if (status < 0)
161862306a36Sopenharmony_ci		return status;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	/* check if write-in-progress bit is cleared */
162162306a36Sopenharmony_ci	if (status & BFA_FLASH_WIP_MASK)
162262306a36Sopenharmony_ci		return BFA_FLASH_ERR_WIP;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	bfa_flash_set_addr(pci_bar, offset);
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	bfa_flash_set_cmd(pci_bar, 0, (u8)len, 4, BFA_FLASH_FAST_READ);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	return 0;
162962306a36Sopenharmony_ci}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci/* Check flash read operation. */
163262306a36Sopenharmony_cistatic u32
163362306a36Sopenharmony_cibfa_flash_read_check(void __iomem *pci_bar)
163462306a36Sopenharmony_ci{
163562306a36Sopenharmony_ci	if (bfa_flash_cmd_act_check(pci_bar))
163662306a36Sopenharmony_ci		return 1;
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	return 0;
163962306a36Sopenharmony_ci}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci/* End flash read operation. */
164262306a36Sopenharmony_cistatic void
164362306a36Sopenharmony_cibfa_flash_read_end(void __iomem *pci_bar, u32 len, char *buf)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	u32 i;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	/* read data fifo up to 32 words */
164862306a36Sopenharmony_ci	for (i = 0; i < len; i += 4) {
164962306a36Sopenharmony_ci		u32 w = readl(pci_bar + FLI_RDDATA_REG);
165062306a36Sopenharmony_ci		*((u32 *)(buf + i)) = swab32(w);
165162306a36Sopenharmony_ci	}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	bfa_flash_fifo_flush(pci_bar);
165462306a36Sopenharmony_ci}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci/* Perform flash raw read. */
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci#define FLASH_BLOCKING_OP_MAX   500
165962306a36Sopenharmony_ci#define FLASH_SEM_LOCK_REG	0x18820
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_cistatic int
166262306a36Sopenharmony_cibfa_raw_sem_get(void __iomem *bar)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci	int	locked;
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	locked = readl(bar + FLASH_SEM_LOCK_REG);
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	return !locked;
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cistatic enum bfa_status
167262306a36Sopenharmony_cibfa_flash_sem_get(void __iomem *bar)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	u32 n = FLASH_BLOCKING_OP_MAX;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	while (!bfa_raw_sem_get(bar)) {
167762306a36Sopenharmony_ci		if (--n <= 0)
167862306a36Sopenharmony_ci			return BFA_STATUS_BADFLASH;
167962306a36Sopenharmony_ci		mdelay(10);
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci	return BFA_STATUS_OK;
168262306a36Sopenharmony_ci}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_cistatic void
168562306a36Sopenharmony_cibfa_flash_sem_put(void __iomem *bar)
168662306a36Sopenharmony_ci{
168762306a36Sopenharmony_ci	writel(0, (bar + FLASH_SEM_LOCK_REG));
168862306a36Sopenharmony_ci}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_cistatic enum bfa_status
169162306a36Sopenharmony_cibfa_flash_raw_read(void __iomem *pci_bar, u32 offset, char *buf,
169262306a36Sopenharmony_ci		   u32 len)
169362306a36Sopenharmony_ci{
169462306a36Sopenharmony_ci	u32 n;
169562306a36Sopenharmony_ci	int status;
169662306a36Sopenharmony_ci	u32 off, l, s, residue, fifo_sz;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	residue = len;
169962306a36Sopenharmony_ci	off = 0;
170062306a36Sopenharmony_ci	fifo_sz = BFA_FLASH_FIFO_SIZE;
170162306a36Sopenharmony_ci	status = bfa_flash_sem_get(pci_bar);
170262306a36Sopenharmony_ci	if (status != BFA_STATUS_OK)
170362306a36Sopenharmony_ci		return status;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	while (residue) {
170662306a36Sopenharmony_ci		s = offset + off;
170762306a36Sopenharmony_ci		n = s / fifo_sz;
170862306a36Sopenharmony_ci		l = (n + 1) * fifo_sz - s;
170962306a36Sopenharmony_ci		if (l > residue)
171062306a36Sopenharmony_ci			l = residue;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci		status = bfa_flash_read_start(pci_bar, offset + off, l,
171362306a36Sopenharmony_ci								&buf[off]);
171462306a36Sopenharmony_ci		if (status < 0) {
171562306a36Sopenharmony_ci			bfa_flash_sem_put(pci_bar);
171662306a36Sopenharmony_ci			return BFA_STATUS_FAILED;
171762306a36Sopenharmony_ci		}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci		n = BFA_FLASH_BLOCKING_OP_MAX;
172062306a36Sopenharmony_ci		while (bfa_flash_read_check(pci_bar)) {
172162306a36Sopenharmony_ci			if (--n <= 0) {
172262306a36Sopenharmony_ci				bfa_flash_sem_put(pci_bar);
172362306a36Sopenharmony_ci				return BFA_STATUS_FAILED;
172462306a36Sopenharmony_ci			}
172562306a36Sopenharmony_ci		}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci		bfa_flash_read_end(pci_bar, l, &buf[off]);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci		residue -= l;
173062306a36Sopenharmony_ci		off += l;
173162306a36Sopenharmony_ci	}
173262306a36Sopenharmony_ci	bfa_flash_sem_put(pci_bar);
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	return BFA_STATUS_OK;
173562306a36Sopenharmony_ci}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci#define BFA_FLASH_PART_FWIMG_ADDR	0x100000 /* fw image address */
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_cistatic enum bfa_status
174062306a36Sopenharmony_cibfa_nw_ioc_flash_img_get_chnk(struct bfa_ioc *ioc, u32 off,
174162306a36Sopenharmony_ci			      u32 *fwimg)
174262306a36Sopenharmony_ci{
174362306a36Sopenharmony_ci	return bfa_flash_raw_read(ioc->pcidev.pci_bar_kva,
174462306a36Sopenharmony_ci			BFA_FLASH_PART_FWIMG_ADDR + (off * sizeof(u32)),
174562306a36Sopenharmony_ci			(char *)fwimg, BFI_FLASH_CHUNK_SZ);
174662306a36Sopenharmony_ci}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_cistatic enum bfi_ioc_img_ver_cmp
174962306a36Sopenharmony_cibfa_ioc_flash_fwver_cmp(struct bfa_ioc *ioc,
175062306a36Sopenharmony_ci			struct bfi_ioc_image_hdr *base_fwhdr)
175162306a36Sopenharmony_ci{
175262306a36Sopenharmony_ci	struct bfi_ioc_image_hdr *flash_fwhdr;
175362306a36Sopenharmony_ci	enum bfa_status status;
175462306a36Sopenharmony_ci	u32 fwimg[BFI_FLASH_CHUNK_SZ_WORDS];
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	status = bfa_nw_ioc_flash_img_get_chnk(ioc, 0, fwimg);
175762306a36Sopenharmony_ci	if (status != BFA_STATUS_OK)
175862306a36Sopenharmony_ci		return BFI_IOC_IMG_VER_INCOMP;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	flash_fwhdr = (struct bfi_ioc_image_hdr *)fwimg;
176162306a36Sopenharmony_ci	if (bfa_ioc_flash_fwver_valid(flash_fwhdr))
176262306a36Sopenharmony_ci		return bfa_ioc_fw_ver_patch_cmp(base_fwhdr, flash_fwhdr);
176362306a36Sopenharmony_ci	else
176462306a36Sopenharmony_ci		return BFI_IOC_IMG_VER_INCOMP;
176562306a36Sopenharmony_ci}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci/*
176862306a36Sopenharmony_ci * Returns TRUE if driver is willing to work with current smem f/w version.
176962306a36Sopenharmony_ci */
177062306a36Sopenharmony_cibool
177162306a36Sopenharmony_cibfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
177262306a36Sopenharmony_ci{
177362306a36Sopenharmony_ci	struct bfi_ioc_image_hdr *drv_fwhdr;
177462306a36Sopenharmony_ci	enum bfi_ioc_img_ver_cmp smem_flash_cmp, drv_smem_cmp;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	drv_fwhdr = (struct bfi_ioc_image_hdr *)
177762306a36Sopenharmony_ci		bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	/* If smem is incompatible or old, driver should not work with it. */
178062306a36Sopenharmony_ci	drv_smem_cmp = bfa_ioc_fw_ver_patch_cmp(drv_fwhdr, fwhdr);
178162306a36Sopenharmony_ci	if (drv_smem_cmp == BFI_IOC_IMG_VER_INCOMP ||
178262306a36Sopenharmony_ci	    drv_smem_cmp == BFI_IOC_IMG_VER_OLD) {
178362306a36Sopenharmony_ci		return false;
178462306a36Sopenharmony_ci	}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	/* IF Flash has a better F/W than smem do not work with smem.
178762306a36Sopenharmony_ci	 * If smem f/w == flash f/w, as smem f/w not old | incmp, work with it.
178862306a36Sopenharmony_ci	 * If Flash is old or incomp work with smem iff smem f/w == drv f/w.
178962306a36Sopenharmony_ci	 */
179062306a36Sopenharmony_ci	smem_flash_cmp = bfa_ioc_flash_fwver_cmp(ioc, fwhdr);
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	if (smem_flash_cmp == BFI_IOC_IMG_VER_BETTER)
179362306a36Sopenharmony_ci		return false;
179462306a36Sopenharmony_ci	else if (smem_flash_cmp == BFI_IOC_IMG_VER_SAME)
179562306a36Sopenharmony_ci		return true;
179662306a36Sopenharmony_ci	else
179762306a36Sopenharmony_ci		return (drv_smem_cmp == BFI_IOC_IMG_VER_SAME) ?
179862306a36Sopenharmony_ci			true : false;
179962306a36Sopenharmony_ci}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci/* Return true if current running version is valid. Firmware signature and
180262306a36Sopenharmony_ci * execution context (driver/bios) must match.
180362306a36Sopenharmony_ci */
180462306a36Sopenharmony_cistatic bool
180562306a36Sopenharmony_cibfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env)
180662306a36Sopenharmony_ci{
180762306a36Sopenharmony_ci	struct bfi_ioc_image_hdr fwhdr;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	bfa_nw_ioc_fwver_get(ioc, &fwhdr);
181062306a36Sopenharmony_ci	if (swab32(fwhdr.bootenv) != boot_env)
181162306a36Sopenharmony_ci		return false;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	return bfa_nw_ioc_fwver_cmp(ioc, &fwhdr);
181462306a36Sopenharmony_ci}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci/* Conditionally flush any pending message from firmware at start. */
181762306a36Sopenharmony_cistatic void
181862306a36Sopenharmony_cibfa_ioc_msgflush(struct bfa_ioc *ioc)
181962306a36Sopenharmony_ci{
182062306a36Sopenharmony_ci	u32	r32;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
182362306a36Sopenharmony_ci	if (r32)
182462306a36Sopenharmony_ci		writel(1, ioc->ioc_regs.lpu_mbox_cmd);
182562306a36Sopenharmony_ci}
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_cistatic void
182862306a36Sopenharmony_cibfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
182962306a36Sopenharmony_ci{
183062306a36Sopenharmony_ci	enum bfi_ioc_state ioc_fwstate;
183162306a36Sopenharmony_ci	bool fwvalid;
183262306a36Sopenharmony_ci	u32 boot_env;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	ioc_fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	if (force)
183762306a36Sopenharmony_ci		ioc_fwstate = BFI_IOC_UNINIT;
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	boot_env = BFI_FWBOOT_ENV_OS;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	/**
184262306a36Sopenharmony_ci	 * check if firmware is valid
184362306a36Sopenharmony_ci	 */
184462306a36Sopenharmony_ci	fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
184562306a36Sopenharmony_ci		false : bfa_ioc_fwver_valid(ioc, boot_env);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	if (!fwvalid) {
184862306a36Sopenharmony_ci		if (bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env) ==
184962306a36Sopenharmony_ci								BFA_STATUS_OK)
185062306a36Sopenharmony_ci			bfa_ioc_poll_fwinit(ioc);
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci		return;
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	/**
185662306a36Sopenharmony_ci	 * If hardware initialization is in progress (initialized by other IOC),
185762306a36Sopenharmony_ci	 * just wait for an initialization completion interrupt.
185862306a36Sopenharmony_ci	 */
185962306a36Sopenharmony_ci	if (ioc_fwstate == BFI_IOC_INITING) {
186062306a36Sopenharmony_ci		bfa_ioc_poll_fwinit(ioc);
186162306a36Sopenharmony_ci		return;
186262306a36Sopenharmony_ci	}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	/**
186562306a36Sopenharmony_ci	 * If IOC function is disabled and firmware version is same,
186662306a36Sopenharmony_ci	 * just re-enable IOC.
186762306a36Sopenharmony_ci	 */
186862306a36Sopenharmony_ci	if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {
186962306a36Sopenharmony_ci		/**
187062306a36Sopenharmony_ci		 * When using MSI-X any pending firmware ready event should
187162306a36Sopenharmony_ci		 * be flushed. Otherwise MSI-X interrupts are not delivered.
187262306a36Sopenharmony_ci		 */
187362306a36Sopenharmony_ci		bfa_ioc_msgflush(ioc);
187462306a36Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);
187562306a36Sopenharmony_ci		return;
187662306a36Sopenharmony_ci	}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	/**
187962306a36Sopenharmony_ci	 * Initialize the h/w for any other states.
188062306a36Sopenharmony_ci	 */
188162306a36Sopenharmony_ci	if (bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env) ==
188262306a36Sopenharmony_ci							BFA_STATUS_OK)
188362306a36Sopenharmony_ci		bfa_ioc_poll_fwinit(ioc);
188462306a36Sopenharmony_ci}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_civoid
188762306a36Sopenharmony_cibfa_nw_ioc_timeout(struct bfa_ioc *ioc)
188862306a36Sopenharmony_ci{
188962306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);
189062306a36Sopenharmony_ci}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_cistatic void
189362306a36Sopenharmony_cibfa_ioc_mbox_send(struct bfa_ioc *ioc, void *ioc_msg, int len)
189462306a36Sopenharmony_ci{
189562306a36Sopenharmony_ci	u32 *msgp = (u32 *) ioc_msg;
189662306a36Sopenharmony_ci	u32 i;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	BUG_ON(!(len <= BFI_IOC_MSGLEN_MAX));
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	/*
190162306a36Sopenharmony_ci	 * first write msg to mailbox registers
190262306a36Sopenharmony_ci	 */
190362306a36Sopenharmony_ci	for (i = 0; i < len / sizeof(u32); i++)
190462306a36Sopenharmony_ci		writel(cpu_to_le32(msgp[i]),
190562306a36Sopenharmony_ci			      ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
190862306a36Sopenharmony_ci		writel(0, ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	/*
191162306a36Sopenharmony_ci	 * write 1 to mailbox CMD to trigger LPU event
191262306a36Sopenharmony_ci	 */
191362306a36Sopenharmony_ci	writel(1, ioc->ioc_regs.hfn_mbox_cmd);
191462306a36Sopenharmony_ci	(void) readl(ioc->ioc_regs.hfn_mbox_cmd);
191562306a36Sopenharmony_ci}
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_cistatic void
191862306a36Sopenharmony_cibfa_ioc_send_enable(struct bfa_ioc *ioc)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	struct bfi_ioc_ctrl_req enable_req;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
192362306a36Sopenharmony_ci		    bfa_ioc_portid(ioc));
192462306a36Sopenharmony_ci	enable_req.clscode = htons(ioc->clscode);
192562306a36Sopenharmony_ci	enable_req.rsvd = htons(0);
192662306a36Sopenharmony_ci	/* overflow in 2106 */
192762306a36Sopenharmony_ci	enable_req.tv_sec = ntohl(ktime_get_real_seconds());
192862306a36Sopenharmony_ci	bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req));
192962306a36Sopenharmony_ci}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_cistatic void
193262306a36Sopenharmony_cibfa_ioc_send_disable(struct bfa_ioc *ioc)
193362306a36Sopenharmony_ci{
193462306a36Sopenharmony_ci	struct bfi_ioc_ctrl_req disable_req;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,
193762306a36Sopenharmony_ci		    bfa_ioc_portid(ioc));
193862306a36Sopenharmony_ci	disable_req.clscode = htons(ioc->clscode);
193962306a36Sopenharmony_ci	disable_req.rsvd = htons(0);
194062306a36Sopenharmony_ci	/* overflow in 2106 */
194162306a36Sopenharmony_ci	disable_req.tv_sec = ntohl(ktime_get_real_seconds());
194262306a36Sopenharmony_ci	bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req));
194362306a36Sopenharmony_ci}
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_cistatic void
194662306a36Sopenharmony_cibfa_ioc_send_getattr(struct bfa_ioc *ioc)
194762306a36Sopenharmony_ci{
194862306a36Sopenharmony_ci	struct bfi_ioc_getattr_req attr_req;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ,
195162306a36Sopenharmony_ci		    bfa_ioc_portid(ioc));
195262306a36Sopenharmony_ci	bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa);
195362306a36Sopenharmony_ci	bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req));
195462306a36Sopenharmony_ci}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_civoid
195762306a36Sopenharmony_cibfa_nw_ioc_hb_check(struct bfa_ioc *ioc)
195862306a36Sopenharmony_ci{
195962306a36Sopenharmony_ci	u32 hb_count;
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	hb_count = readl(ioc->ioc_regs.heartbeat);
196262306a36Sopenharmony_ci	if (ioc->hb_count == hb_count) {
196362306a36Sopenharmony_ci		bfa_ioc_recover(ioc);
196462306a36Sopenharmony_ci		return;
196562306a36Sopenharmony_ci	} else {
196662306a36Sopenharmony_ci		ioc->hb_count = hb_count;
196762306a36Sopenharmony_ci	}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	bfa_ioc_mbox_poll(ioc);
197062306a36Sopenharmony_ci	mod_timer(&ioc->hb_timer, jiffies +
197162306a36Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_HB_TOV));
197262306a36Sopenharmony_ci}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_cistatic void
197562306a36Sopenharmony_cibfa_ioc_hb_monitor(struct bfa_ioc *ioc)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	ioc->hb_count = readl(ioc->ioc_regs.heartbeat);
197862306a36Sopenharmony_ci	mod_timer(&ioc->hb_timer, jiffies +
197962306a36Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_HB_TOV));
198062306a36Sopenharmony_ci}
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_cistatic void
198362306a36Sopenharmony_cibfa_ioc_hb_stop(struct bfa_ioc *ioc)
198462306a36Sopenharmony_ci{
198562306a36Sopenharmony_ci	del_timer(&ioc->hb_timer);
198662306a36Sopenharmony_ci}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci/* Initiate a full firmware download. */
198962306a36Sopenharmony_cistatic enum bfa_status
199062306a36Sopenharmony_cibfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
199162306a36Sopenharmony_ci		    u32 boot_env)
199262306a36Sopenharmony_ci{
199362306a36Sopenharmony_ci	u32 *fwimg;
199462306a36Sopenharmony_ci	u32 pgnum;
199562306a36Sopenharmony_ci	u32 loff = 0;
199662306a36Sopenharmony_ci	u32 chunkno = 0;
199762306a36Sopenharmony_ci	u32 i;
199862306a36Sopenharmony_ci	u32 asicmode;
199962306a36Sopenharmony_ci	u32 fwimg_size;
200062306a36Sopenharmony_ci	u32 fwimg_buf[BFI_FLASH_CHUNK_SZ_WORDS];
200162306a36Sopenharmony_ci	enum bfa_status status;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	if (boot_env == BFI_FWBOOT_ENV_OS &&
200462306a36Sopenharmony_ci	    boot_type == BFI_FWBOOT_TYPE_FLASH) {
200562306a36Sopenharmony_ci		fwimg_size = BFI_FLASH_IMAGE_SZ/sizeof(u32);
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		status = bfa_nw_ioc_flash_img_get_chnk(ioc,
200862306a36Sopenharmony_ci			BFA_IOC_FLASH_CHUNK_ADDR(chunkno), fwimg_buf);
200962306a36Sopenharmony_ci		if (status != BFA_STATUS_OK)
201062306a36Sopenharmony_ci			return status;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci		fwimg = fwimg_buf;
201362306a36Sopenharmony_ci	} else {
201462306a36Sopenharmony_ci		fwimg_size = bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc));
201562306a36Sopenharmony_ci		fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc),
201662306a36Sopenharmony_ci					BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
201762306a36Sopenharmony_ci	}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	pgnum = bfa_ioc_smem_pgnum(ioc, loff);
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	for (i = 0; i < fwimg_size; i++) {
202462306a36Sopenharmony_ci		if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {
202562306a36Sopenharmony_ci			chunkno = BFA_IOC_FLASH_CHUNK_NO(i);
202662306a36Sopenharmony_ci			if (boot_env == BFI_FWBOOT_ENV_OS &&
202762306a36Sopenharmony_ci			    boot_type == BFI_FWBOOT_TYPE_FLASH) {
202862306a36Sopenharmony_ci				status = bfa_nw_ioc_flash_img_get_chnk(ioc,
202962306a36Sopenharmony_ci					BFA_IOC_FLASH_CHUNK_ADDR(chunkno),
203062306a36Sopenharmony_ci					fwimg_buf);
203162306a36Sopenharmony_ci				if (status != BFA_STATUS_OK)
203262306a36Sopenharmony_ci					return status;
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci				fwimg = fwimg_buf;
203562306a36Sopenharmony_ci			} else {
203662306a36Sopenharmony_ci				fwimg = bfa_cb_image_get_chunk(
203762306a36Sopenharmony_ci					bfa_ioc_asic_gen(ioc),
203862306a36Sopenharmony_ci					BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
203962306a36Sopenharmony_ci			}
204062306a36Sopenharmony_ci		}
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci		/**
204362306a36Sopenharmony_ci		 * write smem
204462306a36Sopenharmony_ci		 */
204562306a36Sopenharmony_ci		writel(swab32(fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)]),
204662306a36Sopenharmony_ci		       ioc->ioc_regs.smem_page_start + loff);
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci		loff += sizeof(u32);
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci		/**
205162306a36Sopenharmony_ci		 * handle page offset wrap around
205262306a36Sopenharmony_ci		 */
205362306a36Sopenharmony_ci		loff = PSS_SMEM_PGOFF(loff);
205462306a36Sopenharmony_ci		if (loff == 0) {
205562306a36Sopenharmony_ci			pgnum++;
205662306a36Sopenharmony_ci			writel(pgnum,
205762306a36Sopenharmony_ci				      ioc->ioc_regs.host_page_num_fn);
205862306a36Sopenharmony_ci		}
205962306a36Sopenharmony_ci	}
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	writel(bfa_ioc_smem_pgnum(ioc, 0),
206262306a36Sopenharmony_ci		      ioc->ioc_regs.host_page_num_fn);
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	/*
206562306a36Sopenharmony_ci	 * Set boot type, env and device mode at the end.
206662306a36Sopenharmony_ci	*/
206762306a36Sopenharmony_ci	if (boot_env == BFI_FWBOOT_ENV_OS &&
206862306a36Sopenharmony_ci	    boot_type == BFI_FWBOOT_TYPE_FLASH) {
206962306a36Sopenharmony_ci		boot_type = BFI_FWBOOT_TYPE_NORMAL;
207062306a36Sopenharmony_ci	}
207162306a36Sopenharmony_ci	asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode,
207262306a36Sopenharmony_ci					ioc->port0_mode, ioc->port1_mode);
207362306a36Sopenharmony_ci	writel(asicmode, ((ioc->ioc_regs.smem_page_start)
207462306a36Sopenharmony_ci			+ BFI_FWBOOT_DEVMODE_OFF));
207562306a36Sopenharmony_ci	writel(boot_type, ((ioc->ioc_regs.smem_page_start)
207662306a36Sopenharmony_ci			+ (BFI_FWBOOT_TYPE_OFF)));
207762306a36Sopenharmony_ci	writel(boot_env, ((ioc->ioc_regs.smem_page_start)
207862306a36Sopenharmony_ci			+ (BFI_FWBOOT_ENV_OFF)));
207962306a36Sopenharmony_ci	return BFA_STATUS_OK;
208062306a36Sopenharmony_ci}
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_cistatic void
208362306a36Sopenharmony_cibfa_ioc_reset(struct bfa_ioc *ioc, bool force)
208462306a36Sopenharmony_ci{
208562306a36Sopenharmony_ci	bfa_ioc_hwinit(ioc, force);
208662306a36Sopenharmony_ci}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci/* BFA ioc enable reply by firmware */
208962306a36Sopenharmony_cistatic void
209062306a36Sopenharmony_cibfa_ioc_enable_reply(struct bfa_ioc *ioc, enum bfa_mode port_mode,
209162306a36Sopenharmony_ci			u8 cap_bm)
209262306a36Sopenharmony_ci{
209362306a36Sopenharmony_ci	struct bfa_iocpf *iocpf = &ioc->iocpf;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	ioc->port_mode = ioc->port_mode_cfg = port_mode;
209662306a36Sopenharmony_ci	ioc->ad_cap_bm = cap_bm;
209762306a36Sopenharmony_ci	bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE);
209862306a36Sopenharmony_ci}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci/* Update BFA configuration from firmware configuration. */
210162306a36Sopenharmony_cistatic void
210262306a36Sopenharmony_cibfa_ioc_getattr_reply(struct bfa_ioc *ioc)
210362306a36Sopenharmony_ci{
210462306a36Sopenharmony_ci	struct bfi_ioc_attr *attr = ioc->attr;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	attr->adapter_prop  = ntohl(attr->adapter_prop);
210762306a36Sopenharmony_ci	attr->card_type     = ntohl(attr->card_type);
210862306a36Sopenharmony_ci	attr->maxfrsize	    = ntohs(attr->maxfrsize);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
211162306a36Sopenharmony_ci}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci/* Attach time initialization of mbox logic. */
211462306a36Sopenharmony_cistatic void
211562306a36Sopenharmony_cibfa_ioc_mbox_attach(struct bfa_ioc *ioc)
211662306a36Sopenharmony_ci{
211762306a36Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
211862306a36Sopenharmony_ci	int	mc;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	INIT_LIST_HEAD(&mod->cmd_q);
212162306a36Sopenharmony_ci	for (mc = 0; mc < BFI_MC_MAX; mc++) {
212262306a36Sopenharmony_ci		mod->mbhdlr[mc].cbfn = NULL;
212362306a36Sopenharmony_ci		mod->mbhdlr[mc].cbarg = ioc->bfa;
212462306a36Sopenharmony_ci	}
212562306a36Sopenharmony_ci}
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci/* Mbox poll timer -- restarts any pending mailbox requests. */
212862306a36Sopenharmony_cistatic void
212962306a36Sopenharmony_cibfa_ioc_mbox_poll(struct bfa_ioc *ioc)
213062306a36Sopenharmony_ci{
213162306a36Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
213262306a36Sopenharmony_ci	struct bfa_mbox_cmd *cmd;
213362306a36Sopenharmony_ci	bfa_mbox_cmd_cbfn_t cbfn;
213462306a36Sopenharmony_ci	void *cbarg;
213562306a36Sopenharmony_ci	u32 stat;
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	/**
213862306a36Sopenharmony_ci	 * If no command pending, do nothing
213962306a36Sopenharmony_ci	 */
214062306a36Sopenharmony_ci	if (list_empty(&mod->cmd_q))
214162306a36Sopenharmony_ci		return;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	/**
214462306a36Sopenharmony_ci	 * If previous command is not yet fetched by firmware, do nothing
214562306a36Sopenharmony_ci	 */
214662306a36Sopenharmony_ci	stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
214762306a36Sopenharmony_ci	if (stat)
214862306a36Sopenharmony_ci		return;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	/**
215162306a36Sopenharmony_ci	 * Enqueue command to firmware.
215262306a36Sopenharmony_ci	 */
215362306a36Sopenharmony_ci	cmd = list_first_entry(&mod->cmd_q, struct bfa_mbox_cmd, qe);
215462306a36Sopenharmony_ci	list_del(&cmd->qe);
215562306a36Sopenharmony_ci	bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	/**
215862306a36Sopenharmony_ci	 * Give a callback to the client, indicating that the command is sent
215962306a36Sopenharmony_ci	 */
216062306a36Sopenharmony_ci	if (cmd->cbfn) {
216162306a36Sopenharmony_ci		cbfn = cmd->cbfn;
216262306a36Sopenharmony_ci		cbarg = cmd->cbarg;
216362306a36Sopenharmony_ci		cmd->cbfn = NULL;
216462306a36Sopenharmony_ci		cbfn(cbarg);
216562306a36Sopenharmony_ci	}
216662306a36Sopenharmony_ci}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci/* Cleanup any pending requests. */
216962306a36Sopenharmony_cistatic void
217062306a36Sopenharmony_cibfa_ioc_mbox_flush(struct bfa_ioc *ioc)
217162306a36Sopenharmony_ci{
217262306a36Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
217362306a36Sopenharmony_ci	struct bfa_mbox_cmd *cmd;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	while (!list_empty(&mod->cmd_q)) {
217662306a36Sopenharmony_ci		cmd = list_first_entry(&mod->cmd_q, struct bfa_mbox_cmd, qe);
217762306a36Sopenharmony_ci		list_del(&cmd->qe);
217862306a36Sopenharmony_ci	}
217962306a36Sopenharmony_ci}
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci/**
218262306a36Sopenharmony_ci * bfa_nw_ioc_smem_read - Read data from SMEM to host through PCI memmap
218362306a36Sopenharmony_ci *
218462306a36Sopenharmony_ci * @ioc:     memory for IOC
218562306a36Sopenharmony_ci * @tbuf:    app memory to store data from smem
218662306a36Sopenharmony_ci * @soff:    smem offset
218762306a36Sopenharmony_ci * @sz:      size of smem in bytes
218862306a36Sopenharmony_ci */
218962306a36Sopenharmony_cistatic int
219062306a36Sopenharmony_cibfa_nw_ioc_smem_read(struct bfa_ioc *ioc, void *tbuf, u32 soff, u32 sz)
219162306a36Sopenharmony_ci{
219262306a36Sopenharmony_ci	u32 pgnum, loff, r32;
219362306a36Sopenharmony_ci	int i, len;
219462306a36Sopenharmony_ci	u32 *buf = tbuf;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff);
219762306a36Sopenharmony_ci	loff = PSS_SMEM_PGOFF(soff);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	/*
220062306a36Sopenharmony_ci	 *  Hold semaphore to serialize pll init and fwtrc.
220162306a36Sopenharmony_ci	*/
220262306a36Sopenharmony_ci	if (!bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg))
220362306a36Sopenharmony_ci		return 1;
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	len = sz/sizeof(u32);
220862306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
220962306a36Sopenharmony_ci		r32 = swab32(readl(loff + ioc->ioc_regs.smem_page_start));
221062306a36Sopenharmony_ci		buf[i] = be32_to_cpu(r32);
221162306a36Sopenharmony_ci		loff += sizeof(u32);
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci		/**
221462306a36Sopenharmony_ci		 * handle page offset wrap around
221562306a36Sopenharmony_ci		 */
221662306a36Sopenharmony_ci		loff = PSS_SMEM_PGOFF(loff);
221762306a36Sopenharmony_ci		if (loff == 0) {
221862306a36Sopenharmony_ci			pgnum++;
221962306a36Sopenharmony_ci			writel(pgnum, ioc->ioc_regs.host_page_num_fn);
222062306a36Sopenharmony_ci		}
222162306a36Sopenharmony_ci	}
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),
222462306a36Sopenharmony_ci	       ioc->ioc_regs.host_page_num_fn);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	/*
222762306a36Sopenharmony_ci	 * release semaphore
222862306a36Sopenharmony_ci	 */
222962306a36Sopenharmony_ci	readl(ioc->ioc_regs.ioc_init_sem_reg);
223062306a36Sopenharmony_ci	writel(1, ioc->ioc_regs.ioc_init_sem_reg);
223162306a36Sopenharmony_ci	return 0;
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci/* Retrieve saved firmware trace from a prior IOC failure. */
223562306a36Sopenharmony_ciint
223662306a36Sopenharmony_cibfa_nw_ioc_debug_fwtrc(struct bfa_ioc *ioc, void *trcdata, int *trclen)
223762306a36Sopenharmony_ci{
223862306a36Sopenharmony_ci	u32 loff = BFI_IOC_TRC_OFF + BNA_DBG_FWTRC_LEN * ioc->port_id;
223962306a36Sopenharmony_ci	int tlen, status = 0;
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	tlen = *trclen;
224262306a36Sopenharmony_ci	if (tlen > BNA_DBG_FWTRC_LEN)
224362306a36Sopenharmony_ci		tlen = BNA_DBG_FWTRC_LEN;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	status = bfa_nw_ioc_smem_read(ioc, trcdata, loff, tlen);
224662306a36Sopenharmony_ci	*trclen = tlen;
224762306a36Sopenharmony_ci	return status;
224862306a36Sopenharmony_ci}
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci/* Save firmware trace if configured. */
225162306a36Sopenharmony_cistatic void
225262306a36Sopenharmony_cibfa_nw_ioc_debug_save_ftrc(struct bfa_ioc *ioc)
225362306a36Sopenharmony_ci{
225462306a36Sopenharmony_ci	int tlen;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	if (ioc->dbg_fwsave_once) {
225762306a36Sopenharmony_ci		ioc->dbg_fwsave_once = false;
225862306a36Sopenharmony_ci		if (ioc->dbg_fwsave_len) {
225962306a36Sopenharmony_ci			tlen = ioc->dbg_fwsave_len;
226062306a36Sopenharmony_ci			bfa_nw_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
226162306a36Sopenharmony_ci		}
226262306a36Sopenharmony_ci	}
226362306a36Sopenharmony_ci}
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci/* Retrieve saved firmware trace from a prior IOC failure. */
226662306a36Sopenharmony_ciint
226762306a36Sopenharmony_cibfa_nw_ioc_debug_fwsave(struct bfa_ioc *ioc, void *trcdata, int *trclen)
226862306a36Sopenharmony_ci{
226962306a36Sopenharmony_ci	int tlen;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	if (ioc->dbg_fwsave_len == 0)
227262306a36Sopenharmony_ci		return BFA_STATUS_ENOFSAVE;
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	tlen = *trclen;
227562306a36Sopenharmony_ci	if (tlen > ioc->dbg_fwsave_len)
227662306a36Sopenharmony_ci		tlen = ioc->dbg_fwsave_len;
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	memcpy(trcdata, ioc->dbg_fwsave, tlen);
227962306a36Sopenharmony_ci	*trclen = tlen;
228062306a36Sopenharmony_ci	return BFA_STATUS_OK;
228162306a36Sopenharmony_ci}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_cistatic void
228462306a36Sopenharmony_cibfa_ioc_fail_notify(struct bfa_ioc *ioc)
228562306a36Sopenharmony_ci{
228662306a36Sopenharmony_ci	/**
228762306a36Sopenharmony_ci	 * Notify driver and common modules registered for notification.
228862306a36Sopenharmony_ci	 */
228962306a36Sopenharmony_ci	ioc->cbfn->hbfail_cbfn(ioc->bfa);
229062306a36Sopenharmony_ci	bfa_ioc_event_notify(ioc, BFA_IOC_E_FAILED);
229162306a36Sopenharmony_ci	bfa_nw_ioc_debug_save_ftrc(ioc);
229262306a36Sopenharmony_ci}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci/* IOCPF to IOC interface */
229562306a36Sopenharmony_cistatic void
229662306a36Sopenharmony_cibfa_ioc_pf_enabled(struct bfa_ioc *ioc)
229762306a36Sopenharmony_ci{
229862306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_ENABLED);
229962306a36Sopenharmony_ci}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_cistatic void
230262306a36Sopenharmony_cibfa_ioc_pf_disabled(struct bfa_ioc *ioc)
230362306a36Sopenharmony_ci{
230462306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_DISABLED);
230562306a36Sopenharmony_ci}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_cistatic void
230862306a36Sopenharmony_cibfa_ioc_pf_failed(struct bfa_ioc *ioc)
230962306a36Sopenharmony_ci{
231062306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
231162306a36Sopenharmony_ci}
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_cistatic void
231462306a36Sopenharmony_cibfa_ioc_pf_hwfailed(struct bfa_ioc *ioc)
231562306a36Sopenharmony_ci{
231662306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_HWFAILED);
231762306a36Sopenharmony_ci}
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_cistatic void
232062306a36Sopenharmony_cibfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc)
232162306a36Sopenharmony_ci{
232262306a36Sopenharmony_ci	/**
232362306a36Sopenharmony_ci	 * Provide enable completion callback and AEN notification.
232462306a36Sopenharmony_ci	 */
232562306a36Sopenharmony_ci	ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
232662306a36Sopenharmony_ci}
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci/* IOC public */
232962306a36Sopenharmony_cistatic enum bfa_status
233062306a36Sopenharmony_cibfa_ioc_pll_init(struct bfa_ioc *ioc)
233162306a36Sopenharmony_ci{
233262306a36Sopenharmony_ci	/*
233362306a36Sopenharmony_ci	 *  Hold semaphore so that nobody can access the chip during init.
233462306a36Sopenharmony_ci	 */
233562306a36Sopenharmony_ci	bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg);
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	bfa_ioc_pll_init_asic(ioc);
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	ioc->pllinit = true;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	/* Initialize LMEM */
234262306a36Sopenharmony_ci	bfa_ioc_lmem_init(ioc);
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	/*
234562306a36Sopenharmony_ci	 *  release semaphore.
234662306a36Sopenharmony_ci	 */
234762306a36Sopenharmony_ci	bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	return BFA_STATUS_OK;
235062306a36Sopenharmony_ci}
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci/* Interface used by diag module to do firmware boot with memory test
235362306a36Sopenharmony_ci * as the entry vector.
235462306a36Sopenharmony_ci */
235562306a36Sopenharmony_cistatic enum bfa_status
235662306a36Sopenharmony_cibfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type,
235762306a36Sopenharmony_ci		u32 boot_env)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	struct bfi_ioc_image_hdr *drv_fwhdr;
236062306a36Sopenharmony_ci	enum bfa_status status;
236162306a36Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_boots);
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
236462306a36Sopenharmony_ci		return BFA_STATUS_FAILED;
236562306a36Sopenharmony_ci	if (boot_env == BFI_FWBOOT_ENV_OS &&
236662306a36Sopenharmony_ci	    boot_type == BFI_FWBOOT_TYPE_NORMAL) {
236762306a36Sopenharmony_ci		drv_fwhdr = (struct bfi_ioc_image_hdr *)
236862306a36Sopenharmony_ci			bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);
236962306a36Sopenharmony_ci		/* Work with Flash iff flash f/w is better than driver f/w.
237062306a36Sopenharmony_ci		 * Otherwise push drivers firmware.
237162306a36Sopenharmony_ci		 */
237262306a36Sopenharmony_ci		if (bfa_ioc_flash_fwver_cmp(ioc, drv_fwhdr) ==
237362306a36Sopenharmony_ci			BFI_IOC_IMG_VER_BETTER)
237462306a36Sopenharmony_ci			boot_type = BFI_FWBOOT_TYPE_FLASH;
237562306a36Sopenharmony_ci	}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	/**
237862306a36Sopenharmony_ci	 * Initialize IOC state of all functions on a chip reset.
237962306a36Sopenharmony_ci	 */
238062306a36Sopenharmony_ci	if (boot_type == BFI_FWBOOT_TYPE_MEMTEST) {
238162306a36Sopenharmony_ci		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_MEMTEST);
238262306a36Sopenharmony_ci		bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_MEMTEST);
238362306a36Sopenharmony_ci	} else {
238462306a36Sopenharmony_ci		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_INITING);
238562306a36Sopenharmony_ci		bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_INITING);
238662306a36Sopenharmony_ci	}
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	bfa_ioc_msgflush(ioc);
238962306a36Sopenharmony_ci	status = bfa_ioc_download_fw(ioc, boot_type, boot_env);
239062306a36Sopenharmony_ci	if (status == BFA_STATUS_OK)
239162306a36Sopenharmony_ci		bfa_ioc_lpu_start(ioc);
239262306a36Sopenharmony_ci	else
239362306a36Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	return status;
239662306a36Sopenharmony_ci}
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci/* Enable/disable IOC failure auto recovery. */
239962306a36Sopenharmony_civoid
240062306a36Sopenharmony_cibfa_nw_ioc_auto_recover(bool auto_recover)
240162306a36Sopenharmony_ci{
240262306a36Sopenharmony_ci	bfa_nw_auto_recover = auto_recover;
240362306a36Sopenharmony_ci}
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_cistatic bool
240662306a36Sopenharmony_cibfa_ioc_msgget(struct bfa_ioc *ioc, void *mbmsg)
240762306a36Sopenharmony_ci{
240862306a36Sopenharmony_ci	u32	*msgp = mbmsg;
240962306a36Sopenharmony_ci	u32	r32;
241062306a36Sopenharmony_ci	int		i;
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
241362306a36Sopenharmony_ci	if ((r32 & 1) == 0)
241462306a36Sopenharmony_ci		return false;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	/**
241762306a36Sopenharmony_ci	 * read the MBOX msg
241862306a36Sopenharmony_ci	 */
241962306a36Sopenharmony_ci	for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
242062306a36Sopenharmony_ci	     i++) {
242162306a36Sopenharmony_ci		r32 = readl(ioc->ioc_regs.lpu_mbox +
242262306a36Sopenharmony_ci				   i * sizeof(u32));
242362306a36Sopenharmony_ci		msgp[i] = htonl(r32);
242462306a36Sopenharmony_ci	}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	/**
242762306a36Sopenharmony_ci	 * turn off mailbox interrupt by clearing mailbox status
242862306a36Sopenharmony_ci	 */
242962306a36Sopenharmony_ci	writel(1, ioc->ioc_regs.lpu_mbox_cmd);
243062306a36Sopenharmony_ci	readl(ioc->ioc_regs.lpu_mbox_cmd);
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	return true;
243362306a36Sopenharmony_ci}
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_cistatic void
243662306a36Sopenharmony_cibfa_ioc_isr(struct bfa_ioc *ioc, struct bfi_mbmsg *m)
243762306a36Sopenharmony_ci{
243862306a36Sopenharmony_ci	union bfi_ioc_i2h_msg_u	*msg;
243962306a36Sopenharmony_ci	struct bfa_iocpf *iocpf = &ioc->iocpf;
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	msg = (union bfi_ioc_i2h_msg_u *) m;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_isrs);
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci	switch (msg->mh.msg_id) {
244662306a36Sopenharmony_ci	case BFI_IOC_I2H_HBEAT:
244762306a36Sopenharmony_ci		break;
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	case BFI_IOC_I2H_ENABLE_REPLY:
245062306a36Sopenharmony_ci		bfa_ioc_enable_reply(ioc,
245162306a36Sopenharmony_ci			(enum bfa_mode)msg->fw_event.port_mode,
245262306a36Sopenharmony_ci			msg->fw_event.cap_bm);
245362306a36Sopenharmony_ci		break;
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	case BFI_IOC_I2H_DISABLE_REPLY:
245662306a36Sopenharmony_ci		bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_DISABLE);
245762306a36Sopenharmony_ci		break;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	case BFI_IOC_I2H_GETATTR_REPLY:
246062306a36Sopenharmony_ci		bfa_ioc_getattr_reply(ioc);
246162306a36Sopenharmony_ci		break;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	default:
246462306a36Sopenharmony_ci		BUG_ON(1);
246562306a36Sopenharmony_ci	}
246662306a36Sopenharmony_ci}
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci/**
246962306a36Sopenharmony_ci * bfa_nw_ioc_attach - IOC attach time initialization and setup.
247062306a36Sopenharmony_ci *
247162306a36Sopenharmony_ci * @ioc:	memory for IOC
247262306a36Sopenharmony_ci * @bfa:	driver instance structure
247362306a36Sopenharmony_ci * @cbfn:	callback function
247462306a36Sopenharmony_ci */
247562306a36Sopenharmony_civoid
247662306a36Sopenharmony_cibfa_nw_ioc_attach(struct bfa_ioc *ioc, void *bfa, struct bfa_ioc_cbfn *cbfn)
247762306a36Sopenharmony_ci{
247862306a36Sopenharmony_ci	ioc->bfa	= bfa;
247962306a36Sopenharmony_ci	ioc->cbfn	= cbfn;
248062306a36Sopenharmony_ci	ioc->fcmode	= false;
248162306a36Sopenharmony_ci	ioc->pllinit	= false;
248262306a36Sopenharmony_ci	ioc->dbg_fwsave_once = true;
248362306a36Sopenharmony_ci	ioc->iocpf.ioc  = ioc;
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	bfa_ioc_mbox_attach(ioc);
248662306a36Sopenharmony_ci	INIT_LIST_HEAD(&ioc->notify_q);
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
248962306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_RESET);
249062306a36Sopenharmony_ci}
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci/* Driver detach time IOC cleanup. */
249362306a36Sopenharmony_civoid
249462306a36Sopenharmony_cibfa_nw_ioc_detach(struct bfa_ioc *ioc)
249562306a36Sopenharmony_ci{
249662306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_DETACH);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	/* Done with detach, empty the notify_q. */
249962306a36Sopenharmony_ci	INIT_LIST_HEAD(&ioc->notify_q);
250062306a36Sopenharmony_ci}
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci/**
250362306a36Sopenharmony_ci * bfa_nw_ioc_pci_init - Setup IOC PCI properties.
250462306a36Sopenharmony_ci *
250562306a36Sopenharmony_ci * @ioc:	memory for IOC
250662306a36Sopenharmony_ci * @pcidev:	PCI device information for this IOC
250762306a36Sopenharmony_ci * @clscode:	class code
250862306a36Sopenharmony_ci */
250962306a36Sopenharmony_civoid
251062306a36Sopenharmony_cibfa_nw_ioc_pci_init(struct bfa_ioc *ioc, struct bfa_pcidev *pcidev,
251162306a36Sopenharmony_ci		 enum bfi_pcifn_class clscode)
251262306a36Sopenharmony_ci{
251362306a36Sopenharmony_ci	ioc->clscode	= clscode;
251462306a36Sopenharmony_ci	ioc->pcidev	= *pcidev;
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	/**
251762306a36Sopenharmony_ci	 * Initialize IOC and device personality
251862306a36Sopenharmony_ci	 */
251962306a36Sopenharmony_ci	ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_FC;
252062306a36Sopenharmony_ci	ioc->asic_mode  = BFI_ASIC_MODE_FC;
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	switch (pcidev->device_id) {
252362306a36Sopenharmony_ci	case PCI_DEVICE_ID_BROCADE_CT:
252462306a36Sopenharmony_ci		ioc->asic_gen = BFI_ASIC_GEN_CT;
252562306a36Sopenharmony_ci		ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH;
252662306a36Sopenharmony_ci		ioc->asic_mode  = BFI_ASIC_MODE_ETH;
252762306a36Sopenharmony_ci		ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_CNA;
252862306a36Sopenharmony_ci		ioc->ad_cap_bm = BFA_CM_CNA;
252962306a36Sopenharmony_ci		break;
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	case BFA_PCI_DEVICE_ID_CT2:
253262306a36Sopenharmony_ci		ioc->asic_gen = BFI_ASIC_GEN_CT2;
253362306a36Sopenharmony_ci		if (clscode == BFI_PCIFN_CLASS_FC &&
253462306a36Sopenharmony_ci			pcidev->ssid == BFA_PCI_CT2_SSID_FC) {
253562306a36Sopenharmony_ci			ioc->asic_mode  = BFI_ASIC_MODE_FC16;
253662306a36Sopenharmony_ci			ioc->fcmode = true;
253762306a36Sopenharmony_ci			ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA;
253862306a36Sopenharmony_ci			ioc->ad_cap_bm = BFA_CM_HBA;
253962306a36Sopenharmony_ci		} else {
254062306a36Sopenharmony_ci			ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH;
254162306a36Sopenharmony_ci			ioc->asic_mode  = BFI_ASIC_MODE_ETH;
254262306a36Sopenharmony_ci			if (pcidev->ssid == BFA_PCI_CT2_SSID_FCoE) {
254362306a36Sopenharmony_ci				ioc->port_mode =
254462306a36Sopenharmony_ci				ioc->port_mode_cfg = BFA_MODE_CNA;
254562306a36Sopenharmony_ci				ioc->ad_cap_bm = BFA_CM_CNA;
254662306a36Sopenharmony_ci			} else {
254762306a36Sopenharmony_ci				ioc->port_mode =
254862306a36Sopenharmony_ci				ioc->port_mode_cfg = BFA_MODE_NIC;
254962306a36Sopenharmony_ci				ioc->ad_cap_bm = BFA_CM_NIC;
255062306a36Sopenharmony_ci			}
255162306a36Sopenharmony_ci		}
255262306a36Sopenharmony_ci		break;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	default:
255562306a36Sopenharmony_ci		BUG_ON(1);
255662306a36Sopenharmony_ci	}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	/**
255962306a36Sopenharmony_ci	 * Set asic specific interfaces.
256062306a36Sopenharmony_ci	 */
256162306a36Sopenharmony_ci	if (ioc->asic_gen == BFI_ASIC_GEN_CT)
256262306a36Sopenharmony_ci		bfa_nw_ioc_set_ct_hwif(ioc);
256362306a36Sopenharmony_ci	else {
256462306a36Sopenharmony_ci		WARN_ON(ioc->asic_gen != BFI_ASIC_GEN_CT2);
256562306a36Sopenharmony_ci		bfa_nw_ioc_set_ct2_hwif(ioc);
256662306a36Sopenharmony_ci		bfa_nw_ioc_ct2_poweron(ioc);
256762306a36Sopenharmony_ci	}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	bfa_ioc_map_port(ioc);
257062306a36Sopenharmony_ci	bfa_ioc_reg_init(ioc);
257162306a36Sopenharmony_ci}
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci/**
257462306a36Sopenharmony_ci * bfa_nw_ioc_mem_claim - Initialize IOC dma memory
257562306a36Sopenharmony_ci *
257662306a36Sopenharmony_ci * @ioc:	memory for IOC
257762306a36Sopenharmony_ci * @dm_kva:	kernel virtual address of IOC dma memory
257862306a36Sopenharmony_ci * @dm_pa:	physical address of IOC dma memory
257962306a36Sopenharmony_ci */
258062306a36Sopenharmony_civoid
258162306a36Sopenharmony_cibfa_nw_ioc_mem_claim(struct bfa_ioc *ioc,  u8 *dm_kva, u64 dm_pa)
258262306a36Sopenharmony_ci{
258362306a36Sopenharmony_ci	/**
258462306a36Sopenharmony_ci	 * dma memory for firmware attribute
258562306a36Sopenharmony_ci	 */
258662306a36Sopenharmony_ci	ioc->attr_dma.kva = dm_kva;
258762306a36Sopenharmony_ci	ioc->attr_dma.pa = dm_pa;
258862306a36Sopenharmony_ci	ioc->attr = (struct bfi_ioc_attr *) dm_kva;
258962306a36Sopenharmony_ci}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci/* Return size of dma memory required. */
259262306a36Sopenharmony_ciu32
259362306a36Sopenharmony_cibfa_nw_ioc_meminfo(void)
259462306a36Sopenharmony_ci{
259562306a36Sopenharmony_ci	return roundup(sizeof(struct bfi_ioc_attr), BFA_DMA_ALIGN_SZ);
259662306a36Sopenharmony_ci}
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_civoid
259962306a36Sopenharmony_cibfa_nw_ioc_enable(struct bfa_ioc *ioc)
260062306a36Sopenharmony_ci{
260162306a36Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_enables);
260262306a36Sopenharmony_ci	ioc->dbg_fwsave_once = true;
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_ENABLE);
260562306a36Sopenharmony_ci}
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_civoid
260862306a36Sopenharmony_cibfa_nw_ioc_disable(struct bfa_ioc *ioc)
260962306a36Sopenharmony_ci{
261062306a36Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_disables);
261162306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_DISABLE);
261262306a36Sopenharmony_ci}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci/* Initialize memory for saving firmware trace. */
261562306a36Sopenharmony_civoid
261662306a36Sopenharmony_cibfa_nw_ioc_debug_memclaim(struct bfa_ioc *ioc, void *dbg_fwsave)
261762306a36Sopenharmony_ci{
261862306a36Sopenharmony_ci	ioc->dbg_fwsave = dbg_fwsave;
261962306a36Sopenharmony_ci	ioc->dbg_fwsave_len = ioc->iocpf.auto_recover ? BNA_DBG_FWTRC_LEN : 0;
262062306a36Sopenharmony_ci}
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_cistatic u32
262362306a36Sopenharmony_cibfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr)
262462306a36Sopenharmony_ci{
262562306a36Sopenharmony_ci	return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
262662306a36Sopenharmony_ci}
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci/* Register mailbox message handler function, to be called by common modules */
262962306a36Sopenharmony_civoid
263062306a36Sopenharmony_cibfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
263162306a36Sopenharmony_ci		    bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg)
263262306a36Sopenharmony_ci{
263362306a36Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci	mod->mbhdlr[mc].cbfn	= cbfn;
263662306a36Sopenharmony_ci	mod->mbhdlr[mc].cbarg = cbarg;
263762306a36Sopenharmony_ci}
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci/**
264062306a36Sopenharmony_ci * bfa_nw_ioc_mbox_queue - Queue a mailbox command request to firmware.
264162306a36Sopenharmony_ci *
264262306a36Sopenharmony_ci * @ioc:	IOC instance
264362306a36Sopenharmony_ci * @cmd:	Mailbox command
264462306a36Sopenharmony_ci * @cbfn:	callback function
264562306a36Sopenharmony_ci * @cbarg:	arguments to callback
264662306a36Sopenharmony_ci *
264762306a36Sopenharmony_ci * Waits if mailbox is busy. Responsibility of caller to serialize
264862306a36Sopenharmony_ci */
264962306a36Sopenharmony_cibool
265062306a36Sopenharmony_cibfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd,
265162306a36Sopenharmony_ci			bfa_mbox_cmd_cbfn_t cbfn, void *cbarg)
265262306a36Sopenharmony_ci{
265362306a36Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
265462306a36Sopenharmony_ci	u32			stat;
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	cmd->cbfn = cbfn;
265762306a36Sopenharmony_ci	cmd->cbarg = cbarg;
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	/**
266062306a36Sopenharmony_ci	 * If a previous command is pending, queue new command
266162306a36Sopenharmony_ci	 */
266262306a36Sopenharmony_ci	if (!list_empty(&mod->cmd_q)) {
266362306a36Sopenharmony_ci		list_add_tail(&cmd->qe, &mod->cmd_q);
266462306a36Sopenharmony_ci		return true;
266562306a36Sopenharmony_ci	}
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	/**
266862306a36Sopenharmony_ci	 * If mailbox is busy, queue command for poll timer
266962306a36Sopenharmony_ci	 */
267062306a36Sopenharmony_ci	stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
267162306a36Sopenharmony_ci	if (stat) {
267262306a36Sopenharmony_ci		list_add_tail(&cmd->qe, &mod->cmd_q);
267362306a36Sopenharmony_ci		return true;
267462306a36Sopenharmony_ci	}
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci	/**
267762306a36Sopenharmony_ci	 * mailbox is free -- queue command to firmware
267862306a36Sopenharmony_ci	 */
267962306a36Sopenharmony_ci	bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	return false;
268262306a36Sopenharmony_ci}
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_ci/* Handle mailbox interrupts */
268562306a36Sopenharmony_civoid
268662306a36Sopenharmony_cibfa_nw_ioc_mbox_isr(struct bfa_ioc *ioc)
268762306a36Sopenharmony_ci{
268862306a36Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
268962306a36Sopenharmony_ci	struct bfi_mbmsg m;
269062306a36Sopenharmony_ci	int				mc;
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	if (bfa_ioc_msgget(ioc, &m)) {
269362306a36Sopenharmony_ci		/**
269462306a36Sopenharmony_ci		 * Treat IOC message class as special.
269562306a36Sopenharmony_ci		 */
269662306a36Sopenharmony_ci		mc = m.mh.msg_class;
269762306a36Sopenharmony_ci		if (mc == BFI_MC_IOC) {
269862306a36Sopenharmony_ci			bfa_ioc_isr(ioc, &m);
269962306a36Sopenharmony_ci			return;
270062306a36Sopenharmony_ci		}
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci		if ((mc >= BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL))
270362306a36Sopenharmony_ci			return;
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci		mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
270662306a36Sopenharmony_ci	}
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	bfa_ioc_lpu_read_stat(ioc);
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	/**
271162306a36Sopenharmony_ci	 * Try to send pending mailbox commands
271262306a36Sopenharmony_ci	 */
271362306a36Sopenharmony_ci	bfa_ioc_mbox_poll(ioc);
271462306a36Sopenharmony_ci}
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_civoid
271762306a36Sopenharmony_cibfa_nw_ioc_error_isr(struct bfa_ioc *ioc)
271862306a36Sopenharmony_ci{
271962306a36Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_hbfails);
272062306a36Sopenharmony_ci	bfa_ioc_stats_hb_count(ioc, ioc->hb_count);
272162306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_HWERROR);
272262306a36Sopenharmony_ci}
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci/* return true if IOC is disabled */
272562306a36Sopenharmony_cibool
272662306a36Sopenharmony_cibfa_nw_ioc_is_disabled(struct bfa_ioc *ioc)
272762306a36Sopenharmony_ci{
272862306a36Sopenharmony_ci	return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling) ||
272962306a36Sopenharmony_ci		bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled);
273062306a36Sopenharmony_ci}
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci/* return true if IOC is operational */
273362306a36Sopenharmony_cibool
273462306a36Sopenharmony_cibfa_nw_ioc_is_operational(struct bfa_ioc *ioc)
273562306a36Sopenharmony_ci{
273662306a36Sopenharmony_ci	return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
273762306a36Sopenharmony_ci}
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci/* Add to IOC heartbeat failure notification queue. To be used by common
274062306a36Sopenharmony_ci * modules such as cee, port, diag.
274162306a36Sopenharmony_ci */
274262306a36Sopenharmony_civoid
274362306a36Sopenharmony_cibfa_nw_ioc_notify_register(struct bfa_ioc *ioc,
274462306a36Sopenharmony_ci			struct bfa_ioc_notify *notify)
274562306a36Sopenharmony_ci{
274662306a36Sopenharmony_ci	list_add_tail(&notify->qe, &ioc->notify_q);
274762306a36Sopenharmony_ci}
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci#define BFA_MFG_NAME "QLogic"
275062306a36Sopenharmony_cistatic void
275162306a36Sopenharmony_cibfa_ioc_get_adapter_attr(struct bfa_ioc *ioc,
275262306a36Sopenharmony_ci			 struct bfa_adapter_attr *ad_attr)
275362306a36Sopenharmony_ci{
275462306a36Sopenharmony_ci	struct bfi_ioc_attr *ioc_attr;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	ioc_attr = ioc->attr;
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	bfa_ioc_get_adapter_serial_num(ioc, ad_attr->serial_num);
275962306a36Sopenharmony_ci	bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver);
276062306a36Sopenharmony_ci	bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver);
276162306a36Sopenharmony_ci	bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer);
276262306a36Sopenharmony_ci	memcpy(&ad_attr->vpd, &ioc_attr->vpd,
276362306a36Sopenharmony_ci		      sizeof(struct bfa_mfg_vpd));
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	ad_attr->nports = bfa_ioc_get_nports(ioc);
276662306a36Sopenharmony_ci	ad_attr->max_speed = bfa_ioc_speed_sup(ioc);
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	bfa_ioc_get_adapter_model(ioc, ad_attr->model);
276962306a36Sopenharmony_ci	/* For now, model descr uses same model string */
277062306a36Sopenharmony_ci	bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr);
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	ad_attr->card_type = ioc_attr->card_type;
277362306a36Sopenharmony_ci	ad_attr->is_mezz = bfa_mfg_is_mezz(ioc_attr->card_type);
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
277662306a36Sopenharmony_ci		ad_attr->prototype = 1;
277762306a36Sopenharmony_ci	else
277862306a36Sopenharmony_ci		ad_attr->prototype = 0;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
278162306a36Sopenharmony_ci	bfa_nw_ioc_get_mac(ioc, ad_attr->mac);
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	ad_attr->pcie_gen = ioc_attr->pcie_gen;
278462306a36Sopenharmony_ci	ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
278562306a36Sopenharmony_ci	ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;
278662306a36Sopenharmony_ci	ad_attr->asic_rev = ioc_attr->asic_rev;
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver);
278962306a36Sopenharmony_ci}
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_cistatic enum bfa_ioc_type
279262306a36Sopenharmony_cibfa_ioc_get_type(struct bfa_ioc *ioc)
279362306a36Sopenharmony_ci{
279462306a36Sopenharmony_ci	if (ioc->clscode == BFI_PCIFN_CLASS_ETH)
279562306a36Sopenharmony_ci		return BFA_IOC_TYPE_LL;
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	BUG_ON(!(ioc->clscode == BFI_PCIFN_CLASS_FC));
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	return (ioc->attr->port_mode == BFI_PORT_MODE_FC)
280062306a36Sopenharmony_ci		? BFA_IOC_TYPE_FC : BFA_IOC_TYPE_FCoE;
280162306a36Sopenharmony_ci}
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_cistatic void
280462306a36Sopenharmony_cibfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, char *serial_num)
280562306a36Sopenharmony_ci{
280662306a36Sopenharmony_ci	memcpy(serial_num,
280762306a36Sopenharmony_ci			(void *)ioc->attr->brcd_serialnum,
280862306a36Sopenharmony_ci			BFA_ADAPTER_SERIAL_NUM_LEN);
280962306a36Sopenharmony_ci}
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_cistatic void
281262306a36Sopenharmony_cibfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc, char *fw_ver)
281362306a36Sopenharmony_ci{
281462306a36Sopenharmony_ci	memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
281562306a36Sopenharmony_ci}
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_cistatic void
281862306a36Sopenharmony_cibfa_ioc_get_pci_chip_rev(struct bfa_ioc *ioc, char *chip_rev)
281962306a36Sopenharmony_ci{
282062306a36Sopenharmony_ci	BUG_ON(!(chip_rev));
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	memset(chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	chip_rev[0] = 'R';
282562306a36Sopenharmony_ci	chip_rev[1] = 'e';
282662306a36Sopenharmony_ci	chip_rev[2] = 'v';
282762306a36Sopenharmony_ci	chip_rev[3] = '-';
282862306a36Sopenharmony_ci	chip_rev[4] = ioc->attr->asic_rev;
282962306a36Sopenharmony_ci	chip_rev[5] = '\0';
283062306a36Sopenharmony_ci}
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_cistatic void
283362306a36Sopenharmony_cibfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc, char *optrom_ver)
283462306a36Sopenharmony_ci{
283562306a36Sopenharmony_ci	memcpy(optrom_ver, ioc->attr->optrom_version,
283662306a36Sopenharmony_ci		      BFA_VERSION_LEN);
283762306a36Sopenharmony_ci}
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_cistatic void
284062306a36Sopenharmony_cibfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer)
284162306a36Sopenharmony_ci{
284262306a36Sopenharmony_ci	strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
284362306a36Sopenharmony_ci}
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_cistatic void
284662306a36Sopenharmony_cibfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model)
284762306a36Sopenharmony_ci{
284862306a36Sopenharmony_ci	struct bfi_ioc_attr *ioc_attr;
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	BUG_ON(!(model));
285162306a36Sopenharmony_ci	memset(model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	ioc_attr = ioc->attr;
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
285662306a36Sopenharmony_ci		BFA_MFG_NAME, ioc_attr->card_type);
285762306a36Sopenharmony_ci}
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_cistatic enum bfa_ioc_state
286062306a36Sopenharmony_cibfa_ioc_get_state(struct bfa_ioc *ioc)
286162306a36Sopenharmony_ci{
286262306a36Sopenharmony_ci	enum bfa_iocpf_state iocpf_st;
286362306a36Sopenharmony_ci	enum bfa_ioc_state ioc_st = ioc_sm_to_state(ioc_sm_table, ioc->fsm);
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	if (ioc_st == BFA_IOC_ENABLING ||
286662306a36Sopenharmony_ci		ioc_st == BFA_IOC_FAIL || ioc_st == BFA_IOC_INITFAIL) {
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci		iocpf_st = iocpf_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm);
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci		switch (iocpf_st) {
287162306a36Sopenharmony_ci		case BFA_IOCPF_SEMWAIT:
287262306a36Sopenharmony_ci			ioc_st = BFA_IOC_SEMWAIT;
287362306a36Sopenharmony_ci			break;
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci		case BFA_IOCPF_HWINIT:
287662306a36Sopenharmony_ci			ioc_st = BFA_IOC_HWINIT;
287762306a36Sopenharmony_ci			break;
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci		case BFA_IOCPF_FWMISMATCH:
288062306a36Sopenharmony_ci			ioc_st = BFA_IOC_FWMISMATCH;
288162306a36Sopenharmony_ci			break;
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci		case BFA_IOCPF_FAIL:
288462306a36Sopenharmony_ci			ioc_st = BFA_IOC_FAIL;
288562306a36Sopenharmony_ci			break;
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci		case BFA_IOCPF_INITFAIL:
288862306a36Sopenharmony_ci			ioc_st = BFA_IOC_INITFAIL;
288962306a36Sopenharmony_ci			break;
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci		default:
289262306a36Sopenharmony_ci			break;
289362306a36Sopenharmony_ci		}
289462306a36Sopenharmony_ci	}
289562306a36Sopenharmony_ci	return ioc_st;
289662306a36Sopenharmony_ci}
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_civoid
289962306a36Sopenharmony_cibfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr)
290062306a36Sopenharmony_ci{
290162306a36Sopenharmony_ci	memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr));
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci	ioc_attr->state = bfa_ioc_get_state(ioc);
290462306a36Sopenharmony_ci	ioc_attr->port_id = bfa_ioc_portid(ioc);
290562306a36Sopenharmony_ci	ioc_attr->port_mode = ioc->port_mode;
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci	ioc_attr->port_mode_cfg = ioc->port_mode_cfg;
290862306a36Sopenharmony_ci	ioc_attr->cap_bm = ioc->ad_cap_bm;
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	ioc_attr->ioc_type = bfa_ioc_get_type(ioc);
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	ioc_attr->pci_attr.device_id = bfa_ioc_devid(ioc);
291562306a36Sopenharmony_ci	ioc_attr->pci_attr.pcifn = bfa_ioc_pcifn(ioc);
291662306a36Sopenharmony_ci	ioc_attr->def_fn = bfa_ioc_is_default(ioc);
291762306a36Sopenharmony_ci	bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
291862306a36Sopenharmony_ci}
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci/* WWN public */
292162306a36Sopenharmony_cistatic u64
292262306a36Sopenharmony_cibfa_ioc_get_pwwn(struct bfa_ioc *ioc)
292362306a36Sopenharmony_ci{
292462306a36Sopenharmony_ci	return ioc->attr->pwwn;
292562306a36Sopenharmony_ci}
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_civoid
292862306a36Sopenharmony_cibfa_nw_ioc_get_mac(struct bfa_ioc *ioc, u8 *mac)
292962306a36Sopenharmony_ci{
293062306a36Sopenharmony_ci	ether_addr_copy(mac, ioc->attr->mac);
293162306a36Sopenharmony_ci}
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci/* Firmware failure detected. Start recovery actions. */
293462306a36Sopenharmony_cistatic void
293562306a36Sopenharmony_cibfa_ioc_recover(struct bfa_ioc *ioc)
293662306a36Sopenharmony_ci{
293762306a36Sopenharmony_ci	pr_crit("Heart Beat of IOC has failed\n");
293862306a36Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_hbfails);
293962306a36Sopenharmony_ci	bfa_ioc_stats_hb_count(ioc, ioc->hb_count);
294062306a36Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
294162306a36Sopenharmony_ci}
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci/* BFA IOC PF private functions */
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_cistatic void
294662306a36Sopenharmony_cibfa_iocpf_enable(struct bfa_ioc *ioc)
294762306a36Sopenharmony_ci{
294862306a36Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE);
294962306a36Sopenharmony_ci}
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_cistatic void
295262306a36Sopenharmony_cibfa_iocpf_disable(struct bfa_ioc *ioc)
295362306a36Sopenharmony_ci{
295462306a36Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);
295562306a36Sopenharmony_ci}
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_cistatic void
295862306a36Sopenharmony_cibfa_iocpf_fail(struct bfa_ioc *ioc)
295962306a36Sopenharmony_ci{
296062306a36Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
296162306a36Sopenharmony_ci}
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_cistatic void
296462306a36Sopenharmony_cibfa_iocpf_initfail(struct bfa_ioc *ioc)
296562306a36Sopenharmony_ci{
296662306a36Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
296762306a36Sopenharmony_ci}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_cistatic void
297062306a36Sopenharmony_cibfa_iocpf_getattrfail(struct bfa_ioc *ioc)
297162306a36Sopenharmony_ci{
297262306a36Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL);
297362306a36Sopenharmony_ci}
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_cistatic void
297662306a36Sopenharmony_cibfa_iocpf_stop(struct bfa_ioc *ioc)
297762306a36Sopenharmony_ci{
297862306a36Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
297962306a36Sopenharmony_ci}
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_civoid
298262306a36Sopenharmony_cibfa_nw_iocpf_timeout(struct bfa_ioc *ioc)
298362306a36Sopenharmony_ci{
298462306a36Sopenharmony_ci	enum bfa_iocpf_state iocpf_st;
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci	iocpf_st = iocpf_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm);
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci	if (iocpf_st == BFA_IOCPF_HWINIT)
298962306a36Sopenharmony_ci		bfa_ioc_poll_fwinit(ioc);
299062306a36Sopenharmony_ci	else
299162306a36Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
299262306a36Sopenharmony_ci}
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_civoid
299562306a36Sopenharmony_cibfa_nw_iocpf_sem_timeout(struct bfa_ioc *ioc)
299662306a36Sopenharmony_ci{
299762306a36Sopenharmony_ci	bfa_ioc_hw_sem_get(ioc);
299862306a36Sopenharmony_ci}
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_cistatic void
300162306a36Sopenharmony_cibfa_ioc_poll_fwinit(struct bfa_ioc *ioc)
300262306a36Sopenharmony_ci{
300362306a36Sopenharmony_ci	u32 fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	if (fwstate == BFI_IOC_DISABLED) {
300662306a36Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);
300762306a36Sopenharmony_ci		return;
300862306a36Sopenharmony_ci	}
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	if (ioc->iocpf.poll_time >= BFA_IOC_TOV) {
301162306a36Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
301262306a36Sopenharmony_ci	} else {
301362306a36Sopenharmony_ci		ioc->iocpf.poll_time += BFA_IOC_POLL_TOV;
301462306a36Sopenharmony_ci		mod_timer(&ioc->iocpf_timer, jiffies +
301562306a36Sopenharmony_ci			msecs_to_jiffies(BFA_IOC_POLL_TOV));
301662306a36Sopenharmony_ci	}
301762306a36Sopenharmony_ci}
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci/*
302062306a36Sopenharmony_ci *	Flash module specific
302162306a36Sopenharmony_ci */
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci/*
302462306a36Sopenharmony_ci * FLASH DMA buffer should be big enough to hold both MFG block and
302562306a36Sopenharmony_ci * asic block(64k) at the same time and also should be 2k aligned to
302662306a36Sopenharmony_ci * avoid write segement to cross sector boundary.
302762306a36Sopenharmony_ci */
302862306a36Sopenharmony_ci#define BFA_FLASH_SEG_SZ	2048
302962306a36Sopenharmony_ci#define BFA_FLASH_DMA_BUF_SZ	\
303062306a36Sopenharmony_ci	roundup(0x010000 + sizeof(struct bfa_mfg_block), BFA_FLASH_SEG_SZ)
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_cistatic void
303362306a36Sopenharmony_cibfa_flash_cb(struct bfa_flash *flash)
303462306a36Sopenharmony_ci{
303562306a36Sopenharmony_ci	flash->op_busy = 0;
303662306a36Sopenharmony_ci	if (flash->cbfn)
303762306a36Sopenharmony_ci		flash->cbfn(flash->cbarg, flash->status);
303862306a36Sopenharmony_ci}
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_cistatic void
304162306a36Sopenharmony_cibfa_flash_notify(void *cbarg, enum bfa_ioc_event event)
304262306a36Sopenharmony_ci{
304362306a36Sopenharmony_ci	struct bfa_flash *flash = cbarg;
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci	switch (event) {
304662306a36Sopenharmony_ci	case BFA_IOC_E_DISABLED:
304762306a36Sopenharmony_ci	case BFA_IOC_E_FAILED:
304862306a36Sopenharmony_ci		if (flash->op_busy) {
304962306a36Sopenharmony_ci			flash->status = BFA_STATUS_IOC_FAILURE;
305062306a36Sopenharmony_ci			flash->cbfn(flash->cbarg, flash->status);
305162306a36Sopenharmony_ci			flash->op_busy = 0;
305262306a36Sopenharmony_ci		}
305362306a36Sopenharmony_ci		break;
305462306a36Sopenharmony_ci	default:
305562306a36Sopenharmony_ci		break;
305662306a36Sopenharmony_ci	}
305762306a36Sopenharmony_ci}
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci/*
306062306a36Sopenharmony_ci * Send flash write request.
306162306a36Sopenharmony_ci */
306262306a36Sopenharmony_cistatic void
306362306a36Sopenharmony_cibfa_flash_write_send(struct bfa_flash *flash)
306462306a36Sopenharmony_ci{
306562306a36Sopenharmony_ci	struct bfi_flash_write_req *msg =
306662306a36Sopenharmony_ci			(struct bfi_flash_write_req *) flash->mb.msg;
306762306a36Sopenharmony_ci	u32	len;
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	msg->type = be32_to_cpu(flash->type);
307062306a36Sopenharmony_ci	msg->instance = flash->instance;
307162306a36Sopenharmony_ci	msg->offset = be32_to_cpu(flash->addr_off + flash->offset);
307262306a36Sopenharmony_ci	len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ?
307362306a36Sopenharmony_ci	       flash->residue : BFA_FLASH_DMA_BUF_SZ;
307462306a36Sopenharmony_ci	msg->length = be32_to_cpu(len);
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	/* indicate if it's the last msg of the whole write operation */
307762306a36Sopenharmony_ci	msg->last = (len == flash->residue) ? 1 : 0;
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci	bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_WRITE_REQ,
308062306a36Sopenharmony_ci		    bfa_ioc_portid(flash->ioc));
308162306a36Sopenharmony_ci	bfa_alen_set(&msg->alen, len, flash->dbuf_pa);
308262306a36Sopenharmony_ci	memcpy(flash->dbuf_kva, flash->ubuf + flash->offset, len);
308362306a36Sopenharmony_ci	bfa_nw_ioc_mbox_queue(flash->ioc, &flash->mb, NULL, NULL);
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci	flash->residue -= len;
308662306a36Sopenharmony_ci	flash->offset += len;
308762306a36Sopenharmony_ci}
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci/**
309062306a36Sopenharmony_ci * bfa_flash_read_send - Send flash read request.
309162306a36Sopenharmony_ci *
309262306a36Sopenharmony_ci * @cbarg: callback argument
309362306a36Sopenharmony_ci */
309462306a36Sopenharmony_cistatic void
309562306a36Sopenharmony_cibfa_flash_read_send(void *cbarg)
309662306a36Sopenharmony_ci{
309762306a36Sopenharmony_ci	struct bfa_flash *flash = cbarg;
309862306a36Sopenharmony_ci	struct bfi_flash_read_req *msg =
309962306a36Sopenharmony_ci			(struct bfi_flash_read_req *) flash->mb.msg;
310062306a36Sopenharmony_ci	u32	len;
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	msg->type = be32_to_cpu(flash->type);
310362306a36Sopenharmony_ci	msg->instance = flash->instance;
310462306a36Sopenharmony_ci	msg->offset = be32_to_cpu(flash->addr_off + flash->offset);
310562306a36Sopenharmony_ci	len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ?
310662306a36Sopenharmony_ci	       flash->residue : BFA_FLASH_DMA_BUF_SZ;
310762306a36Sopenharmony_ci	msg->length = be32_to_cpu(len);
310862306a36Sopenharmony_ci	bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_READ_REQ,
310962306a36Sopenharmony_ci		    bfa_ioc_portid(flash->ioc));
311062306a36Sopenharmony_ci	bfa_alen_set(&msg->alen, len, flash->dbuf_pa);
311162306a36Sopenharmony_ci	bfa_nw_ioc_mbox_queue(flash->ioc, &flash->mb, NULL, NULL);
311262306a36Sopenharmony_ci}
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci/**
311562306a36Sopenharmony_ci * bfa_flash_intr - Process flash response messages upon receiving interrupts.
311662306a36Sopenharmony_ci *
311762306a36Sopenharmony_ci * @flasharg: flash structure
311862306a36Sopenharmony_ci * @msg: message structure
311962306a36Sopenharmony_ci */
312062306a36Sopenharmony_cistatic void
312162306a36Sopenharmony_cibfa_flash_intr(void *flasharg, struct bfi_mbmsg *msg)
312262306a36Sopenharmony_ci{
312362306a36Sopenharmony_ci	struct bfa_flash *flash = flasharg;
312462306a36Sopenharmony_ci	u32	status;
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_ci	union {
312762306a36Sopenharmony_ci		struct bfi_flash_query_rsp *query;
312862306a36Sopenharmony_ci		struct bfi_flash_write_rsp *write;
312962306a36Sopenharmony_ci		struct bfi_flash_read_rsp *read;
313062306a36Sopenharmony_ci		struct bfi_mbmsg   *msg;
313162306a36Sopenharmony_ci	} m;
313262306a36Sopenharmony_ci
313362306a36Sopenharmony_ci	m.msg = msg;
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci	/* receiving response after ioc failure */
313662306a36Sopenharmony_ci	if (!flash->op_busy && msg->mh.msg_id != BFI_FLASH_I2H_EVENT)
313762306a36Sopenharmony_ci		return;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	switch (msg->mh.msg_id) {
314062306a36Sopenharmony_ci	case BFI_FLASH_I2H_QUERY_RSP:
314162306a36Sopenharmony_ci		status = be32_to_cpu(m.query->status);
314262306a36Sopenharmony_ci		if (status == BFA_STATUS_OK) {
314362306a36Sopenharmony_ci			u32	i;
314462306a36Sopenharmony_ci			struct bfa_flash_attr *attr, *f;
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci			attr = (struct bfa_flash_attr *) flash->ubuf;
314762306a36Sopenharmony_ci			f = (struct bfa_flash_attr *) flash->dbuf_kva;
314862306a36Sopenharmony_ci			attr->status = be32_to_cpu(f->status);
314962306a36Sopenharmony_ci			attr->npart = be32_to_cpu(f->npart);
315062306a36Sopenharmony_ci			for (i = 0; i < attr->npart; i++) {
315162306a36Sopenharmony_ci				attr->part[i].part_type =
315262306a36Sopenharmony_ci					be32_to_cpu(f->part[i].part_type);
315362306a36Sopenharmony_ci				attr->part[i].part_instance =
315462306a36Sopenharmony_ci					be32_to_cpu(f->part[i].part_instance);
315562306a36Sopenharmony_ci				attr->part[i].part_off =
315662306a36Sopenharmony_ci					be32_to_cpu(f->part[i].part_off);
315762306a36Sopenharmony_ci				attr->part[i].part_size =
315862306a36Sopenharmony_ci					be32_to_cpu(f->part[i].part_size);
315962306a36Sopenharmony_ci				attr->part[i].part_len =
316062306a36Sopenharmony_ci					be32_to_cpu(f->part[i].part_len);
316162306a36Sopenharmony_ci				attr->part[i].part_status =
316262306a36Sopenharmony_ci					be32_to_cpu(f->part[i].part_status);
316362306a36Sopenharmony_ci			}
316462306a36Sopenharmony_ci		}
316562306a36Sopenharmony_ci		flash->status = status;
316662306a36Sopenharmony_ci		bfa_flash_cb(flash);
316762306a36Sopenharmony_ci		break;
316862306a36Sopenharmony_ci	case BFI_FLASH_I2H_WRITE_RSP:
316962306a36Sopenharmony_ci		status = be32_to_cpu(m.write->status);
317062306a36Sopenharmony_ci		if (status != BFA_STATUS_OK || flash->residue == 0) {
317162306a36Sopenharmony_ci			flash->status = status;
317262306a36Sopenharmony_ci			bfa_flash_cb(flash);
317362306a36Sopenharmony_ci		} else
317462306a36Sopenharmony_ci			bfa_flash_write_send(flash);
317562306a36Sopenharmony_ci		break;
317662306a36Sopenharmony_ci	case BFI_FLASH_I2H_READ_RSP:
317762306a36Sopenharmony_ci		status = be32_to_cpu(m.read->status);
317862306a36Sopenharmony_ci		if (status != BFA_STATUS_OK) {
317962306a36Sopenharmony_ci			flash->status = status;
318062306a36Sopenharmony_ci			bfa_flash_cb(flash);
318162306a36Sopenharmony_ci		} else {
318262306a36Sopenharmony_ci			u32 len = be32_to_cpu(m.read->length);
318362306a36Sopenharmony_ci			memcpy(flash->ubuf + flash->offset,
318462306a36Sopenharmony_ci			       flash->dbuf_kva, len);
318562306a36Sopenharmony_ci			flash->residue -= len;
318662306a36Sopenharmony_ci			flash->offset += len;
318762306a36Sopenharmony_ci			if (flash->residue == 0) {
318862306a36Sopenharmony_ci				flash->status = status;
318962306a36Sopenharmony_ci				bfa_flash_cb(flash);
319062306a36Sopenharmony_ci			} else
319162306a36Sopenharmony_ci				bfa_flash_read_send(flash);
319262306a36Sopenharmony_ci		}
319362306a36Sopenharmony_ci		break;
319462306a36Sopenharmony_ci	case BFI_FLASH_I2H_BOOT_VER_RSP:
319562306a36Sopenharmony_ci	case BFI_FLASH_I2H_EVENT:
319662306a36Sopenharmony_ci		break;
319762306a36Sopenharmony_ci	default:
319862306a36Sopenharmony_ci		WARN_ON(1);
319962306a36Sopenharmony_ci	}
320062306a36Sopenharmony_ci}
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci/*
320362306a36Sopenharmony_ci * Flash memory info API.
320462306a36Sopenharmony_ci */
320562306a36Sopenharmony_ciu32
320662306a36Sopenharmony_cibfa_nw_flash_meminfo(void)
320762306a36Sopenharmony_ci{
320862306a36Sopenharmony_ci	return roundup(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
320962306a36Sopenharmony_ci}
321062306a36Sopenharmony_ci
321162306a36Sopenharmony_ci/**
321262306a36Sopenharmony_ci * bfa_nw_flash_attach - Flash attach API.
321362306a36Sopenharmony_ci *
321462306a36Sopenharmony_ci * @flash: flash structure
321562306a36Sopenharmony_ci * @ioc: ioc structure
321662306a36Sopenharmony_ci * @dev: device structure
321762306a36Sopenharmony_ci */
321862306a36Sopenharmony_civoid
321962306a36Sopenharmony_cibfa_nw_flash_attach(struct bfa_flash *flash, struct bfa_ioc *ioc, void *dev)
322062306a36Sopenharmony_ci{
322162306a36Sopenharmony_ci	flash->ioc = ioc;
322262306a36Sopenharmony_ci	flash->cbfn = NULL;
322362306a36Sopenharmony_ci	flash->cbarg = NULL;
322462306a36Sopenharmony_ci	flash->op_busy = 0;
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	bfa_nw_ioc_mbox_regisr(flash->ioc, BFI_MC_FLASH, bfa_flash_intr, flash);
322762306a36Sopenharmony_ci	bfa_ioc_notify_init(&flash->ioc_notify, bfa_flash_notify, flash);
322862306a36Sopenharmony_ci	list_add_tail(&flash->ioc_notify.qe, &flash->ioc->notify_q);
322962306a36Sopenharmony_ci}
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci/**
323262306a36Sopenharmony_ci * bfa_nw_flash_memclaim - Claim memory for flash
323362306a36Sopenharmony_ci *
323462306a36Sopenharmony_ci * @flash: flash structure
323562306a36Sopenharmony_ci * @dm_kva: pointer to virtual memory address
323662306a36Sopenharmony_ci * @dm_pa: physical memory address
323762306a36Sopenharmony_ci */
323862306a36Sopenharmony_civoid
323962306a36Sopenharmony_cibfa_nw_flash_memclaim(struct bfa_flash *flash, u8 *dm_kva, u64 dm_pa)
324062306a36Sopenharmony_ci{
324162306a36Sopenharmony_ci	flash->dbuf_kva = dm_kva;
324262306a36Sopenharmony_ci	flash->dbuf_pa = dm_pa;
324362306a36Sopenharmony_ci	memset(flash->dbuf_kva, 0, BFA_FLASH_DMA_BUF_SZ);
324462306a36Sopenharmony_ci	dm_kva += roundup(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
324562306a36Sopenharmony_ci	dm_pa += roundup(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
324662306a36Sopenharmony_ci}
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci/**
324962306a36Sopenharmony_ci * bfa_nw_flash_get_attr - Get flash attribute.
325062306a36Sopenharmony_ci *
325162306a36Sopenharmony_ci * @flash: flash structure
325262306a36Sopenharmony_ci * @attr: flash attribute structure
325362306a36Sopenharmony_ci * @cbfn: callback function
325462306a36Sopenharmony_ci * @cbarg: callback argument
325562306a36Sopenharmony_ci *
325662306a36Sopenharmony_ci * Return status.
325762306a36Sopenharmony_ci */
325862306a36Sopenharmony_cienum bfa_status
325962306a36Sopenharmony_cibfa_nw_flash_get_attr(struct bfa_flash *flash, struct bfa_flash_attr *attr,
326062306a36Sopenharmony_ci		      bfa_cb_flash cbfn, void *cbarg)
326162306a36Sopenharmony_ci{
326262306a36Sopenharmony_ci	struct bfi_flash_query_req *msg =
326362306a36Sopenharmony_ci			(struct bfi_flash_query_req *) flash->mb.msg;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	if (!bfa_nw_ioc_is_operational(flash->ioc))
326662306a36Sopenharmony_ci		return BFA_STATUS_IOC_NON_OP;
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	if (flash->op_busy)
326962306a36Sopenharmony_ci		return BFA_STATUS_DEVBUSY;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	flash->op_busy = 1;
327262306a36Sopenharmony_ci	flash->cbfn = cbfn;
327362306a36Sopenharmony_ci	flash->cbarg = cbarg;
327462306a36Sopenharmony_ci	flash->ubuf = (u8 *) attr;
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_QUERY_REQ,
327762306a36Sopenharmony_ci		    bfa_ioc_portid(flash->ioc));
327862306a36Sopenharmony_ci	bfa_alen_set(&msg->alen, sizeof(struct bfa_flash_attr), flash->dbuf_pa);
327962306a36Sopenharmony_ci	bfa_nw_ioc_mbox_queue(flash->ioc, &flash->mb, NULL, NULL);
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	return BFA_STATUS_OK;
328262306a36Sopenharmony_ci}
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci/**
328562306a36Sopenharmony_ci * bfa_nw_flash_update_part - Update flash partition.
328662306a36Sopenharmony_ci *
328762306a36Sopenharmony_ci * @flash: flash structure
328862306a36Sopenharmony_ci * @type: flash partition type
328962306a36Sopenharmony_ci * @instance: flash partition instance
329062306a36Sopenharmony_ci * @buf: update data buffer
329162306a36Sopenharmony_ci * @len: data buffer length
329262306a36Sopenharmony_ci * @offset: offset relative to the partition starting address
329362306a36Sopenharmony_ci * @cbfn: callback function
329462306a36Sopenharmony_ci * @cbarg: callback argument
329562306a36Sopenharmony_ci *
329662306a36Sopenharmony_ci * Return status.
329762306a36Sopenharmony_ci */
329862306a36Sopenharmony_cienum bfa_status
329962306a36Sopenharmony_cibfa_nw_flash_update_part(struct bfa_flash *flash, u32 type, u8 instance,
330062306a36Sopenharmony_ci			 void *buf, u32 len, u32 offset,
330162306a36Sopenharmony_ci			 bfa_cb_flash cbfn, void *cbarg)
330262306a36Sopenharmony_ci{
330362306a36Sopenharmony_ci	if (!bfa_nw_ioc_is_operational(flash->ioc))
330462306a36Sopenharmony_ci		return BFA_STATUS_IOC_NON_OP;
330562306a36Sopenharmony_ci
330662306a36Sopenharmony_ci	/*
330762306a36Sopenharmony_ci	 * 'len' must be in word (4-byte) boundary
330862306a36Sopenharmony_ci	 */
330962306a36Sopenharmony_ci	if (!len || (len & 0x03))
331062306a36Sopenharmony_ci		return BFA_STATUS_FLASH_BAD_LEN;
331162306a36Sopenharmony_ci
331262306a36Sopenharmony_ci	if (type == BFA_FLASH_PART_MFG)
331362306a36Sopenharmony_ci		return BFA_STATUS_EINVAL;
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci	if (flash->op_busy)
331662306a36Sopenharmony_ci		return BFA_STATUS_DEVBUSY;
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	flash->op_busy = 1;
331962306a36Sopenharmony_ci	flash->cbfn = cbfn;
332062306a36Sopenharmony_ci	flash->cbarg = cbarg;
332162306a36Sopenharmony_ci	flash->type = type;
332262306a36Sopenharmony_ci	flash->instance = instance;
332362306a36Sopenharmony_ci	flash->residue = len;
332462306a36Sopenharmony_ci	flash->offset = 0;
332562306a36Sopenharmony_ci	flash->addr_off = offset;
332662306a36Sopenharmony_ci	flash->ubuf = buf;
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_ci	bfa_flash_write_send(flash);
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ci	return BFA_STATUS_OK;
333162306a36Sopenharmony_ci}
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci/**
333462306a36Sopenharmony_ci * bfa_nw_flash_read_part - Read flash partition.
333562306a36Sopenharmony_ci *
333662306a36Sopenharmony_ci * @flash: flash structure
333762306a36Sopenharmony_ci * @type: flash partition type
333862306a36Sopenharmony_ci * @instance: flash partition instance
333962306a36Sopenharmony_ci * @buf: read data buffer
334062306a36Sopenharmony_ci * @len: data buffer length
334162306a36Sopenharmony_ci * @offset: offset relative to the partition starting address
334262306a36Sopenharmony_ci * @cbfn: callback function
334362306a36Sopenharmony_ci * @cbarg: callback argument
334462306a36Sopenharmony_ci *
334562306a36Sopenharmony_ci * Return status.
334662306a36Sopenharmony_ci */
334762306a36Sopenharmony_cienum bfa_status
334862306a36Sopenharmony_cibfa_nw_flash_read_part(struct bfa_flash *flash, u32 type, u8 instance,
334962306a36Sopenharmony_ci		       void *buf, u32 len, u32 offset,
335062306a36Sopenharmony_ci		       bfa_cb_flash cbfn, void *cbarg)
335162306a36Sopenharmony_ci{
335262306a36Sopenharmony_ci	if (!bfa_nw_ioc_is_operational(flash->ioc))
335362306a36Sopenharmony_ci		return BFA_STATUS_IOC_NON_OP;
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	/*
335662306a36Sopenharmony_ci	 * 'len' must be in word (4-byte) boundary
335762306a36Sopenharmony_ci	 */
335862306a36Sopenharmony_ci	if (!len || (len & 0x03))
335962306a36Sopenharmony_ci		return BFA_STATUS_FLASH_BAD_LEN;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci	if (flash->op_busy)
336262306a36Sopenharmony_ci		return BFA_STATUS_DEVBUSY;
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	flash->op_busy = 1;
336562306a36Sopenharmony_ci	flash->cbfn = cbfn;
336662306a36Sopenharmony_ci	flash->cbarg = cbarg;
336762306a36Sopenharmony_ci	flash->type = type;
336862306a36Sopenharmony_ci	flash->instance = instance;
336962306a36Sopenharmony_ci	flash->residue = len;
337062306a36Sopenharmony_ci	flash->offset = 0;
337162306a36Sopenharmony_ci	flash->addr_off = offset;
337262306a36Sopenharmony_ci	flash->ubuf = buf;
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci	bfa_flash_read_send(flash);
337562306a36Sopenharmony_ci
337662306a36Sopenharmony_ci	return BFA_STATUS_OK;
337762306a36Sopenharmony_ci}
3378