18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Linux network driver for QLogic BR-series Converged Network Adapter.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci/*
68c2ecf20Sopenharmony_ci * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
78c2ecf20Sopenharmony_ci * Copyright (c) 2014-2015 QLogic Corporation
88c2ecf20Sopenharmony_ci * All rights reserved
98c2ecf20Sopenharmony_ci * www.qlogic.com
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "bfa_ioc.h"
138c2ecf20Sopenharmony_ci#include "bfi_reg.h"
148c2ecf20Sopenharmony_ci#include "bfa_defs.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* IOC local definitions */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details. */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define bfa_ioc_firmware_lock(__ioc)			\
218c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc))
228c2ecf20Sopenharmony_ci#define bfa_ioc_firmware_unlock(__ioc)			\
238c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))
248c2ecf20Sopenharmony_ci#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))
258c2ecf20Sopenharmony_ci#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))
268c2ecf20Sopenharmony_ci#define bfa_ioc_notify_fail(__ioc)			\
278c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_notify_fail(__ioc))
288c2ecf20Sopenharmony_ci#define bfa_ioc_sync_start(__ioc)               \
298c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_start(__ioc))
308c2ecf20Sopenharmony_ci#define bfa_ioc_sync_join(__ioc)			\
318c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_join(__ioc))
328c2ecf20Sopenharmony_ci#define bfa_ioc_sync_leave(__ioc)			\
338c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_leave(__ioc))
348c2ecf20Sopenharmony_ci#define bfa_ioc_sync_ack(__ioc)				\
358c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_ack(__ioc))
368c2ecf20Sopenharmony_ci#define bfa_ioc_sync_complete(__ioc)			\
378c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_sync_complete(__ioc))
388c2ecf20Sopenharmony_ci#define bfa_ioc_set_cur_ioc_fwstate(__ioc, __fwstate)		\
398c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_set_fwstate(__ioc, __fwstate))
408c2ecf20Sopenharmony_ci#define bfa_ioc_get_cur_ioc_fwstate(__ioc)		\
418c2ecf20Sopenharmony_ci			((__ioc)->ioc_hwif->ioc_get_fwstate(__ioc))
428c2ecf20Sopenharmony_ci#define bfa_ioc_set_alt_ioc_fwstate(__ioc, __fwstate)		\
438c2ecf20Sopenharmony_ci		((__ioc)->ioc_hwif->ioc_set_alt_fwstate(__ioc, __fwstate))
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic bool bfa_nw_auto_recover = true;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci * forward declarations
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_cistatic void bfa_ioc_hw_sem_init(struct bfa_ioc *ioc);
518c2ecf20Sopenharmony_cistatic void bfa_ioc_hw_sem_get(struct bfa_ioc *ioc);
528c2ecf20Sopenharmony_cistatic void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc);
538c2ecf20Sopenharmony_cistatic void bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force);
548c2ecf20Sopenharmony_cistatic void bfa_ioc_poll_fwinit(struct bfa_ioc *ioc);
558c2ecf20Sopenharmony_cistatic void bfa_ioc_send_enable(struct bfa_ioc *ioc);
568c2ecf20Sopenharmony_cistatic void bfa_ioc_send_disable(struct bfa_ioc *ioc);
578c2ecf20Sopenharmony_cistatic void bfa_ioc_send_getattr(struct bfa_ioc *ioc);
588c2ecf20Sopenharmony_cistatic void bfa_ioc_hb_monitor(struct bfa_ioc *ioc);
598c2ecf20Sopenharmony_cistatic void bfa_ioc_hb_stop(struct bfa_ioc *ioc);
608c2ecf20Sopenharmony_cistatic void bfa_ioc_reset(struct bfa_ioc *ioc, bool force);
618c2ecf20Sopenharmony_cistatic void bfa_ioc_mbox_poll(struct bfa_ioc *ioc);
628c2ecf20Sopenharmony_cistatic void bfa_ioc_mbox_flush(struct bfa_ioc *ioc);
638c2ecf20Sopenharmony_cistatic void bfa_ioc_recover(struct bfa_ioc *ioc);
648c2ecf20Sopenharmony_cistatic void bfa_ioc_event_notify(struct bfa_ioc *, enum bfa_ioc_event);
658c2ecf20Sopenharmony_cistatic void bfa_ioc_disable_comp(struct bfa_ioc *ioc);
668c2ecf20Sopenharmony_cistatic void bfa_ioc_lpu_stop(struct bfa_ioc *ioc);
678c2ecf20Sopenharmony_cistatic void bfa_nw_ioc_debug_save_ftrc(struct bfa_ioc *ioc);
688c2ecf20Sopenharmony_cistatic void bfa_ioc_fail_notify(struct bfa_ioc *ioc);
698c2ecf20Sopenharmony_cistatic void bfa_ioc_pf_enabled(struct bfa_ioc *ioc);
708c2ecf20Sopenharmony_cistatic void bfa_ioc_pf_disabled(struct bfa_ioc *ioc);
718c2ecf20Sopenharmony_cistatic void bfa_ioc_pf_failed(struct bfa_ioc *ioc);
728c2ecf20Sopenharmony_cistatic void bfa_ioc_pf_hwfailed(struct bfa_ioc *ioc);
738c2ecf20Sopenharmony_cistatic void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc);
748c2ecf20Sopenharmony_cistatic enum bfa_status bfa_ioc_boot(struct bfa_ioc *ioc,
758c2ecf20Sopenharmony_ci			enum bfi_fwboot_type boot_type, u32 boot_param);
768c2ecf20Sopenharmony_cistatic u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr);
778c2ecf20Sopenharmony_cistatic void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc,
788c2ecf20Sopenharmony_ci						char *serial_num);
798c2ecf20Sopenharmony_cistatic void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc,
808c2ecf20Sopenharmony_ci						char *fw_ver);
818c2ecf20Sopenharmony_cistatic void bfa_ioc_get_pci_chip_rev(struct bfa_ioc *ioc,
828c2ecf20Sopenharmony_ci						char *chip_rev);
838c2ecf20Sopenharmony_cistatic void bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc,
848c2ecf20Sopenharmony_ci						char *optrom_ver);
858c2ecf20Sopenharmony_cistatic void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc,
868c2ecf20Sopenharmony_ci						char *manufacturer);
878c2ecf20Sopenharmony_cistatic void bfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model);
888c2ecf20Sopenharmony_cistatic u64 bfa_ioc_get_pwwn(struct bfa_ioc *ioc);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/* IOC state machine definitions/declarations */
918c2ecf20Sopenharmony_cienum ioc_event {
928c2ecf20Sopenharmony_ci	IOC_E_RESET		= 1,	/*!< IOC reset request		*/
938c2ecf20Sopenharmony_ci	IOC_E_ENABLE		= 2,	/*!< IOC enable request		*/
948c2ecf20Sopenharmony_ci	IOC_E_DISABLE		= 3,	/*!< IOC disable request	*/
958c2ecf20Sopenharmony_ci	IOC_E_DETACH		= 4,	/*!< driver detach cleanup	*/
968c2ecf20Sopenharmony_ci	IOC_E_ENABLED		= 5,	/*!< f/w enabled		*/
978c2ecf20Sopenharmony_ci	IOC_E_FWRSP_GETATTR	= 6,	/*!< IOC get attribute response	*/
988c2ecf20Sopenharmony_ci	IOC_E_DISABLED		= 7,	/*!< f/w disabled		*/
998c2ecf20Sopenharmony_ci	IOC_E_PFFAILED		= 8,	/*!< failure notice by iocpf sm	*/
1008c2ecf20Sopenharmony_ci	IOC_E_HBFAIL		= 9,	/*!< heartbeat failure		*/
1018c2ecf20Sopenharmony_ci	IOC_E_HWERROR		= 10,	/*!< hardware error interrupt	*/
1028c2ecf20Sopenharmony_ci	IOC_E_TIMEOUT		= 11,	/*!< timeout			*/
1038c2ecf20Sopenharmony_ci	IOC_E_HWFAILED		= 12,	/*!< PCI mapping failure notice	*/
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc, enum ioc_event);
1078c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc, enum ioc_event);
1088c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc, enum ioc_event);
1098c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc, enum ioc_event);
1108c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc, enum ioc_event);
1118c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc, enum ioc_event);
1128c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc, enum ioc_event);
1138c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc, enum ioc_event);
1148c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc, enum ioc_event);
1158c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc, enum ioc_event);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic struct bfa_sm_table ioc_sm_table[] = {
1188c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT},
1198c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},
1208c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING},
1218c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
1228c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
1238c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_fail_retry), BFA_IOC_INITFAIL},
1248c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL},
1258c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
1268c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
1278c2ecf20Sopenharmony_ci	{BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL},
1288c2ecf20Sopenharmony_ci};
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/*
1318c2ecf20Sopenharmony_ci * Forward declareations for iocpf state machine
1328c2ecf20Sopenharmony_ci */
1338c2ecf20Sopenharmony_cistatic void bfa_iocpf_enable(struct bfa_ioc *ioc);
1348c2ecf20Sopenharmony_cistatic void bfa_iocpf_disable(struct bfa_ioc *ioc);
1358c2ecf20Sopenharmony_cistatic void bfa_iocpf_fail(struct bfa_ioc *ioc);
1368c2ecf20Sopenharmony_cistatic void bfa_iocpf_initfail(struct bfa_ioc *ioc);
1378c2ecf20Sopenharmony_cistatic void bfa_iocpf_getattrfail(struct bfa_ioc *ioc);
1388c2ecf20Sopenharmony_cistatic void bfa_iocpf_stop(struct bfa_ioc *ioc);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/* IOCPF state machine events */
1418c2ecf20Sopenharmony_cienum iocpf_event {
1428c2ecf20Sopenharmony_ci	IOCPF_E_ENABLE		= 1,	/*!< IOCPF enable request	*/
1438c2ecf20Sopenharmony_ci	IOCPF_E_DISABLE		= 2,	/*!< IOCPF disable request	*/
1448c2ecf20Sopenharmony_ci	IOCPF_E_STOP		= 3,	/*!< stop on driver detach	*/
1458c2ecf20Sopenharmony_ci	IOCPF_E_FWREADY		= 4,	/*!< f/w initialization done	*/
1468c2ecf20Sopenharmony_ci	IOCPF_E_FWRSP_ENABLE	= 5,	/*!< enable f/w response	*/
1478c2ecf20Sopenharmony_ci	IOCPF_E_FWRSP_DISABLE	= 6,	/*!< disable f/w response	*/
1488c2ecf20Sopenharmony_ci	IOCPF_E_FAIL		= 7,	/*!< failure notice by ioc sm	*/
1498c2ecf20Sopenharmony_ci	IOCPF_E_INITFAIL	= 8,	/*!< init fail notice by ioc sm	*/
1508c2ecf20Sopenharmony_ci	IOCPF_E_GETATTRFAIL	= 9,	/*!< init fail notice by ioc sm	*/
1518c2ecf20Sopenharmony_ci	IOCPF_E_SEMLOCKED	= 10,   /*!< h/w semaphore is locked	*/
1528c2ecf20Sopenharmony_ci	IOCPF_E_TIMEOUT		= 11,   /*!< f/w response timeout	*/
1538c2ecf20Sopenharmony_ci	IOCPF_E_SEM_ERROR	= 12,   /*!< h/w sem mapping error	*/
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/* IOCPF states */
1578c2ecf20Sopenharmony_cienum bfa_iocpf_state {
1588c2ecf20Sopenharmony_ci	BFA_IOCPF_RESET		= 1,	/*!< IOC is in reset state */
1598c2ecf20Sopenharmony_ci	BFA_IOCPF_SEMWAIT	= 2,	/*!< Waiting for IOC h/w semaphore */
1608c2ecf20Sopenharmony_ci	BFA_IOCPF_HWINIT	= 3,	/*!< IOC h/w is being initialized */
1618c2ecf20Sopenharmony_ci	BFA_IOCPF_READY		= 4,	/*!< IOCPF is initialized */
1628c2ecf20Sopenharmony_ci	BFA_IOCPF_INITFAIL	= 5,	/*!< IOCPF failed */
1638c2ecf20Sopenharmony_ci	BFA_IOCPF_FAIL		= 6,	/*!< IOCPF failed */
1648c2ecf20Sopenharmony_ci	BFA_IOCPF_DISABLING	= 7,	/*!< IOCPF is being disabled */
1658c2ecf20Sopenharmony_ci	BFA_IOCPF_DISABLED	= 8,	/*!< IOCPF is disabled */
1668c2ecf20Sopenharmony_ci	BFA_IOCPF_FWMISMATCH	= 9,	/*!< IOC f/w different from drivers */
1678c2ecf20Sopenharmony_ci};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, reset, struct bfa_iocpf, enum iocpf_event);
1708c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, fwcheck, struct bfa_iocpf, enum iocpf_event);
1718c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, mismatch, struct bfa_iocpf, enum iocpf_event);
1728c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, semwait, struct bfa_iocpf, enum iocpf_event);
1738c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, hwinit, struct bfa_iocpf, enum iocpf_event);
1748c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, enabling, struct bfa_iocpf, enum iocpf_event);
1758c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, ready, struct bfa_iocpf, enum iocpf_event);
1768c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, initfail_sync, struct bfa_iocpf,
1778c2ecf20Sopenharmony_ci						enum iocpf_event);
1788c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, initfail, struct bfa_iocpf, enum iocpf_event);
1798c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, fail_sync, struct bfa_iocpf, enum iocpf_event);
1808c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, fail, struct bfa_iocpf, enum iocpf_event);
1818c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, disabling, struct bfa_iocpf, enum iocpf_event);
1828c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, disabling_sync, struct bfa_iocpf,
1838c2ecf20Sopenharmony_ci						enum iocpf_event);
1848c2ecf20Sopenharmony_cibfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf, enum iocpf_event);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic struct bfa_sm_table iocpf_sm_table[] = {
1878c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET},
1888c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH},
1898c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH},
1908c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_semwait), BFA_IOCPF_SEMWAIT},
1918c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_hwinit), BFA_IOCPF_HWINIT},
1928c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_enabling), BFA_IOCPF_HWINIT},
1938c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_ready), BFA_IOCPF_READY},
1948c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_initfail_sync), BFA_IOCPF_INITFAIL},
1958c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_initfail), BFA_IOCPF_INITFAIL},
1968c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_fail_sync), BFA_IOCPF_FAIL},
1978c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_fail), BFA_IOCPF_FAIL},
1988c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_disabling), BFA_IOCPF_DISABLING},
1998c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_disabling_sync), BFA_IOCPF_DISABLING},
2008c2ecf20Sopenharmony_ci	{BFA_SM(bfa_iocpf_sm_disabled), BFA_IOCPF_DISABLED},
2018c2ecf20Sopenharmony_ci};
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci/* IOC State Machine */
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci/* Beginning state. IOC uninit state. */
2068c2ecf20Sopenharmony_cistatic void
2078c2ecf20Sopenharmony_cibfa_ioc_sm_uninit_entry(struct bfa_ioc *ioc)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci/* IOC is in uninit state. */
2128c2ecf20Sopenharmony_cistatic void
2138c2ecf20Sopenharmony_cibfa_ioc_sm_uninit(struct bfa_ioc *ioc, enum ioc_event event)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	switch (event) {
2168c2ecf20Sopenharmony_ci	case IOC_E_RESET:
2178c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
2188c2ecf20Sopenharmony_ci		break;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	default:
2218c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci/* Reset entry actions -- initialize state machine */
2268c2ecf20Sopenharmony_cistatic void
2278c2ecf20Sopenharmony_cibfa_ioc_sm_reset_entry(struct bfa_ioc *ioc)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	bfa_fsm_set_state(&ioc->iocpf, bfa_iocpf_sm_reset);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci/* IOC is in reset state. */
2338c2ecf20Sopenharmony_cistatic void
2348c2ecf20Sopenharmony_cibfa_ioc_sm_reset(struct bfa_ioc *ioc, enum ioc_event event)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	switch (event) {
2378c2ecf20Sopenharmony_ci	case IOC_E_ENABLE:
2388c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
2398c2ecf20Sopenharmony_ci		break;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	case IOC_E_DISABLE:
2428c2ecf20Sopenharmony_ci		bfa_ioc_disable_comp(ioc);
2438c2ecf20Sopenharmony_ci		break;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	case IOC_E_DETACH:
2468c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
2478c2ecf20Sopenharmony_ci		break;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	default:
2508c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic void
2558c2ecf20Sopenharmony_cibfa_ioc_sm_enabling_entry(struct bfa_ioc *ioc)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	bfa_iocpf_enable(ioc);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci/* Host IOC function is being enabled, awaiting response from firmware.
2618c2ecf20Sopenharmony_ci * Semaphore is acquired.
2628c2ecf20Sopenharmony_ci */
2638c2ecf20Sopenharmony_cistatic void
2648c2ecf20Sopenharmony_cibfa_ioc_sm_enabling(struct bfa_ioc *ioc, enum ioc_event event)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	switch (event) {
2678c2ecf20Sopenharmony_ci	case IOC_E_ENABLED:
2688c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	case IOC_E_PFFAILED:
2728c2ecf20Sopenharmony_ci		fallthrough;
2738c2ecf20Sopenharmony_ci	case IOC_E_HWERROR:
2748c2ecf20Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
2758c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
2768c2ecf20Sopenharmony_ci		if (event != IOC_E_PFFAILED)
2778c2ecf20Sopenharmony_ci			bfa_iocpf_initfail(ioc);
2788c2ecf20Sopenharmony_ci		break;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	case IOC_E_HWFAILED:
2818c2ecf20Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
2828c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
2838c2ecf20Sopenharmony_ci		break;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	case IOC_E_DISABLE:
2868c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	case IOC_E_DETACH:
2908c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
2918c2ecf20Sopenharmony_ci		bfa_iocpf_stop(ioc);
2928c2ecf20Sopenharmony_ci		break;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	case IOC_E_ENABLE:
2958c2ecf20Sopenharmony_ci		break;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	default:
2988c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci/* Semaphore should be acquired for version check. */
3038c2ecf20Sopenharmony_cistatic void
3048c2ecf20Sopenharmony_cibfa_ioc_sm_getattr_entry(struct bfa_ioc *ioc)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	mod_timer(&ioc->ioc_timer, jiffies +
3078c2ecf20Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_TOV));
3088c2ecf20Sopenharmony_ci	bfa_ioc_send_getattr(ioc);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci/* IOC configuration in progress. Timer is active. */
3128c2ecf20Sopenharmony_cistatic void
3138c2ecf20Sopenharmony_cibfa_ioc_sm_getattr(struct bfa_ioc *ioc, enum ioc_event event)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	switch (event) {
3168c2ecf20Sopenharmony_ci	case IOC_E_FWRSP_GETATTR:
3178c2ecf20Sopenharmony_ci		del_timer(&ioc->ioc_timer);
3188c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
3198c2ecf20Sopenharmony_ci		break;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	case IOC_E_PFFAILED:
3228c2ecf20Sopenharmony_ci	case IOC_E_HWERROR:
3238c2ecf20Sopenharmony_ci		del_timer(&ioc->ioc_timer);
3248c2ecf20Sopenharmony_ci		fallthrough;
3258c2ecf20Sopenharmony_ci	case IOC_E_TIMEOUT:
3268c2ecf20Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
3278c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
3288c2ecf20Sopenharmony_ci		if (event != IOC_E_PFFAILED)
3298c2ecf20Sopenharmony_ci			bfa_iocpf_getattrfail(ioc);
3308c2ecf20Sopenharmony_ci		break;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	case IOC_E_DISABLE:
3338c2ecf20Sopenharmony_ci		del_timer(&ioc->ioc_timer);
3348c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
3358c2ecf20Sopenharmony_ci		break;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	case IOC_E_ENABLE:
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	default:
3418c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic void
3468c2ecf20Sopenharmony_cibfa_ioc_sm_op_entry(struct bfa_ioc *ioc)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
3498c2ecf20Sopenharmony_ci	bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED);
3508c2ecf20Sopenharmony_ci	bfa_ioc_hb_monitor(ioc);
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic void
3548c2ecf20Sopenharmony_cibfa_ioc_sm_op(struct bfa_ioc *ioc, enum ioc_event event)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	switch (event) {
3578c2ecf20Sopenharmony_ci	case IOC_E_ENABLE:
3588c2ecf20Sopenharmony_ci		break;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	case IOC_E_DISABLE:
3618c2ecf20Sopenharmony_ci		bfa_ioc_hb_stop(ioc);
3628c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
3638c2ecf20Sopenharmony_ci		break;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	case IOC_E_PFFAILED:
3668c2ecf20Sopenharmony_ci	case IOC_E_HWERROR:
3678c2ecf20Sopenharmony_ci		bfa_ioc_hb_stop(ioc);
3688c2ecf20Sopenharmony_ci		fallthrough;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	case IOC_E_HBFAIL:
3718c2ecf20Sopenharmony_ci		if (ioc->iocpf.auto_recover)
3728c2ecf20Sopenharmony_ci			bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);
3738c2ecf20Sopenharmony_ci		else
3748c2ecf20Sopenharmony_ci			bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci		bfa_ioc_fail_notify(ioc);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci		if (event != IOC_E_PFFAILED)
3798c2ecf20Sopenharmony_ci			bfa_iocpf_fail(ioc);
3808c2ecf20Sopenharmony_ci		break;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	default:
3838c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic void
3888c2ecf20Sopenharmony_cibfa_ioc_sm_disabling_entry(struct bfa_ioc *ioc)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	bfa_iocpf_disable(ioc);
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci/* IOC is being disabled */
3948c2ecf20Sopenharmony_cistatic void
3958c2ecf20Sopenharmony_cibfa_ioc_sm_disabling(struct bfa_ioc *ioc, enum ioc_event event)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	switch (event) {
3988c2ecf20Sopenharmony_ci	case IOC_E_DISABLED:
3998c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
4008c2ecf20Sopenharmony_ci		break;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	case IOC_E_HWERROR:
4038c2ecf20Sopenharmony_ci		/*
4048c2ecf20Sopenharmony_ci		 * No state change.  Will move to disabled state
4058c2ecf20Sopenharmony_ci		 * after iocpf sm completes failure processing and
4068c2ecf20Sopenharmony_ci		 * moves to disabled state.
4078c2ecf20Sopenharmony_ci		 */
4088c2ecf20Sopenharmony_ci		bfa_iocpf_fail(ioc);
4098c2ecf20Sopenharmony_ci		break;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	case IOC_E_HWFAILED:
4128c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
4138c2ecf20Sopenharmony_ci		bfa_ioc_disable_comp(ioc);
4148c2ecf20Sopenharmony_ci		break;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	default:
4178c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci/* IOC disable completion entry. */
4228c2ecf20Sopenharmony_cistatic void
4238c2ecf20Sopenharmony_cibfa_ioc_sm_disabled_entry(struct bfa_ioc *ioc)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	bfa_ioc_disable_comp(ioc);
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic void
4298c2ecf20Sopenharmony_cibfa_ioc_sm_disabled(struct bfa_ioc *ioc, enum ioc_event event)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	switch (event) {
4328c2ecf20Sopenharmony_ci	case IOC_E_ENABLE:
4338c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
4348c2ecf20Sopenharmony_ci		break;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	case IOC_E_DISABLE:
4378c2ecf20Sopenharmony_ci		ioc->cbfn->disable_cbfn(ioc->bfa);
4388c2ecf20Sopenharmony_ci		break;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	case IOC_E_DETACH:
4418c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
4428c2ecf20Sopenharmony_ci		bfa_iocpf_stop(ioc);
4438c2ecf20Sopenharmony_ci		break;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	default:
4468c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
4478c2ecf20Sopenharmony_ci	}
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic void
4518c2ecf20Sopenharmony_cibfa_ioc_sm_fail_retry_entry(struct bfa_ioc *ioc)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci/* Hardware initialization retry. */
4568c2ecf20Sopenharmony_cistatic void
4578c2ecf20Sopenharmony_cibfa_ioc_sm_fail_retry(struct bfa_ioc *ioc, enum ioc_event event)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	switch (event) {
4608c2ecf20Sopenharmony_ci	case IOC_E_ENABLED:
4618c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
4628c2ecf20Sopenharmony_ci		break;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	case IOC_E_PFFAILED:
4658c2ecf20Sopenharmony_ci	case IOC_E_HWERROR:
4668c2ecf20Sopenharmony_ci		/**
4678c2ecf20Sopenharmony_ci		 * Initialization retry failed.
4688c2ecf20Sopenharmony_ci		 */
4698c2ecf20Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
4708c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);
4718c2ecf20Sopenharmony_ci		if (event != IOC_E_PFFAILED)
4728c2ecf20Sopenharmony_ci			bfa_iocpf_initfail(ioc);
4738c2ecf20Sopenharmony_ci		break;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	case IOC_E_HWFAILED:
4768c2ecf20Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
4778c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);
4788c2ecf20Sopenharmony_ci		break;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	case IOC_E_ENABLE:
4818c2ecf20Sopenharmony_ci		break;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	case IOC_E_DISABLE:
4848c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
4858c2ecf20Sopenharmony_ci		break;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	case IOC_E_DETACH:
4888c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
4898c2ecf20Sopenharmony_ci		bfa_iocpf_stop(ioc);
4908c2ecf20Sopenharmony_ci		break;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	default:
4938c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic void
4988c2ecf20Sopenharmony_cibfa_ioc_sm_fail_entry(struct bfa_ioc *ioc)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci/* IOC failure. */
5038c2ecf20Sopenharmony_cistatic void
5048c2ecf20Sopenharmony_cibfa_ioc_sm_fail(struct bfa_ioc *ioc, enum ioc_event event)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	switch (event) {
5078c2ecf20Sopenharmony_ci	case IOC_E_ENABLE:
5088c2ecf20Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
5098c2ecf20Sopenharmony_ci		break;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	case IOC_E_DISABLE:
5128c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
5138c2ecf20Sopenharmony_ci		break;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	case IOC_E_DETACH:
5168c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
5178c2ecf20Sopenharmony_ci		bfa_iocpf_stop(ioc);
5188c2ecf20Sopenharmony_ci		break;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	case IOC_E_HWERROR:
5218c2ecf20Sopenharmony_ci		/* HB failure notification, ignore. */
5228c2ecf20Sopenharmony_ci		break;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	default:
5258c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic void
5308c2ecf20Sopenharmony_cibfa_ioc_sm_hwfail_entry(struct bfa_ioc *ioc)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci/* IOC failure. */
5358c2ecf20Sopenharmony_cistatic void
5368c2ecf20Sopenharmony_cibfa_ioc_sm_hwfail(struct bfa_ioc *ioc, enum ioc_event event)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	switch (event) {
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	case IOC_E_ENABLE:
5418c2ecf20Sopenharmony_ci		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
5428c2ecf20Sopenharmony_ci		break;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	case IOC_E_DISABLE:
5458c2ecf20Sopenharmony_ci		ioc->cbfn->disable_cbfn(ioc->bfa);
5468c2ecf20Sopenharmony_ci		break;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	case IOC_E_DETACH:
5498c2ecf20Sopenharmony_ci		bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
5508c2ecf20Sopenharmony_ci		break;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	default:
5538c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci/* IOCPF State Machine */
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci/* Reset entry actions -- initialize state machine */
5608c2ecf20Sopenharmony_cistatic void
5618c2ecf20Sopenharmony_cibfa_iocpf_sm_reset_entry(struct bfa_iocpf *iocpf)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	iocpf->fw_mismatch_notified = false;
5648c2ecf20Sopenharmony_ci	iocpf->auto_recover = bfa_nw_auto_recover;
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci/* Beginning state. IOC is in reset state. */
5688c2ecf20Sopenharmony_cistatic void
5698c2ecf20Sopenharmony_cibfa_iocpf_sm_reset(struct bfa_iocpf *iocpf, enum iocpf_event event)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	switch (event) {
5728c2ecf20Sopenharmony_ci	case IOCPF_E_ENABLE:
5738c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck);
5748c2ecf20Sopenharmony_ci		break;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	case IOCPF_E_STOP:
5778c2ecf20Sopenharmony_ci		break;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	default:
5808c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci/* Semaphore should be acquired for version check. */
5858c2ecf20Sopenharmony_cistatic void
5868c2ecf20Sopenharmony_cibfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf *iocpf)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	bfa_ioc_hw_sem_init(iocpf->ioc);
5898c2ecf20Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci/* Awaiting h/w semaphore to continue with version check. */
5938c2ecf20Sopenharmony_cistatic void
5948c2ecf20Sopenharmony_cibfa_iocpf_sm_fwcheck(struct bfa_iocpf *iocpf, enum iocpf_event event)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	switch (event) {
5998c2ecf20Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
6008c2ecf20Sopenharmony_ci		if (bfa_ioc_firmware_lock(ioc)) {
6018c2ecf20Sopenharmony_ci			if (bfa_ioc_sync_start(ioc)) {
6028c2ecf20Sopenharmony_ci				bfa_ioc_sync_join(ioc);
6038c2ecf20Sopenharmony_ci				bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
6048c2ecf20Sopenharmony_ci			} else {
6058c2ecf20Sopenharmony_ci				bfa_ioc_firmware_unlock(ioc);
6068c2ecf20Sopenharmony_ci				bfa_nw_ioc_hw_sem_release(ioc);
6078c2ecf20Sopenharmony_ci				mod_timer(&ioc->sem_timer, jiffies +
6088c2ecf20Sopenharmony_ci					msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
6098c2ecf20Sopenharmony_ci			}
6108c2ecf20Sopenharmony_ci		} else {
6118c2ecf20Sopenharmony_ci			bfa_nw_ioc_hw_sem_release(ioc);
6128c2ecf20Sopenharmony_ci			bfa_fsm_set_state(iocpf, bfa_iocpf_sm_mismatch);
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci		break;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
6178c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
6188c2ecf20Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
6198c2ecf20Sopenharmony_ci		break;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
6228c2ecf20Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
6238c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
6248c2ecf20Sopenharmony_ci		bfa_ioc_pf_disabled(ioc);
6258c2ecf20Sopenharmony_ci		break;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	case IOCPF_E_STOP:
6288c2ecf20Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
6298c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
6308c2ecf20Sopenharmony_ci		break;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	default:
6338c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci/* Notify enable completion callback */
6388c2ecf20Sopenharmony_cistatic void
6398c2ecf20Sopenharmony_cibfa_iocpf_sm_mismatch_entry(struct bfa_iocpf *iocpf)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	/* Call only the first time sm enters fwmismatch state. */
6428c2ecf20Sopenharmony_ci	if (!iocpf->fw_mismatch_notified)
6438c2ecf20Sopenharmony_ci		bfa_ioc_pf_fwmismatch(iocpf->ioc);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	iocpf->fw_mismatch_notified = true;
6468c2ecf20Sopenharmony_ci	mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
6478c2ecf20Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_TOV));
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci/* Awaiting firmware version match. */
6518c2ecf20Sopenharmony_cistatic void
6528c2ecf20Sopenharmony_cibfa_iocpf_sm_mismatch(struct bfa_iocpf *iocpf, enum iocpf_event event)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	switch (event) {
6578c2ecf20Sopenharmony_ci	case IOCPF_E_TIMEOUT:
6588c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck);
6598c2ecf20Sopenharmony_ci		break;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
6628c2ecf20Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
6638c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
6648c2ecf20Sopenharmony_ci		bfa_ioc_pf_disabled(ioc);
6658c2ecf20Sopenharmony_ci		break;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	case IOCPF_E_STOP:
6688c2ecf20Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
6698c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
6708c2ecf20Sopenharmony_ci		break;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	default:
6738c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
6748c2ecf20Sopenharmony_ci	}
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci/* Request for semaphore. */
6788c2ecf20Sopenharmony_cistatic void
6798c2ecf20Sopenharmony_cibfa_iocpf_sm_semwait_entry(struct bfa_iocpf *iocpf)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci/* Awaiting semaphore for h/w initialzation. */
6858c2ecf20Sopenharmony_cistatic void
6868c2ecf20Sopenharmony_cibfa_iocpf_sm_semwait(struct bfa_iocpf *iocpf, enum iocpf_event event)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	switch (event) {
6918c2ecf20Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
6928c2ecf20Sopenharmony_ci		if (bfa_ioc_sync_complete(ioc)) {
6938c2ecf20Sopenharmony_ci			bfa_ioc_sync_join(ioc);
6948c2ecf20Sopenharmony_ci			bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
6958c2ecf20Sopenharmony_ci		} else {
6968c2ecf20Sopenharmony_ci			bfa_nw_ioc_hw_sem_release(ioc);
6978c2ecf20Sopenharmony_ci			mod_timer(&ioc->sem_timer, jiffies +
6988c2ecf20Sopenharmony_ci				msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
6998c2ecf20Sopenharmony_ci		}
7008c2ecf20Sopenharmony_ci		break;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
7038c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
7048c2ecf20Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
7058c2ecf20Sopenharmony_ci		break;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
7088c2ecf20Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
7098c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
7108c2ecf20Sopenharmony_ci		break;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	default:
7138c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic void
7188c2ecf20Sopenharmony_cibfa_iocpf_sm_hwinit_entry(struct bfa_iocpf *iocpf)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	iocpf->poll_time = 0;
7218c2ecf20Sopenharmony_ci	bfa_ioc_reset(iocpf->ioc, false);
7228c2ecf20Sopenharmony_ci}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci/* Hardware is being initialized. Interrupts are enabled.
7258c2ecf20Sopenharmony_ci * Holding hardware semaphore lock.
7268c2ecf20Sopenharmony_ci */
7278c2ecf20Sopenharmony_cistatic void
7288c2ecf20Sopenharmony_cibfa_iocpf_sm_hwinit(struct bfa_iocpf *iocpf, enum iocpf_event event)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	switch (event) {
7338c2ecf20Sopenharmony_ci	case IOCPF_E_FWREADY:
7348c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_enabling);
7358c2ecf20Sopenharmony_ci		break;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	case IOCPF_E_TIMEOUT:
7388c2ecf20Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
7398c2ecf20Sopenharmony_ci		bfa_ioc_pf_failed(ioc);
7408c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
7418c2ecf20Sopenharmony_ci		break;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
7448c2ecf20Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
7458c2ecf20Sopenharmony_ci		bfa_ioc_sync_leave(ioc);
7468c2ecf20Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
7478c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
7488c2ecf20Sopenharmony_ci		break;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	default:
7518c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic void
7568c2ecf20Sopenharmony_cibfa_iocpf_sm_enabling_entry(struct bfa_iocpf *iocpf)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
7598c2ecf20Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_TOV));
7608c2ecf20Sopenharmony_ci	/**
7618c2ecf20Sopenharmony_ci	 * Enable Interrupts before sending fw IOC ENABLE cmd.
7628c2ecf20Sopenharmony_ci	 */
7638c2ecf20Sopenharmony_ci	iocpf->ioc->cbfn->reset_cbfn(iocpf->ioc->bfa);
7648c2ecf20Sopenharmony_ci	bfa_ioc_send_enable(iocpf->ioc);
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci/* Host IOC function is being enabled, awaiting response from firmware.
7688c2ecf20Sopenharmony_ci * Semaphore is acquired.
7698c2ecf20Sopenharmony_ci */
7708c2ecf20Sopenharmony_cistatic void
7718c2ecf20Sopenharmony_cibfa_iocpf_sm_enabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
7728c2ecf20Sopenharmony_ci{
7738c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	switch (event) {
7768c2ecf20Sopenharmony_ci	case IOCPF_E_FWRSP_ENABLE:
7778c2ecf20Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
7788c2ecf20Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
7798c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_ready);
7808c2ecf20Sopenharmony_ci		break;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	case IOCPF_E_INITFAIL:
7838c2ecf20Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
7848c2ecf20Sopenharmony_ci		fallthrough;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	case IOCPF_E_TIMEOUT:
7878c2ecf20Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
7888c2ecf20Sopenharmony_ci		if (event == IOCPF_E_TIMEOUT)
7898c2ecf20Sopenharmony_ci			bfa_ioc_pf_failed(ioc);
7908c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
7918c2ecf20Sopenharmony_ci		break;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
7948c2ecf20Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
7958c2ecf20Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
7968c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
7978c2ecf20Sopenharmony_ci		break;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	default:
8008c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
8018c2ecf20Sopenharmony_ci	}
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic void
8058c2ecf20Sopenharmony_cibfa_iocpf_sm_ready_entry(struct bfa_iocpf *iocpf)
8068c2ecf20Sopenharmony_ci{
8078c2ecf20Sopenharmony_ci	bfa_ioc_pf_enabled(iocpf->ioc);
8088c2ecf20Sopenharmony_ci}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_cistatic void
8118c2ecf20Sopenharmony_cibfa_iocpf_sm_ready(struct bfa_iocpf *iocpf, enum iocpf_event event)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci	switch (event) {
8148c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
8158c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);
8168c2ecf20Sopenharmony_ci		break;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	case IOCPF_E_GETATTRFAIL:
8198c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);
8208c2ecf20Sopenharmony_ci		break;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	case IOCPF_E_FAIL:
8238c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);
8248c2ecf20Sopenharmony_ci		break;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	default:
8278c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cistatic void
8328c2ecf20Sopenharmony_cibfa_iocpf_sm_disabling_entry(struct bfa_iocpf *iocpf)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	mod_timer(&(iocpf->ioc)->iocpf_timer, jiffies +
8358c2ecf20Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_TOV));
8368c2ecf20Sopenharmony_ci	bfa_ioc_send_disable(iocpf->ioc);
8378c2ecf20Sopenharmony_ci}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci/* IOC is being disabled */
8408c2ecf20Sopenharmony_cistatic void
8418c2ecf20Sopenharmony_cibfa_iocpf_sm_disabling(struct bfa_iocpf *iocpf, enum iocpf_event event)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	switch (event) {
8468c2ecf20Sopenharmony_ci	case IOCPF_E_FWRSP_DISABLE:
8478c2ecf20Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
8488c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
8498c2ecf20Sopenharmony_ci		break;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	case IOCPF_E_FAIL:
8528c2ecf20Sopenharmony_ci		del_timer(&ioc->iocpf_timer);
8538c2ecf20Sopenharmony_ci		fallthrough;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	case IOCPF_E_TIMEOUT:
8568c2ecf20Sopenharmony_ci		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
8578c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
8588c2ecf20Sopenharmony_ci		break;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	case IOCPF_E_FWRSP_ENABLE:
8618c2ecf20Sopenharmony_ci		break;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	default:
8648c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
8658c2ecf20Sopenharmony_ci	}
8668c2ecf20Sopenharmony_ci}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_cistatic void
8698c2ecf20Sopenharmony_cibfa_iocpf_sm_disabling_sync_entry(struct bfa_iocpf *iocpf)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci/* IOC hb ack request is being removed. */
8758c2ecf20Sopenharmony_cistatic void
8768c2ecf20Sopenharmony_cibfa_iocpf_sm_disabling_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	switch (event) {
8818c2ecf20Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
8828c2ecf20Sopenharmony_ci		bfa_ioc_sync_leave(ioc);
8838c2ecf20Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
8848c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
8858c2ecf20Sopenharmony_ci		break;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
8888c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
8898c2ecf20Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
8908c2ecf20Sopenharmony_ci		break;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	case IOCPF_E_FAIL:
8938c2ecf20Sopenharmony_ci		break;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	default:
8968c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci/* IOC disable completion entry. */
9018c2ecf20Sopenharmony_cistatic void
9028c2ecf20Sopenharmony_cibfa_iocpf_sm_disabled_entry(struct bfa_iocpf *iocpf)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	bfa_ioc_mbox_flush(iocpf->ioc);
9058c2ecf20Sopenharmony_ci	bfa_ioc_pf_disabled(iocpf->ioc);
9068c2ecf20Sopenharmony_ci}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistatic void
9098c2ecf20Sopenharmony_cibfa_iocpf_sm_disabled(struct bfa_iocpf *iocpf, enum iocpf_event event)
9108c2ecf20Sopenharmony_ci{
9118c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	switch (event) {
9148c2ecf20Sopenharmony_ci	case IOCPF_E_ENABLE:
9158c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
9168c2ecf20Sopenharmony_ci		break;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	case IOCPF_E_STOP:
9198c2ecf20Sopenharmony_ci		bfa_ioc_firmware_unlock(ioc);
9208c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
9218c2ecf20Sopenharmony_ci		break;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	default:
9248c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_cistatic void
9298c2ecf20Sopenharmony_cibfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf *iocpf)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	bfa_nw_ioc_debug_save_ftrc(iocpf->ioc);
9328c2ecf20Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
9338c2ecf20Sopenharmony_ci}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci/* Hardware initialization failed. */
9368c2ecf20Sopenharmony_cistatic void
9378c2ecf20Sopenharmony_cibfa_iocpf_sm_initfail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
9388c2ecf20Sopenharmony_ci{
9398c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	switch (event) {
9428c2ecf20Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
9438c2ecf20Sopenharmony_ci		bfa_ioc_notify_fail(ioc);
9448c2ecf20Sopenharmony_ci		bfa_ioc_sync_leave(ioc);
9458c2ecf20Sopenharmony_ci		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
9468c2ecf20Sopenharmony_ci		bfa_nw_ioc_hw_sem_release(ioc);
9478c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);
9488c2ecf20Sopenharmony_ci		break;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
9518c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
9528c2ecf20Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
9538c2ecf20Sopenharmony_ci		break;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
9568c2ecf20Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
9578c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
9588c2ecf20Sopenharmony_ci		break;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	case IOCPF_E_STOP:
9618c2ecf20Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
9628c2ecf20Sopenharmony_ci		bfa_ioc_firmware_unlock(ioc);
9638c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
9648c2ecf20Sopenharmony_ci		break;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	case IOCPF_E_FAIL:
9678c2ecf20Sopenharmony_ci		break;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	default:
9708c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
9718c2ecf20Sopenharmony_ci	}
9728c2ecf20Sopenharmony_ci}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_cistatic void
9758c2ecf20Sopenharmony_cibfa_iocpf_sm_initfail_entry(struct bfa_iocpf *iocpf)
9768c2ecf20Sopenharmony_ci{
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci/* Hardware initialization failed. */
9808c2ecf20Sopenharmony_cistatic void
9818c2ecf20Sopenharmony_cibfa_iocpf_sm_initfail(struct bfa_iocpf *iocpf, enum iocpf_event event)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	switch (event) {
9868c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
9878c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
9888c2ecf20Sopenharmony_ci		break;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	case IOCPF_E_STOP:
9918c2ecf20Sopenharmony_ci		bfa_ioc_firmware_unlock(ioc);
9928c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);
9938c2ecf20Sopenharmony_ci		break;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	default:
9968c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
9978c2ecf20Sopenharmony_ci	}
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_cistatic void
10018c2ecf20Sopenharmony_cibfa_iocpf_sm_fail_sync_entry(struct bfa_iocpf *iocpf)
10028c2ecf20Sopenharmony_ci{
10038c2ecf20Sopenharmony_ci	/**
10048c2ecf20Sopenharmony_ci	 * Mark IOC as failed in hardware and stop firmware.
10058c2ecf20Sopenharmony_ci	 */
10068c2ecf20Sopenharmony_ci	bfa_ioc_lpu_stop(iocpf->ioc);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/**
10098c2ecf20Sopenharmony_ci	 * Flush any queued up mailbox requests.
10108c2ecf20Sopenharmony_ci	 */
10118c2ecf20Sopenharmony_ci	bfa_ioc_mbox_flush(iocpf->ioc);
10128c2ecf20Sopenharmony_ci	bfa_ioc_hw_sem_get(iocpf->ioc);
10138c2ecf20Sopenharmony_ci}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci/* IOC is in failed state. */
10168c2ecf20Sopenharmony_cistatic void
10178c2ecf20Sopenharmony_cibfa_iocpf_sm_fail_sync(struct bfa_iocpf *iocpf, enum iocpf_event event)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	struct bfa_ioc *ioc = iocpf->ioc;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	switch (event) {
10228c2ecf20Sopenharmony_ci	case IOCPF_E_SEMLOCKED:
10238c2ecf20Sopenharmony_ci		bfa_ioc_sync_ack(ioc);
10248c2ecf20Sopenharmony_ci		bfa_ioc_notify_fail(ioc);
10258c2ecf20Sopenharmony_ci		if (!iocpf->auto_recover) {
10268c2ecf20Sopenharmony_ci			bfa_ioc_sync_leave(ioc);
10278c2ecf20Sopenharmony_ci			bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);
10288c2ecf20Sopenharmony_ci			bfa_nw_ioc_hw_sem_release(ioc);
10298c2ecf20Sopenharmony_ci			bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
10308c2ecf20Sopenharmony_ci		} else {
10318c2ecf20Sopenharmony_ci			if (bfa_ioc_sync_complete(ioc))
10328c2ecf20Sopenharmony_ci				bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);
10338c2ecf20Sopenharmony_ci			else {
10348c2ecf20Sopenharmony_ci				bfa_nw_ioc_hw_sem_release(ioc);
10358c2ecf20Sopenharmony_ci				bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);
10368c2ecf20Sopenharmony_ci			}
10378c2ecf20Sopenharmony_ci		}
10388c2ecf20Sopenharmony_ci		break;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	case IOCPF_E_SEM_ERROR:
10418c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);
10428c2ecf20Sopenharmony_ci		bfa_ioc_pf_hwfailed(ioc);
10438c2ecf20Sopenharmony_ci		break;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
10468c2ecf20Sopenharmony_ci		bfa_ioc_hw_sem_get_cancel(ioc);
10478c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);
10488c2ecf20Sopenharmony_ci		break;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	case IOCPF_E_FAIL:
10518c2ecf20Sopenharmony_ci		break;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	default:
10548c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_cistatic void
10598c2ecf20Sopenharmony_cibfa_iocpf_sm_fail_entry(struct bfa_iocpf *iocpf)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci/* IOC is in failed state. */
10648c2ecf20Sopenharmony_cistatic void
10658c2ecf20Sopenharmony_cibfa_iocpf_sm_fail(struct bfa_iocpf *iocpf, enum iocpf_event event)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	switch (event) {
10688c2ecf20Sopenharmony_ci	case IOCPF_E_DISABLE:
10698c2ecf20Sopenharmony_ci		bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);
10708c2ecf20Sopenharmony_ci		break;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	default:
10738c2ecf20Sopenharmony_ci		bfa_sm_fault(event);
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci/* BFA IOC private functions */
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci/* Notify common modules registered for notification. */
10808c2ecf20Sopenharmony_cistatic void
10818c2ecf20Sopenharmony_cibfa_ioc_event_notify(struct bfa_ioc *ioc, enum bfa_ioc_event event)
10828c2ecf20Sopenharmony_ci{
10838c2ecf20Sopenharmony_ci	struct bfa_ioc_notify *notify;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	list_for_each_entry(notify, &ioc->notify_q, qe)
10868c2ecf20Sopenharmony_ci		notify->cbfn(notify->cbarg, event);
10878c2ecf20Sopenharmony_ci}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_cistatic void
10908c2ecf20Sopenharmony_cibfa_ioc_disable_comp(struct bfa_ioc *ioc)
10918c2ecf20Sopenharmony_ci{
10928c2ecf20Sopenharmony_ci	ioc->cbfn->disable_cbfn(ioc->bfa);
10938c2ecf20Sopenharmony_ci	bfa_ioc_event_notify(ioc, BFA_IOC_E_DISABLED);
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cibool
10978c2ecf20Sopenharmony_cibfa_nw_ioc_sem_get(void __iomem *sem_reg)
10988c2ecf20Sopenharmony_ci{
10998c2ecf20Sopenharmony_ci	u32 r32;
11008c2ecf20Sopenharmony_ci	int cnt = 0;
11018c2ecf20Sopenharmony_ci#define BFA_SEM_SPINCNT	3000
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	r32 = readl(sem_reg);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	while ((r32 & 1) && (cnt < BFA_SEM_SPINCNT)) {
11068c2ecf20Sopenharmony_ci		cnt++;
11078c2ecf20Sopenharmony_ci		udelay(2);
11088c2ecf20Sopenharmony_ci		r32 = readl(sem_reg);
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	if (!(r32 & 1))
11128c2ecf20Sopenharmony_ci		return true;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	return false;
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_civoid
11188c2ecf20Sopenharmony_cibfa_nw_ioc_sem_release(void __iomem *sem_reg)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	readl(sem_reg);
11218c2ecf20Sopenharmony_ci	writel(1, sem_reg);
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci/* Clear fwver hdr */
11258c2ecf20Sopenharmony_cistatic void
11268c2ecf20Sopenharmony_cibfa_ioc_fwver_clear(struct bfa_ioc *ioc)
11278c2ecf20Sopenharmony_ci{
11288c2ecf20Sopenharmony_ci	u32 pgnum, loff = 0;
11298c2ecf20Sopenharmony_ci	int i;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);
11328c2ecf20Sopenharmony_ci	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32)); i++) {
11358c2ecf20Sopenharmony_ci		writel(0, ioc->ioc_regs.smem_page_start + loff);
11368c2ecf20Sopenharmony_ci		loff += sizeof(u32);
11378c2ecf20Sopenharmony_ci	}
11388c2ecf20Sopenharmony_ci}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_cistatic void
11428c2ecf20Sopenharmony_cibfa_ioc_hw_sem_init(struct bfa_ioc *ioc)
11438c2ecf20Sopenharmony_ci{
11448c2ecf20Sopenharmony_ci	struct bfi_ioc_image_hdr fwhdr;
11458c2ecf20Sopenharmony_ci	u32 fwstate, r32;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	/* Spin on init semaphore to serialize. */
11488c2ecf20Sopenharmony_ci	r32 = readl(ioc->ioc_regs.ioc_init_sem_reg);
11498c2ecf20Sopenharmony_ci	while (r32 & 0x1) {
11508c2ecf20Sopenharmony_ci		udelay(20);
11518c2ecf20Sopenharmony_ci		r32 = readl(ioc->ioc_regs.ioc_init_sem_reg);
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
11558c2ecf20Sopenharmony_ci	if (fwstate == BFI_IOC_UNINIT) {
11568c2ecf20Sopenharmony_ci		writel(1, ioc->ioc_regs.ioc_init_sem_reg);
11578c2ecf20Sopenharmony_ci		return;
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	bfa_nw_ioc_fwver_get(ioc, &fwhdr);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL) {
11638c2ecf20Sopenharmony_ci		writel(1, ioc->ioc_regs.ioc_init_sem_reg);
11648c2ecf20Sopenharmony_ci		return;
11658c2ecf20Sopenharmony_ci	}
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	bfa_ioc_fwver_clear(ioc);
11688c2ecf20Sopenharmony_ci	bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_UNINIT);
11698c2ecf20Sopenharmony_ci	bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_UNINIT);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	/*
11728c2ecf20Sopenharmony_ci	 * Try to lock and then unlock the semaphore.
11738c2ecf20Sopenharmony_ci	 */
11748c2ecf20Sopenharmony_ci	readl(ioc->ioc_regs.ioc_sem_reg);
11758c2ecf20Sopenharmony_ci	writel(1, ioc->ioc_regs.ioc_sem_reg);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	/* Unlock init semaphore */
11788c2ecf20Sopenharmony_ci	writel(1, ioc->ioc_regs.ioc_init_sem_reg);
11798c2ecf20Sopenharmony_ci}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_cistatic void
11828c2ecf20Sopenharmony_cibfa_ioc_hw_sem_get(struct bfa_ioc *ioc)
11838c2ecf20Sopenharmony_ci{
11848c2ecf20Sopenharmony_ci	u32	r32;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	/**
11878c2ecf20Sopenharmony_ci	 * First read to the semaphore register will return 0, subsequent reads
11888c2ecf20Sopenharmony_ci	 * will return 1. Semaphore is released by writing 1 to the register
11898c2ecf20Sopenharmony_ci	 */
11908c2ecf20Sopenharmony_ci	r32 = readl(ioc->ioc_regs.ioc_sem_reg);
11918c2ecf20Sopenharmony_ci	if (r32 == ~0) {
11928c2ecf20Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEM_ERROR);
11938c2ecf20Sopenharmony_ci		return;
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci	if (!(r32 & 1)) {
11968c2ecf20Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED);
11978c2ecf20Sopenharmony_ci		return;
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	mod_timer(&ioc->sem_timer, jiffies +
12018c2ecf20Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_HWSEM_TOV));
12028c2ecf20Sopenharmony_ci}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_civoid
12058c2ecf20Sopenharmony_cibfa_nw_ioc_hw_sem_release(struct bfa_ioc *ioc)
12068c2ecf20Sopenharmony_ci{
12078c2ecf20Sopenharmony_ci	writel(1, ioc->ioc_regs.ioc_sem_reg);
12088c2ecf20Sopenharmony_ci}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_cistatic void
12118c2ecf20Sopenharmony_cibfa_ioc_hw_sem_get_cancel(struct bfa_ioc *ioc)
12128c2ecf20Sopenharmony_ci{
12138c2ecf20Sopenharmony_ci	del_timer(&ioc->sem_timer);
12148c2ecf20Sopenharmony_ci}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci/* Initialize LPU local memory (aka secondary memory / SRAM) */
12178c2ecf20Sopenharmony_cistatic void
12188c2ecf20Sopenharmony_cibfa_ioc_lmem_init(struct bfa_ioc *ioc)
12198c2ecf20Sopenharmony_ci{
12208c2ecf20Sopenharmony_ci	u32	pss_ctl;
12218c2ecf20Sopenharmony_ci	int		i;
12228c2ecf20Sopenharmony_ci#define PSS_LMEM_INIT_TIME  10000
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
12258c2ecf20Sopenharmony_ci	pss_ctl &= ~__PSS_LMEM_RESET;
12268c2ecf20Sopenharmony_ci	pss_ctl |= __PSS_LMEM_INIT_EN;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	/*
12298c2ecf20Sopenharmony_ci	 * i2c workaround 12.5khz clock
12308c2ecf20Sopenharmony_ci	 */
12318c2ecf20Sopenharmony_ci	pss_ctl |= __PSS_I2C_CLK_DIV(3UL);
12328c2ecf20Sopenharmony_ci	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	/**
12358c2ecf20Sopenharmony_ci	 * wait for memory initialization to be complete
12368c2ecf20Sopenharmony_ci	 */
12378c2ecf20Sopenharmony_ci	i = 0;
12388c2ecf20Sopenharmony_ci	do {
12398c2ecf20Sopenharmony_ci		pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
12408c2ecf20Sopenharmony_ci		i++;
12418c2ecf20Sopenharmony_ci	} while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	/**
12448c2ecf20Sopenharmony_ci	 * If memory initialization is not successful, IOC timeout will catch
12458c2ecf20Sopenharmony_ci	 * such failures.
12468c2ecf20Sopenharmony_ci	 */
12478c2ecf20Sopenharmony_ci	BUG_ON(!(pss_ctl & __PSS_LMEM_INIT_DONE));
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
12508c2ecf20Sopenharmony_ci	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
12518c2ecf20Sopenharmony_ci}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_cistatic void
12548c2ecf20Sopenharmony_cibfa_ioc_lpu_start(struct bfa_ioc *ioc)
12558c2ecf20Sopenharmony_ci{
12568c2ecf20Sopenharmony_ci	u32	pss_ctl;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	/**
12598c2ecf20Sopenharmony_ci	 * Take processor out of reset.
12608c2ecf20Sopenharmony_ci	 */
12618c2ecf20Sopenharmony_ci	pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
12628c2ecf20Sopenharmony_ci	pss_ctl &= ~__PSS_LPU0_RESET;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_cistatic void
12688c2ecf20Sopenharmony_cibfa_ioc_lpu_stop(struct bfa_ioc *ioc)
12698c2ecf20Sopenharmony_ci{
12708c2ecf20Sopenharmony_ci	u32	pss_ctl;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	/**
12738c2ecf20Sopenharmony_ci	 * Put processors in reset.
12748c2ecf20Sopenharmony_ci	 */
12758c2ecf20Sopenharmony_ci	pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);
12768c2ecf20Sopenharmony_ci	pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);
12798c2ecf20Sopenharmony_ci}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci/* Get driver and firmware versions. */
12828c2ecf20Sopenharmony_civoid
12838c2ecf20Sopenharmony_cibfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
12848c2ecf20Sopenharmony_ci{
12858c2ecf20Sopenharmony_ci	u32	pgnum;
12868c2ecf20Sopenharmony_ci	u32	loff = 0;
12878c2ecf20Sopenharmony_ci	int		i;
12888c2ecf20Sopenharmony_ci	u32	*fwsig = (u32 *) fwhdr;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	pgnum = bfa_ioc_smem_pgnum(ioc, loff);
12918c2ecf20Sopenharmony_ci	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32));
12948c2ecf20Sopenharmony_ci	     i++) {
12958c2ecf20Sopenharmony_ci		fwsig[i] =
12968c2ecf20Sopenharmony_ci			swab32(readl(loff + ioc->ioc_regs.smem_page_start));
12978c2ecf20Sopenharmony_ci		loff += sizeof(u32);
12988c2ecf20Sopenharmony_ci	}
12998c2ecf20Sopenharmony_ci}
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_cistatic bool
13028c2ecf20Sopenharmony_cibfa_ioc_fwver_md5_check(struct bfi_ioc_image_hdr *fwhdr_1,
13038c2ecf20Sopenharmony_ci			struct bfi_ioc_image_hdr *fwhdr_2)
13048c2ecf20Sopenharmony_ci{
13058c2ecf20Sopenharmony_ci	int i;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
13088c2ecf20Sopenharmony_ci		if (fwhdr_1->md5sum[i] != fwhdr_2->md5sum[i])
13098c2ecf20Sopenharmony_ci			return false;
13108c2ecf20Sopenharmony_ci	}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	return true;
13138c2ecf20Sopenharmony_ci}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci/* Returns TRUE if major minor and maintenance are same.
13168c2ecf20Sopenharmony_ci * If patch version are same, check for MD5 Checksum to be same.
13178c2ecf20Sopenharmony_ci */
13188c2ecf20Sopenharmony_cistatic bool
13198c2ecf20Sopenharmony_cibfa_ioc_fw_ver_compatible(struct bfi_ioc_image_hdr *drv_fwhdr,
13208c2ecf20Sopenharmony_ci			  struct bfi_ioc_image_hdr *fwhdr_to_cmp)
13218c2ecf20Sopenharmony_ci{
13228c2ecf20Sopenharmony_ci	if (drv_fwhdr->signature != fwhdr_to_cmp->signature)
13238c2ecf20Sopenharmony_ci		return false;
13248c2ecf20Sopenharmony_ci	if (drv_fwhdr->fwver.major != fwhdr_to_cmp->fwver.major)
13258c2ecf20Sopenharmony_ci		return false;
13268c2ecf20Sopenharmony_ci	if (drv_fwhdr->fwver.minor != fwhdr_to_cmp->fwver.minor)
13278c2ecf20Sopenharmony_ci		return false;
13288c2ecf20Sopenharmony_ci	if (drv_fwhdr->fwver.maint != fwhdr_to_cmp->fwver.maint)
13298c2ecf20Sopenharmony_ci		return false;
13308c2ecf20Sopenharmony_ci	if (drv_fwhdr->fwver.patch == fwhdr_to_cmp->fwver.patch &&
13318c2ecf20Sopenharmony_ci	    drv_fwhdr->fwver.phase == fwhdr_to_cmp->fwver.phase &&
13328c2ecf20Sopenharmony_ci	    drv_fwhdr->fwver.build == fwhdr_to_cmp->fwver.build)
13338c2ecf20Sopenharmony_ci		return bfa_ioc_fwver_md5_check(drv_fwhdr, fwhdr_to_cmp);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	return true;
13368c2ecf20Sopenharmony_ci}
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_cistatic bool
13398c2ecf20Sopenharmony_cibfa_ioc_flash_fwver_valid(struct bfi_ioc_image_hdr *flash_fwhdr)
13408c2ecf20Sopenharmony_ci{
13418c2ecf20Sopenharmony_ci	if (flash_fwhdr->fwver.major == 0 || flash_fwhdr->fwver.major == 0xFF)
13428c2ecf20Sopenharmony_ci		return false;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	return true;
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_cistatic bool
13488c2ecf20Sopenharmony_cifwhdr_is_ga(struct bfi_ioc_image_hdr *fwhdr)
13498c2ecf20Sopenharmony_ci{
13508c2ecf20Sopenharmony_ci	if (fwhdr->fwver.phase == 0 &&
13518c2ecf20Sopenharmony_ci	    fwhdr->fwver.build == 0)
13528c2ecf20Sopenharmony_ci		return false;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	return true;
13558c2ecf20Sopenharmony_ci}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci/* Returns TRUE if both are compatible and patch of fwhdr_to_cmp is better. */
13588c2ecf20Sopenharmony_cistatic enum bfi_ioc_img_ver_cmp
13598c2ecf20Sopenharmony_cibfa_ioc_fw_ver_patch_cmp(struct bfi_ioc_image_hdr *base_fwhdr,
13608c2ecf20Sopenharmony_ci			 struct bfi_ioc_image_hdr *fwhdr_to_cmp)
13618c2ecf20Sopenharmony_ci{
13628c2ecf20Sopenharmony_ci	if (!bfa_ioc_fw_ver_compatible(base_fwhdr, fwhdr_to_cmp))
13638c2ecf20Sopenharmony_ci		return BFI_IOC_IMG_VER_INCOMP;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	if (fwhdr_to_cmp->fwver.patch > base_fwhdr->fwver.patch)
13668c2ecf20Sopenharmony_ci		return BFI_IOC_IMG_VER_BETTER;
13678c2ecf20Sopenharmony_ci	else if (fwhdr_to_cmp->fwver.patch < base_fwhdr->fwver.patch)
13688c2ecf20Sopenharmony_ci		return BFI_IOC_IMG_VER_OLD;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	/* GA takes priority over internal builds of the same patch stream.
13718c2ecf20Sopenharmony_ci	 * At this point major minor maint and patch numbers are same.
13728c2ecf20Sopenharmony_ci	 */
13738c2ecf20Sopenharmony_ci	if (fwhdr_is_ga(base_fwhdr))
13748c2ecf20Sopenharmony_ci		if (fwhdr_is_ga(fwhdr_to_cmp))
13758c2ecf20Sopenharmony_ci			return BFI_IOC_IMG_VER_SAME;
13768c2ecf20Sopenharmony_ci		else
13778c2ecf20Sopenharmony_ci			return BFI_IOC_IMG_VER_OLD;
13788c2ecf20Sopenharmony_ci	else
13798c2ecf20Sopenharmony_ci		if (fwhdr_is_ga(fwhdr_to_cmp))
13808c2ecf20Sopenharmony_ci			return BFI_IOC_IMG_VER_BETTER;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	if (fwhdr_to_cmp->fwver.phase > base_fwhdr->fwver.phase)
13838c2ecf20Sopenharmony_ci		return BFI_IOC_IMG_VER_BETTER;
13848c2ecf20Sopenharmony_ci	else if (fwhdr_to_cmp->fwver.phase < base_fwhdr->fwver.phase)
13858c2ecf20Sopenharmony_ci		return BFI_IOC_IMG_VER_OLD;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	if (fwhdr_to_cmp->fwver.build > base_fwhdr->fwver.build)
13888c2ecf20Sopenharmony_ci		return BFI_IOC_IMG_VER_BETTER;
13898c2ecf20Sopenharmony_ci	else if (fwhdr_to_cmp->fwver.build < base_fwhdr->fwver.build)
13908c2ecf20Sopenharmony_ci		return BFI_IOC_IMG_VER_OLD;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	/* All Version Numbers are equal.
13938c2ecf20Sopenharmony_ci	 * Md5 check to be done as a part of compatibility check.
13948c2ecf20Sopenharmony_ci	 */
13958c2ecf20Sopenharmony_ci	return BFI_IOC_IMG_VER_SAME;
13968c2ecf20Sopenharmony_ci}
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci/* register definitions */
13998c2ecf20Sopenharmony_ci#define FLI_CMD_REG			0x0001d000
14008c2ecf20Sopenharmony_ci#define FLI_WRDATA_REG			0x0001d00c
14018c2ecf20Sopenharmony_ci#define FLI_RDDATA_REG			0x0001d010
14028c2ecf20Sopenharmony_ci#define FLI_ADDR_REG			0x0001d004
14038c2ecf20Sopenharmony_ci#define FLI_DEV_STATUS_REG		0x0001d014
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci#define BFA_FLASH_FIFO_SIZE		128	/* fifo size */
14068c2ecf20Sopenharmony_ci#define BFA_FLASH_CHECK_MAX		10000	/* max # of status check */
14078c2ecf20Sopenharmony_ci#define BFA_FLASH_BLOCKING_OP_MAX	1000000	/* max # of blocking op check */
14088c2ecf20Sopenharmony_ci#define BFA_FLASH_WIP_MASK		0x01	/* write in progress bit mask */
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci#define NFC_STATE_RUNNING		0x20000001
14118c2ecf20Sopenharmony_ci#define NFC_STATE_PAUSED		0x00004560
14128c2ecf20Sopenharmony_ci#define NFC_VER_VALID			0x147
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_cienum bfa_flash_cmd {
14158c2ecf20Sopenharmony_ci	BFA_FLASH_FAST_READ	= 0x0b,	/* fast read */
14168c2ecf20Sopenharmony_ci	BFA_FLASH_WRITE_ENABLE	= 0x06,	/* write enable */
14178c2ecf20Sopenharmony_ci	BFA_FLASH_SECTOR_ERASE	= 0xd8,	/* sector erase */
14188c2ecf20Sopenharmony_ci	BFA_FLASH_WRITE		= 0x02,	/* write */
14198c2ecf20Sopenharmony_ci	BFA_FLASH_READ_STATUS	= 0x05,	/* read status */
14208c2ecf20Sopenharmony_ci};
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci/* hardware error definition */
14238c2ecf20Sopenharmony_cienum bfa_flash_err {
14248c2ecf20Sopenharmony_ci	BFA_FLASH_NOT_PRESENT	= -1,	/*!< flash not present */
14258c2ecf20Sopenharmony_ci	BFA_FLASH_UNINIT	= -2,	/*!< flash not initialized */
14268c2ecf20Sopenharmony_ci	BFA_FLASH_BAD		= -3,	/*!< flash bad */
14278c2ecf20Sopenharmony_ci	BFA_FLASH_BUSY		= -4,	/*!< flash busy */
14288c2ecf20Sopenharmony_ci	BFA_FLASH_ERR_CMD_ACT	= -5,	/*!< command active never cleared */
14298c2ecf20Sopenharmony_ci	BFA_FLASH_ERR_FIFO_CNT	= -6,	/*!< fifo count never cleared */
14308c2ecf20Sopenharmony_ci	BFA_FLASH_ERR_WIP	= -7,	/*!< write-in-progress never cleared */
14318c2ecf20Sopenharmony_ci	BFA_FLASH_ERR_TIMEOUT	= -8,	/*!< fli timeout */
14328c2ecf20Sopenharmony_ci	BFA_FLASH_ERR_LEN	= -9,	/*!< invalid length */
14338c2ecf20Sopenharmony_ci};
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci/* flash command register data structure */
14368c2ecf20Sopenharmony_ciunion bfa_flash_cmd_reg {
14378c2ecf20Sopenharmony_ci	struct {
14388c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
14398c2ecf20Sopenharmony_ci		u32	act:1;
14408c2ecf20Sopenharmony_ci		u32	rsv:1;
14418c2ecf20Sopenharmony_ci		u32	write_cnt:9;
14428c2ecf20Sopenharmony_ci		u32	read_cnt:9;
14438c2ecf20Sopenharmony_ci		u32	addr_cnt:4;
14448c2ecf20Sopenharmony_ci		u32	cmd:8;
14458c2ecf20Sopenharmony_ci#else
14468c2ecf20Sopenharmony_ci		u32	cmd:8;
14478c2ecf20Sopenharmony_ci		u32	addr_cnt:4;
14488c2ecf20Sopenharmony_ci		u32	read_cnt:9;
14498c2ecf20Sopenharmony_ci		u32	write_cnt:9;
14508c2ecf20Sopenharmony_ci		u32	rsv:1;
14518c2ecf20Sopenharmony_ci		u32	act:1;
14528c2ecf20Sopenharmony_ci#endif
14538c2ecf20Sopenharmony_ci	} r;
14548c2ecf20Sopenharmony_ci	u32	i;
14558c2ecf20Sopenharmony_ci};
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci/* flash device status register data structure */
14588c2ecf20Sopenharmony_ciunion bfa_flash_dev_status_reg {
14598c2ecf20Sopenharmony_ci	struct {
14608c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
14618c2ecf20Sopenharmony_ci		u32	rsv:21;
14628c2ecf20Sopenharmony_ci		u32	fifo_cnt:6;
14638c2ecf20Sopenharmony_ci		u32	busy:1;
14648c2ecf20Sopenharmony_ci		u32	init_status:1;
14658c2ecf20Sopenharmony_ci		u32	present:1;
14668c2ecf20Sopenharmony_ci		u32	bad:1;
14678c2ecf20Sopenharmony_ci		u32	good:1;
14688c2ecf20Sopenharmony_ci#else
14698c2ecf20Sopenharmony_ci		u32	good:1;
14708c2ecf20Sopenharmony_ci		u32	bad:1;
14718c2ecf20Sopenharmony_ci		u32	present:1;
14728c2ecf20Sopenharmony_ci		u32	init_status:1;
14738c2ecf20Sopenharmony_ci		u32	busy:1;
14748c2ecf20Sopenharmony_ci		u32	fifo_cnt:6;
14758c2ecf20Sopenharmony_ci		u32	rsv:21;
14768c2ecf20Sopenharmony_ci#endif
14778c2ecf20Sopenharmony_ci	} r;
14788c2ecf20Sopenharmony_ci	u32	i;
14798c2ecf20Sopenharmony_ci};
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci/* flash address register data structure */
14828c2ecf20Sopenharmony_ciunion bfa_flash_addr_reg {
14838c2ecf20Sopenharmony_ci	struct {
14848c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
14858c2ecf20Sopenharmony_ci		u32	addr:24;
14868c2ecf20Sopenharmony_ci		u32	dummy:8;
14878c2ecf20Sopenharmony_ci#else
14888c2ecf20Sopenharmony_ci		u32	dummy:8;
14898c2ecf20Sopenharmony_ci		u32	addr:24;
14908c2ecf20Sopenharmony_ci#endif
14918c2ecf20Sopenharmony_ci	} r;
14928c2ecf20Sopenharmony_ci	u32	i;
14938c2ecf20Sopenharmony_ci};
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci/* Flash raw private functions */
14968c2ecf20Sopenharmony_cistatic void
14978c2ecf20Sopenharmony_cibfa_flash_set_cmd(void __iomem *pci_bar, u8 wr_cnt,
14988c2ecf20Sopenharmony_ci		  u8 rd_cnt, u8 ad_cnt, u8 op)
14998c2ecf20Sopenharmony_ci{
15008c2ecf20Sopenharmony_ci	union bfa_flash_cmd_reg cmd;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	cmd.i = 0;
15038c2ecf20Sopenharmony_ci	cmd.r.act = 1;
15048c2ecf20Sopenharmony_ci	cmd.r.write_cnt = wr_cnt;
15058c2ecf20Sopenharmony_ci	cmd.r.read_cnt = rd_cnt;
15068c2ecf20Sopenharmony_ci	cmd.r.addr_cnt = ad_cnt;
15078c2ecf20Sopenharmony_ci	cmd.r.cmd = op;
15088c2ecf20Sopenharmony_ci	writel(cmd.i, (pci_bar + FLI_CMD_REG));
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_cistatic void
15128c2ecf20Sopenharmony_cibfa_flash_set_addr(void __iomem *pci_bar, u32 address)
15138c2ecf20Sopenharmony_ci{
15148c2ecf20Sopenharmony_ci	union bfa_flash_addr_reg addr;
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	addr.r.addr = address & 0x00ffffff;
15178c2ecf20Sopenharmony_ci	addr.r.dummy = 0;
15188c2ecf20Sopenharmony_ci	writel(addr.i, (pci_bar + FLI_ADDR_REG));
15198c2ecf20Sopenharmony_ci}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_cistatic int
15228c2ecf20Sopenharmony_cibfa_flash_cmd_act_check(void __iomem *pci_bar)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	union bfa_flash_cmd_reg cmd;
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	cmd.i = readl(pci_bar + FLI_CMD_REG);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	if (cmd.r.act)
15298c2ecf20Sopenharmony_ci		return BFA_FLASH_ERR_CMD_ACT;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	return 0;
15328c2ecf20Sopenharmony_ci}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci/* Flush FLI data fifo. */
15358c2ecf20Sopenharmony_cistatic int
15368c2ecf20Sopenharmony_cibfa_flash_fifo_flush(void __iomem *pci_bar)
15378c2ecf20Sopenharmony_ci{
15388c2ecf20Sopenharmony_ci	u32 i;
15398c2ecf20Sopenharmony_ci	union bfa_flash_dev_status_reg dev_status;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	if (!dev_status.r.fifo_cnt)
15448c2ecf20Sopenharmony_ci		return 0;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	/* fifo counter in terms of words */
15478c2ecf20Sopenharmony_ci	for (i = 0; i < dev_status.r.fifo_cnt; i++)
15488c2ecf20Sopenharmony_ci		readl(pci_bar + FLI_RDDATA_REG);
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	/* Check the device status. It may take some time. */
15518c2ecf20Sopenharmony_ci	for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) {
15528c2ecf20Sopenharmony_ci		dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);
15538c2ecf20Sopenharmony_ci		if (!dev_status.r.fifo_cnt)
15548c2ecf20Sopenharmony_ci			break;
15558c2ecf20Sopenharmony_ci	}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	if (dev_status.r.fifo_cnt)
15588c2ecf20Sopenharmony_ci		return BFA_FLASH_ERR_FIFO_CNT;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	return 0;
15618c2ecf20Sopenharmony_ci}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci/* Read flash status. */
15648c2ecf20Sopenharmony_cistatic int
15658c2ecf20Sopenharmony_cibfa_flash_status_read(void __iomem *pci_bar)
15668c2ecf20Sopenharmony_ci{
15678c2ecf20Sopenharmony_ci	union bfa_flash_dev_status_reg	dev_status;
15688c2ecf20Sopenharmony_ci	int				status;
15698c2ecf20Sopenharmony_ci	u32			ret_status;
15708c2ecf20Sopenharmony_ci	int				i;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	status = bfa_flash_fifo_flush(pci_bar);
15738c2ecf20Sopenharmony_ci	if (status < 0)
15748c2ecf20Sopenharmony_ci		return status;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	bfa_flash_set_cmd(pci_bar, 0, 4, 0, BFA_FLASH_READ_STATUS);
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) {
15798c2ecf20Sopenharmony_ci		status = bfa_flash_cmd_act_check(pci_bar);
15808c2ecf20Sopenharmony_ci		if (!status)
15818c2ecf20Sopenharmony_ci			break;
15828c2ecf20Sopenharmony_ci	}
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	if (status)
15858c2ecf20Sopenharmony_ci		return status;
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);
15888c2ecf20Sopenharmony_ci	if (!dev_status.r.fifo_cnt)
15898c2ecf20Sopenharmony_ci		return BFA_FLASH_BUSY;
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	ret_status = readl(pci_bar + FLI_RDDATA_REG);
15928c2ecf20Sopenharmony_ci	ret_status >>= 24;
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	status = bfa_flash_fifo_flush(pci_bar);
15958c2ecf20Sopenharmony_ci	if (status < 0)
15968c2ecf20Sopenharmony_ci		return status;
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	return ret_status;
15998c2ecf20Sopenharmony_ci}
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci/* Start flash read operation. */
16028c2ecf20Sopenharmony_cistatic int
16038c2ecf20Sopenharmony_cibfa_flash_read_start(void __iomem *pci_bar, u32 offset, u32 len,
16048c2ecf20Sopenharmony_ci		     char *buf)
16058c2ecf20Sopenharmony_ci{
16068c2ecf20Sopenharmony_ci	int status;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	/* len must be mutiple of 4 and not exceeding fifo size */
16098c2ecf20Sopenharmony_ci	if (len == 0 || len > BFA_FLASH_FIFO_SIZE || (len & 0x03) != 0)
16108c2ecf20Sopenharmony_ci		return BFA_FLASH_ERR_LEN;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	/* check status */
16138c2ecf20Sopenharmony_ci	status = bfa_flash_status_read(pci_bar);
16148c2ecf20Sopenharmony_ci	if (status == BFA_FLASH_BUSY)
16158c2ecf20Sopenharmony_ci		status = bfa_flash_status_read(pci_bar);
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	if (status < 0)
16188c2ecf20Sopenharmony_ci		return status;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	/* check if write-in-progress bit is cleared */
16218c2ecf20Sopenharmony_ci	if (status & BFA_FLASH_WIP_MASK)
16228c2ecf20Sopenharmony_ci		return BFA_FLASH_ERR_WIP;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	bfa_flash_set_addr(pci_bar, offset);
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	bfa_flash_set_cmd(pci_bar, 0, (u8)len, 4, BFA_FLASH_FAST_READ);
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	return 0;
16298c2ecf20Sopenharmony_ci}
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci/* Check flash read operation. */
16328c2ecf20Sopenharmony_cistatic u32
16338c2ecf20Sopenharmony_cibfa_flash_read_check(void __iomem *pci_bar)
16348c2ecf20Sopenharmony_ci{
16358c2ecf20Sopenharmony_ci	if (bfa_flash_cmd_act_check(pci_bar))
16368c2ecf20Sopenharmony_ci		return 1;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	return 0;
16398c2ecf20Sopenharmony_ci}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci/* End flash read operation. */
16428c2ecf20Sopenharmony_cistatic void
16438c2ecf20Sopenharmony_cibfa_flash_read_end(void __iomem *pci_bar, u32 len, char *buf)
16448c2ecf20Sopenharmony_ci{
16458c2ecf20Sopenharmony_ci	u32 i;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	/* read data fifo up to 32 words */
16488c2ecf20Sopenharmony_ci	for (i = 0; i < len; i += 4) {
16498c2ecf20Sopenharmony_ci		u32 w = readl(pci_bar + FLI_RDDATA_REG);
16508c2ecf20Sopenharmony_ci		*((u32 *)(buf + i)) = swab32(w);
16518c2ecf20Sopenharmony_ci	}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	bfa_flash_fifo_flush(pci_bar);
16548c2ecf20Sopenharmony_ci}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci/* Perform flash raw read. */
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci#define FLASH_BLOCKING_OP_MAX   500
16598c2ecf20Sopenharmony_ci#define FLASH_SEM_LOCK_REG	0x18820
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_cistatic int
16628c2ecf20Sopenharmony_cibfa_raw_sem_get(void __iomem *bar)
16638c2ecf20Sopenharmony_ci{
16648c2ecf20Sopenharmony_ci	int	locked;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	locked = readl(bar + FLASH_SEM_LOCK_REG);
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	return !locked;
16698c2ecf20Sopenharmony_ci}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_cistatic enum bfa_status
16728c2ecf20Sopenharmony_cibfa_flash_sem_get(void __iomem *bar)
16738c2ecf20Sopenharmony_ci{
16748c2ecf20Sopenharmony_ci	u32 n = FLASH_BLOCKING_OP_MAX;
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	while (!bfa_raw_sem_get(bar)) {
16778c2ecf20Sopenharmony_ci		if (--n <= 0)
16788c2ecf20Sopenharmony_ci			return BFA_STATUS_BADFLASH;
16798c2ecf20Sopenharmony_ci		mdelay(10);
16808c2ecf20Sopenharmony_ci	}
16818c2ecf20Sopenharmony_ci	return BFA_STATUS_OK;
16828c2ecf20Sopenharmony_ci}
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_cistatic void
16858c2ecf20Sopenharmony_cibfa_flash_sem_put(void __iomem *bar)
16868c2ecf20Sopenharmony_ci{
16878c2ecf20Sopenharmony_ci	writel(0, (bar + FLASH_SEM_LOCK_REG));
16888c2ecf20Sopenharmony_ci}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_cistatic enum bfa_status
16918c2ecf20Sopenharmony_cibfa_flash_raw_read(void __iomem *pci_bar, u32 offset, char *buf,
16928c2ecf20Sopenharmony_ci		   u32 len)
16938c2ecf20Sopenharmony_ci{
16948c2ecf20Sopenharmony_ci	u32 n;
16958c2ecf20Sopenharmony_ci	int status;
16968c2ecf20Sopenharmony_ci	u32 off, l, s, residue, fifo_sz;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	residue = len;
16998c2ecf20Sopenharmony_ci	off = 0;
17008c2ecf20Sopenharmony_ci	fifo_sz = BFA_FLASH_FIFO_SIZE;
17018c2ecf20Sopenharmony_ci	status = bfa_flash_sem_get(pci_bar);
17028c2ecf20Sopenharmony_ci	if (status != BFA_STATUS_OK)
17038c2ecf20Sopenharmony_ci		return status;
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	while (residue) {
17068c2ecf20Sopenharmony_ci		s = offset + off;
17078c2ecf20Sopenharmony_ci		n = s / fifo_sz;
17088c2ecf20Sopenharmony_ci		l = (n + 1) * fifo_sz - s;
17098c2ecf20Sopenharmony_ci		if (l > residue)
17108c2ecf20Sopenharmony_ci			l = residue;
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci		status = bfa_flash_read_start(pci_bar, offset + off, l,
17138c2ecf20Sopenharmony_ci								&buf[off]);
17148c2ecf20Sopenharmony_ci		if (status < 0) {
17158c2ecf20Sopenharmony_ci			bfa_flash_sem_put(pci_bar);
17168c2ecf20Sopenharmony_ci			return BFA_STATUS_FAILED;
17178c2ecf20Sopenharmony_ci		}
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci		n = BFA_FLASH_BLOCKING_OP_MAX;
17208c2ecf20Sopenharmony_ci		while (bfa_flash_read_check(pci_bar)) {
17218c2ecf20Sopenharmony_ci			if (--n <= 0) {
17228c2ecf20Sopenharmony_ci				bfa_flash_sem_put(pci_bar);
17238c2ecf20Sopenharmony_ci				return BFA_STATUS_FAILED;
17248c2ecf20Sopenharmony_ci			}
17258c2ecf20Sopenharmony_ci		}
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci		bfa_flash_read_end(pci_bar, l, &buf[off]);
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci		residue -= l;
17308c2ecf20Sopenharmony_ci		off += l;
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci	bfa_flash_sem_put(pci_bar);
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	return BFA_STATUS_OK;
17358c2ecf20Sopenharmony_ci}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci#define BFA_FLASH_PART_FWIMG_ADDR	0x100000 /* fw image address */
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_cistatic enum bfa_status
17408c2ecf20Sopenharmony_cibfa_nw_ioc_flash_img_get_chnk(struct bfa_ioc *ioc, u32 off,
17418c2ecf20Sopenharmony_ci			      u32 *fwimg)
17428c2ecf20Sopenharmony_ci{
17438c2ecf20Sopenharmony_ci	return bfa_flash_raw_read(ioc->pcidev.pci_bar_kva,
17448c2ecf20Sopenharmony_ci			BFA_FLASH_PART_FWIMG_ADDR + (off * sizeof(u32)),
17458c2ecf20Sopenharmony_ci			(char *)fwimg, BFI_FLASH_CHUNK_SZ);
17468c2ecf20Sopenharmony_ci}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_cistatic enum bfi_ioc_img_ver_cmp
17498c2ecf20Sopenharmony_cibfa_ioc_flash_fwver_cmp(struct bfa_ioc *ioc,
17508c2ecf20Sopenharmony_ci			struct bfi_ioc_image_hdr *base_fwhdr)
17518c2ecf20Sopenharmony_ci{
17528c2ecf20Sopenharmony_ci	struct bfi_ioc_image_hdr *flash_fwhdr;
17538c2ecf20Sopenharmony_ci	enum bfa_status status;
17548c2ecf20Sopenharmony_ci	u32 fwimg[BFI_FLASH_CHUNK_SZ_WORDS];
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	status = bfa_nw_ioc_flash_img_get_chnk(ioc, 0, fwimg);
17578c2ecf20Sopenharmony_ci	if (status != BFA_STATUS_OK)
17588c2ecf20Sopenharmony_ci		return BFI_IOC_IMG_VER_INCOMP;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	flash_fwhdr = (struct bfi_ioc_image_hdr *)fwimg;
17618c2ecf20Sopenharmony_ci	if (bfa_ioc_flash_fwver_valid(flash_fwhdr))
17628c2ecf20Sopenharmony_ci		return bfa_ioc_fw_ver_patch_cmp(base_fwhdr, flash_fwhdr);
17638c2ecf20Sopenharmony_ci	else
17648c2ecf20Sopenharmony_ci		return BFI_IOC_IMG_VER_INCOMP;
17658c2ecf20Sopenharmony_ci}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci/*
17688c2ecf20Sopenharmony_ci * Returns TRUE if driver is willing to work with current smem f/w version.
17698c2ecf20Sopenharmony_ci */
17708c2ecf20Sopenharmony_cibool
17718c2ecf20Sopenharmony_cibfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
17728c2ecf20Sopenharmony_ci{
17738c2ecf20Sopenharmony_ci	struct bfi_ioc_image_hdr *drv_fwhdr;
17748c2ecf20Sopenharmony_ci	enum bfi_ioc_img_ver_cmp smem_flash_cmp, drv_smem_cmp;
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	drv_fwhdr = (struct bfi_ioc_image_hdr *)
17778c2ecf20Sopenharmony_ci		bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	/* If smem is incompatible or old, driver should not work with it. */
17808c2ecf20Sopenharmony_ci	drv_smem_cmp = bfa_ioc_fw_ver_patch_cmp(drv_fwhdr, fwhdr);
17818c2ecf20Sopenharmony_ci	if (drv_smem_cmp == BFI_IOC_IMG_VER_INCOMP ||
17828c2ecf20Sopenharmony_ci	    drv_smem_cmp == BFI_IOC_IMG_VER_OLD) {
17838c2ecf20Sopenharmony_ci		return false;
17848c2ecf20Sopenharmony_ci	}
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	/* IF Flash has a better F/W than smem do not work with smem.
17878c2ecf20Sopenharmony_ci	 * If smem f/w == flash f/w, as smem f/w not old | incmp, work with it.
17888c2ecf20Sopenharmony_ci	 * If Flash is old or incomp work with smem iff smem f/w == drv f/w.
17898c2ecf20Sopenharmony_ci	 */
17908c2ecf20Sopenharmony_ci	smem_flash_cmp = bfa_ioc_flash_fwver_cmp(ioc, fwhdr);
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	if (smem_flash_cmp == BFI_IOC_IMG_VER_BETTER)
17938c2ecf20Sopenharmony_ci		return false;
17948c2ecf20Sopenharmony_ci	else if (smem_flash_cmp == BFI_IOC_IMG_VER_SAME)
17958c2ecf20Sopenharmony_ci		return true;
17968c2ecf20Sopenharmony_ci	else
17978c2ecf20Sopenharmony_ci		return (drv_smem_cmp == BFI_IOC_IMG_VER_SAME) ?
17988c2ecf20Sopenharmony_ci			true : false;
17998c2ecf20Sopenharmony_ci}
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci/* Return true if current running version is valid. Firmware signature and
18028c2ecf20Sopenharmony_ci * execution context (driver/bios) must match.
18038c2ecf20Sopenharmony_ci */
18048c2ecf20Sopenharmony_cistatic bool
18058c2ecf20Sopenharmony_cibfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env)
18068c2ecf20Sopenharmony_ci{
18078c2ecf20Sopenharmony_ci	struct bfi_ioc_image_hdr fwhdr;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	bfa_nw_ioc_fwver_get(ioc, &fwhdr);
18108c2ecf20Sopenharmony_ci	if (swab32(fwhdr.bootenv) != boot_env)
18118c2ecf20Sopenharmony_ci		return false;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	return bfa_nw_ioc_fwver_cmp(ioc, &fwhdr);
18148c2ecf20Sopenharmony_ci}
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci/* Conditionally flush any pending message from firmware at start. */
18178c2ecf20Sopenharmony_cistatic void
18188c2ecf20Sopenharmony_cibfa_ioc_msgflush(struct bfa_ioc *ioc)
18198c2ecf20Sopenharmony_ci{
18208c2ecf20Sopenharmony_ci	u32	r32;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
18238c2ecf20Sopenharmony_ci	if (r32)
18248c2ecf20Sopenharmony_ci		writel(1, ioc->ioc_regs.lpu_mbox_cmd);
18258c2ecf20Sopenharmony_ci}
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_cistatic void
18288c2ecf20Sopenharmony_cibfa_ioc_hwinit(struct bfa_ioc *ioc, bool force)
18298c2ecf20Sopenharmony_ci{
18308c2ecf20Sopenharmony_ci	enum bfi_ioc_state ioc_fwstate;
18318c2ecf20Sopenharmony_ci	bool fwvalid;
18328c2ecf20Sopenharmony_ci	u32 boot_env;
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	ioc_fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	if (force)
18378c2ecf20Sopenharmony_ci		ioc_fwstate = BFI_IOC_UNINIT;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	boot_env = BFI_FWBOOT_ENV_OS;
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	/**
18428c2ecf20Sopenharmony_ci	 * check if firmware is valid
18438c2ecf20Sopenharmony_ci	 */
18448c2ecf20Sopenharmony_ci	fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
18458c2ecf20Sopenharmony_ci		false : bfa_ioc_fwver_valid(ioc, boot_env);
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	if (!fwvalid) {
18488c2ecf20Sopenharmony_ci		if (bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env) ==
18498c2ecf20Sopenharmony_ci								BFA_STATUS_OK)
18508c2ecf20Sopenharmony_ci			bfa_ioc_poll_fwinit(ioc);
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci		return;
18538c2ecf20Sopenharmony_ci	}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	/**
18568c2ecf20Sopenharmony_ci	 * If hardware initialization is in progress (initialized by other IOC),
18578c2ecf20Sopenharmony_ci	 * just wait for an initialization completion interrupt.
18588c2ecf20Sopenharmony_ci	 */
18598c2ecf20Sopenharmony_ci	if (ioc_fwstate == BFI_IOC_INITING) {
18608c2ecf20Sopenharmony_ci		bfa_ioc_poll_fwinit(ioc);
18618c2ecf20Sopenharmony_ci		return;
18628c2ecf20Sopenharmony_ci	}
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	/**
18658c2ecf20Sopenharmony_ci	 * If IOC function is disabled and firmware version is same,
18668c2ecf20Sopenharmony_ci	 * just re-enable IOC.
18678c2ecf20Sopenharmony_ci	 */
18688c2ecf20Sopenharmony_ci	if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {
18698c2ecf20Sopenharmony_ci		/**
18708c2ecf20Sopenharmony_ci		 * When using MSI-X any pending firmware ready event should
18718c2ecf20Sopenharmony_ci		 * be flushed. Otherwise MSI-X interrupts are not delivered.
18728c2ecf20Sopenharmony_ci		 */
18738c2ecf20Sopenharmony_ci		bfa_ioc_msgflush(ioc);
18748c2ecf20Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);
18758c2ecf20Sopenharmony_ci		return;
18768c2ecf20Sopenharmony_ci	}
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	/**
18798c2ecf20Sopenharmony_ci	 * Initialize the h/w for any other states.
18808c2ecf20Sopenharmony_ci	 */
18818c2ecf20Sopenharmony_ci	if (bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env) ==
18828c2ecf20Sopenharmony_ci							BFA_STATUS_OK)
18838c2ecf20Sopenharmony_ci		bfa_ioc_poll_fwinit(ioc);
18848c2ecf20Sopenharmony_ci}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_civoid
18878c2ecf20Sopenharmony_cibfa_nw_ioc_timeout(struct bfa_ioc *ioc)
18888c2ecf20Sopenharmony_ci{
18898c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);
18908c2ecf20Sopenharmony_ci}
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_cistatic void
18938c2ecf20Sopenharmony_cibfa_ioc_mbox_send(struct bfa_ioc *ioc, void *ioc_msg, int len)
18948c2ecf20Sopenharmony_ci{
18958c2ecf20Sopenharmony_ci	u32 *msgp = (u32 *) ioc_msg;
18968c2ecf20Sopenharmony_ci	u32 i;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	BUG_ON(!(len <= BFI_IOC_MSGLEN_MAX));
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	/*
19018c2ecf20Sopenharmony_ci	 * first write msg to mailbox registers
19028c2ecf20Sopenharmony_ci	 */
19038c2ecf20Sopenharmony_ci	for (i = 0; i < len / sizeof(u32); i++)
19048c2ecf20Sopenharmony_ci		writel(cpu_to_le32(msgp[i]),
19058c2ecf20Sopenharmony_ci			      ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
19088c2ecf20Sopenharmony_ci		writel(0, ioc->ioc_regs.hfn_mbox + i * sizeof(u32));
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	/*
19118c2ecf20Sopenharmony_ci	 * write 1 to mailbox CMD to trigger LPU event
19128c2ecf20Sopenharmony_ci	 */
19138c2ecf20Sopenharmony_ci	writel(1, ioc->ioc_regs.hfn_mbox_cmd);
19148c2ecf20Sopenharmony_ci	(void) readl(ioc->ioc_regs.hfn_mbox_cmd);
19158c2ecf20Sopenharmony_ci}
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_cistatic void
19188c2ecf20Sopenharmony_cibfa_ioc_send_enable(struct bfa_ioc *ioc)
19198c2ecf20Sopenharmony_ci{
19208c2ecf20Sopenharmony_ci	struct bfi_ioc_ctrl_req enable_req;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
19238c2ecf20Sopenharmony_ci		    bfa_ioc_portid(ioc));
19248c2ecf20Sopenharmony_ci	enable_req.clscode = htons(ioc->clscode);
19258c2ecf20Sopenharmony_ci	enable_req.rsvd = htons(0);
19268c2ecf20Sopenharmony_ci	/* overflow in 2106 */
19278c2ecf20Sopenharmony_ci	enable_req.tv_sec = ntohl(ktime_get_real_seconds());
19288c2ecf20Sopenharmony_ci	bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req));
19298c2ecf20Sopenharmony_ci}
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_cistatic void
19328c2ecf20Sopenharmony_cibfa_ioc_send_disable(struct bfa_ioc *ioc)
19338c2ecf20Sopenharmony_ci{
19348c2ecf20Sopenharmony_ci	struct bfi_ioc_ctrl_req disable_req;
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,
19378c2ecf20Sopenharmony_ci		    bfa_ioc_portid(ioc));
19388c2ecf20Sopenharmony_ci	disable_req.clscode = htons(ioc->clscode);
19398c2ecf20Sopenharmony_ci	disable_req.rsvd = htons(0);
19408c2ecf20Sopenharmony_ci	/* overflow in 2106 */
19418c2ecf20Sopenharmony_ci	disable_req.tv_sec = ntohl(ktime_get_real_seconds());
19428c2ecf20Sopenharmony_ci	bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req));
19438c2ecf20Sopenharmony_ci}
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_cistatic void
19468c2ecf20Sopenharmony_cibfa_ioc_send_getattr(struct bfa_ioc *ioc)
19478c2ecf20Sopenharmony_ci{
19488c2ecf20Sopenharmony_ci	struct bfi_ioc_getattr_req attr_req;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ,
19518c2ecf20Sopenharmony_ci		    bfa_ioc_portid(ioc));
19528c2ecf20Sopenharmony_ci	bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa);
19538c2ecf20Sopenharmony_ci	bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req));
19548c2ecf20Sopenharmony_ci}
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_civoid
19578c2ecf20Sopenharmony_cibfa_nw_ioc_hb_check(struct bfa_ioc *ioc)
19588c2ecf20Sopenharmony_ci{
19598c2ecf20Sopenharmony_ci	u32 hb_count;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	hb_count = readl(ioc->ioc_regs.heartbeat);
19628c2ecf20Sopenharmony_ci	if (ioc->hb_count == hb_count) {
19638c2ecf20Sopenharmony_ci		bfa_ioc_recover(ioc);
19648c2ecf20Sopenharmony_ci		return;
19658c2ecf20Sopenharmony_ci	} else {
19668c2ecf20Sopenharmony_ci		ioc->hb_count = hb_count;
19678c2ecf20Sopenharmony_ci	}
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	bfa_ioc_mbox_poll(ioc);
19708c2ecf20Sopenharmony_ci	mod_timer(&ioc->hb_timer, jiffies +
19718c2ecf20Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_HB_TOV));
19728c2ecf20Sopenharmony_ci}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_cistatic void
19758c2ecf20Sopenharmony_cibfa_ioc_hb_monitor(struct bfa_ioc *ioc)
19768c2ecf20Sopenharmony_ci{
19778c2ecf20Sopenharmony_ci	ioc->hb_count = readl(ioc->ioc_regs.heartbeat);
19788c2ecf20Sopenharmony_ci	mod_timer(&ioc->hb_timer, jiffies +
19798c2ecf20Sopenharmony_ci		msecs_to_jiffies(BFA_IOC_HB_TOV));
19808c2ecf20Sopenharmony_ci}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_cistatic void
19838c2ecf20Sopenharmony_cibfa_ioc_hb_stop(struct bfa_ioc *ioc)
19848c2ecf20Sopenharmony_ci{
19858c2ecf20Sopenharmony_ci	del_timer(&ioc->hb_timer);
19868c2ecf20Sopenharmony_ci}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci/* Initiate a full firmware download. */
19898c2ecf20Sopenharmony_cistatic enum bfa_status
19908c2ecf20Sopenharmony_cibfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
19918c2ecf20Sopenharmony_ci		    u32 boot_env)
19928c2ecf20Sopenharmony_ci{
19938c2ecf20Sopenharmony_ci	u32 *fwimg;
19948c2ecf20Sopenharmony_ci	u32 pgnum;
19958c2ecf20Sopenharmony_ci	u32 loff = 0;
19968c2ecf20Sopenharmony_ci	u32 chunkno = 0;
19978c2ecf20Sopenharmony_ci	u32 i;
19988c2ecf20Sopenharmony_ci	u32 asicmode;
19998c2ecf20Sopenharmony_ci	u32 fwimg_size;
20008c2ecf20Sopenharmony_ci	u32 fwimg_buf[BFI_FLASH_CHUNK_SZ_WORDS];
20018c2ecf20Sopenharmony_ci	enum bfa_status status;
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	if (boot_env == BFI_FWBOOT_ENV_OS &&
20048c2ecf20Sopenharmony_ci	    boot_type == BFI_FWBOOT_TYPE_FLASH) {
20058c2ecf20Sopenharmony_ci		fwimg_size = BFI_FLASH_IMAGE_SZ/sizeof(u32);
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci		status = bfa_nw_ioc_flash_img_get_chnk(ioc,
20088c2ecf20Sopenharmony_ci			BFA_IOC_FLASH_CHUNK_ADDR(chunkno), fwimg_buf);
20098c2ecf20Sopenharmony_ci		if (status != BFA_STATUS_OK)
20108c2ecf20Sopenharmony_ci			return status;
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci		fwimg = fwimg_buf;
20138c2ecf20Sopenharmony_ci	} else {
20148c2ecf20Sopenharmony_ci		fwimg_size = bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc));
20158c2ecf20Sopenharmony_ci		fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc),
20168c2ecf20Sopenharmony_ci					BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
20178c2ecf20Sopenharmony_ci	}
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	pgnum = bfa_ioc_smem_pgnum(ioc, loff);
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	for (i = 0; i < fwimg_size; i++) {
20248c2ecf20Sopenharmony_ci		if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {
20258c2ecf20Sopenharmony_ci			chunkno = BFA_IOC_FLASH_CHUNK_NO(i);
20268c2ecf20Sopenharmony_ci			if (boot_env == BFI_FWBOOT_ENV_OS &&
20278c2ecf20Sopenharmony_ci			    boot_type == BFI_FWBOOT_TYPE_FLASH) {
20288c2ecf20Sopenharmony_ci				status = bfa_nw_ioc_flash_img_get_chnk(ioc,
20298c2ecf20Sopenharmony_ci					BFA_IOC_FLASH_CHUNK_ADDR(chunkno),
20308c2ecf20Sopenharmony_ci					fwimg_buf);
20318c2ecf20Sopenharmony_ci				if (status != BFA_STATUS_OK)
20328c2ecf20Sopenharmony_ci					return status;
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci				fwimg = fwimg_buf;
20358c2ecf20Sopenharmony_ci			} else {
20368c2ecf20Sopenharmony_ci				fwimg = bfa_cb_image_get_chunk(
20378c2ecf20Sopenharmony_ci					bfa_ioc_asic_gen(ioc),
20388c2ecf20Sopenharmony_ci					BFA_IOC_FLASH_CHUNK_ADDR(chunkno));
20398c2ecf20Sopenharmony_ci			}
20408c2ecf20Sopenharmony_ci		}
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci		/**
20438c2ecf20Sopenharmony_ci		 * write smem
20448c2ecf20Sopenharmony_ci		 */
20458c2ecf20Sopenharmony_ci		writel(swab32(fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)]),
20468c2ecf20Sopenharmony_ci		       ioc->ioc_regs.smem_page_start + loff);
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci		loff += sizeof(u32);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci		/**
20518c2ecf20Sopenharmony_ci		 * handle page offset wrap around
20528c2ecf20Sopenharmony_ci		 */
20538c2ecf20Sopenharmony_ci		loff = PSS_SMEM_PGOFF(loff);
20548c2ecf20Sopenharmony_ci		if (loff == 0) {
20558c2ecf20Sopenharmony_ci			pgnum++;
20568c2ecf20Sopenharmony_ci			writel(pgnum,
20578c2ecf20Sopenharmony_ci				      ioc->ioc_regs.host_page_num_fn);
20588c2ecf20Sopenharmony_ci		}
20598c2ecf20Sopenharmony_ci	}
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	writel(bfa_ioc_smem_pgnum(ioc, 0),
20628c2ecf20Sopenharmony_ci		      ioc->ioc_regs.host_page_num_fn);
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	/*
20658c2ecf20Sopenharmony_ci	 * Set boot type, env and device mode at the end.
20668c2ecf20Sopenharmony_ci	*/
20678c2ecf20Sopenharmony_ci	if (boot_env == BFI_FWBOOT_ENV_OS &&
20688c2ecf20Sopenharmony_ci	    boot_type == BFI_FWBOOT_TYPE_FLASH) {
20698c2ecf20Sopenharmony_ci		boot_type = BFI_FWBOOT_TYPE_NORMAL;
20708c2ecf20Sopenharmony_ci	}
20718c2ecf20Sopenharmony_ci	asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode,
20728c2ecf20Sopenharmony_ci					ioc->port0_mode, ioc->port1_mode);
20738c2ecf20Sopenharmony_ci	writel(asicmode, ((ioc->ioc_regs.smem_page_start)
20748c2ecf20Sopenharmony_ci			+ BFI_FWBOOT_DEVMODE_OFF));
20758c2ecf20Sopenharmony_ci	writel(boot_type, ((ioc->ioc_regs.smem_page_start)
20768c2ecf20Sopenharmony_ci			+ (BFI_FWBOOT_TYPE_OFF)));
20778c2ecf20Sopenharmony_ci	writel(boot_env, ((ioc->ioc_regs.smem_page_start)
20788c2ecf20Sopenharmony_ci			+ (BFI_FWBOOT_ENV_OFF)));
20798c2ecf20Sopenharmony_ci	return BFA_STATUS_OK;
20808c2ecf20Sopenharmony_ci}
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_cistatic void
20838c2ecf20Sopenharmony_cibfa_ioc_reset(struct bfa_ioc *ioc, bool force)
20848c2ecf20Sopenharmony_ci{
20858c2ecf20Sopenharmony_ci	bfa_ioc_hwinit(ioc, force);
20868c2ecf20Sopenharmony_ci}
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci/* BFA ioc enable reply by firmware */
20898c2ecf20Sopenharmony_cistatic void
20908c2ecf20Sopenharmony_cibfa_ioc_enable_reply(struct bfa_ioc *ioc, enum bfa_mode port_mode,
20918c2ecf20Sopenharmony_ci			u8 cap_bm)
20928c2ecf20Sopenharmony_ci{
20938c2ecf20Sopenharmony_ci	struct bfa_iocpf *iocpf = &ioc->iocpf;
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci	ioc->port_mode = ioc->port_mode_cfg = port_mode;
20968c2ecf20Sopenharmony_ci	ioc->ad_cap_bm = cap_bm;
20978c2ecf20Sopenharmony_ci	bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE);
20988c2ecf20Sopenharmony_ci}
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci/* Update BFA configuration from firmware configuration. */
21018c2ecf20Sopenharmony_cistatic void
21028c2ecf20Sopenharmony_cibfa_ioc_getattr_reply(struct bfa_ioc *ioc)
21038c2ecf20Sopenharmony_ci{
21048c2ecf20Sopenharmony_ci	struct bfi_ioc_attr *attr = ioc->attr;
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	attr->adapter_prop  = ntohl(attr->adapter_prop);
21078c2ecf20Sopenharmony_ci	attr->card_type     = ntohl(attr->card_type);
21088c2ecf20Sopenharmony_ci	attr->maxfrsize	    = ntohs(attr->maxfrsize);
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
21118c2ecf20Sopenharmony_ci}
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci/* Attach time initialization of mbox logic. */
21148c2ecf20Sopenharmony_cistatic void
21158c2ecf20Sopenharmony_cibfa_ioc_mbox_attach(struct bfa_ioc *ioc)
21168c2ecf20Sopenharmony_ci{
21178c2ecf20Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
21188c2ecf20Sopenharmony_ci	int	mc;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mod->cmd_q);
21218c2ecf20Sopenharmony_ci	for (mc = 0; mc < BFI_MC_MAX; mc++) {
21228c2ecf20Sopenharmony_ci		mod->mbhdlr[mc].cbfn = NULL;
21238c2ecf20Sopenharmony_ci		mod->mbhdlr[mc].cbarg = ioc->bfa;
21248c2ecf20Sopenharmony_ci	}
21258c2ecf20Sopenharmony_ci}
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci/* Mbox poll timer -- restarts any pending mailbox requests. */
21288c2ecf20Sopenharmony_cistatic void
21298c2ecf20Sopenharmony_cibfa_ioc_mbox_poll(struct bfa_ioc *ioc)
21308c2ecf20Sopenharmony_ci{
21318c2ecf20Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
21328c2ecf20Sopenharmony_ci	struct bfa_mbox_cmd *cmd;
21338c2ecf20Sopenharmony_ci	bfa_mbox_cmd_cbfn_t cbfn;
21348c2ecf20Sopenharmony_ci	void *cbarg;
21358c2ecf20Sopenharmony_ci	u32 stat;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	/**
21388c2ecf20Sopenharmony_ci	 * If no command pending, do nothing
21398c2ecf20Sopenharmony_ci	 */
21408c2ecf20Sopenharmony_ci	if (list_empty(&mod->cmd_q))
21418c2ecf20Sopenharmony_ci		return;
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci	/**
21448c2ecf20Sopenharmony_ci	 * If previous command is not yet fetched by firmware, do nothing
21458c2ecf20Sopenharmony_ci	 */
21468c2ecf20Sopenharmony_ci	stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
21478c2ecf20Sopenharmony_ci	if (stat)
21488c2ecf20Sopenharmony_ci		return;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	/**
21518c2ecf20Sopenharmony_ci	 * Enqueue command to firmware.
21528c2ecf20Sopenharmony_ci	 */
21538c2ecf20Sopenharmony_ci	cmd = list_first_entry(&mod->cmd_q, struct bfa_mbox_cmd, qe);
21548c2ecf20Sopenharmony_ci	list_del(&cmd->qe);
21558c2ecf20Sopenharmony_ci	bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	/**
21588c2ecf20Sopenharmony_ci	 * Give a callback to the client, indicating that the command is sent
21598c2ecf20Sopenharmony_ci	 */
21608c2ecf20Sopenharmony_ci	if (cmd->cbfn) {
21618c2ecf20Sopenharmony_ci		cbfn = cmd->cbfn;
21628c2ecf20Sopenharmony_ci		cbarg = cmd->cbarg;
21638c2ecf20Sopenharmony_ci		cmd->cbfn = NULL;
21648c2ecf20Sopenharmony_ci		cbfn(cbarg);
21658c2ecf20Sopenharmony_ci	}
21668c2ecf20Sopenharmony_ci}
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci/* Cleanup any pending requests. */
21698c2ecf20Sopenharmony_cistatic void
21708c2ecf20Sopenharmony_cibfa_ioc_mbox_flush(struct bfa_ioc *ioc)
21718c2ecf20Sopenharmony_ci{
21728c2ecf20Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
21738c2ecf20Sopenharmony_ci	struct bfa_mbox_cmd *cmd;
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	while (!list_empty(&mod->cmd_q)) {
21768c2ecf20Sopenharmony_ci		cmd = list_first_entry(&mod->cmd_q, struct bfa_mbox_cmd, qe);
21778c2ecf20Sopenharmony_ci		list_del(&cmd->qe);
21788c2ecf20Sopenharmony_ci	}
21798c2ecf20Sopenharmony_ci}
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci/**
21828c2ecf20Sopenharmony_ci * bfa_nw_ioc_smem_read - Read data from SMEM to host through PCI memmap
21838c2ecf20Sopenharmony_ci *
21848c2ecf20Sopenharmony_ci * @ioc:     memory for IOC
21858c2ecf20Sopenharmony_ci * @tbuf:    app memory to store data from smem
21868c2ecf20Sopenharmony_ci * @soff:    smem offset
21878c2ecf20Sopenharmony_ci * @sz:      size of smem in bytes
21888c2ecf20Sopenharmony_ci */
21898c2ecf20Sopenharmony_cistatic int
21908c2ecf20Sopenharmony_cibfa_nw_ioc_smem_read(struct bfa_ioc *ioc, void *tbuf, u32 soff, u32 sz)
21918c2ecf20Sopenharmony_ci{
21928c2ecf20Sopenharmony_ci	u32 pgnum, loff, r32;
21938c2ecf20Sopenharmony_ci	int i, len;
21948c2ecf20Sopenharmony_ci	u32 *buf = tbuf;
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff);
21978c2ecf20Sopenharmony_ci	loff = PSS_SMEM_PGOFF(soff);
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci	/*
22008c2ecf20Sopenharmony_ci	 *  Hold semaphore to serialize pll init and fwtrc.
22018c2ecf20Sopenharmony_ci	*/
22028c2ecf20Sopenharmony_ci	if (!bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg))
22038c2ecf20Sopenharmony_ci		return 1;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	writel(pgnum, ioc->ioc_regs.host_page_num_fn);
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	len = sz/sizeof(u32);
22088c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
22098c2ecf20Sopenharmony_ci		r32 = swab32(readl(loff + ioc->ioc_regs.smem_page_start));
22108c2ecf20Sopenharmony_ci		buf[i] = be32_to_cpu(r32);
22118c2ecf20Sopenharmony_ci		loff += sizeof(u32);
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci		/**
22148c2ecf20Sopenharmony_ci		 * handle page offset wrap around
22158c2ecf20Sopenharmony_ci		 */
22168c2ecf20Sopenharmony_ci		loff = PSS_SMEM_PGOFF(loff);
22178c2ecf20Sopenharmony_ci		if (loff == 0) {
22188c2ecf20Sopenharmony_ci			pgnum++;
22198c2ecf20Sopenharmony_ci			writel(pgnum, ioc->ioc_regs.host_page_num_fn);
22208c2ecf20Sopenharmony_ci		}
22218c2ecf20Sopenharmony_ci	}
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),
22248c2ecf20Sopenharmony_ci	       ioc->ioc_regs.host_page_num_fn);
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci	/*
22278c2ecf20Sopenharmony_ci	 * release semaphore
22288c2ecf20Sopenharmony_ci	 */
22298c2ecf20Sopenharmony_ci	readl(ioc->ioc_regs.ioc_init_sem_reg);
22308c2ecf20Sopenharmony_ci	writel(1, ioc->ioc_regs.ioc_init_sem_reg);
22318c2ecf20Sopenharmony_ci	return 0;
22328c2ecf20Sopenharmony_ci}
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci/* Retrieve saved firmware trace from a prior IOC failure. */
22358c2ecf20Sopenharmony_ciint
22368c2ecf20Sopenharmony_cibfa_nw_ioc_debug_fwtrc(struct bfa_ioc *ioc, void *trcdata, int *trclen)
22378c2ecf20Sopenharmony_ci{
22388c2ecf20Sopenharmony_ci	u32 loff = BFI_IOC_TRC_OFF + BNA_DBG_FWTRC_LEN * ioc->port_id;
22398c2ecf20Sopenharmony_ci	int tlen, status = 0;
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	tlen = *trclen;
22428c2ecf20Sopenharmony_ci	if (tlen > BNA_DBG_FWTRC_LEN)
22438c2ecf20Sopenharmony_ci		tlen = BNA_DBG_FWTRC_LEN;
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci	status = bfa_nw_ioc_smem_read(ioc, trcdata, loff, tlen);
22468c2ecf20Sopenharmony_ci	*trclen = tlen;
22478c2ecf20Sopenharmony_ci	return status;
22488c2ecf20Sopenharmony_ci}
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci/* Save firmware trace if configured. */
22518c2ecf20Sopenharmony_cistatic void
22528c2ecf20Sopenharmony_cibfa_nw_ioc_debug_save_ftrc(struct bfa_ioc *ioc)
22538c2ecf20Sopenharmony_ci{
22548c2ecf20Sopenharmony_ci	int tlen;
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci	if (ioc->dbg_fwsave_once) {
22578c2ecf20Sopenharmony_ci		ioc->dbg_fwsave_once = false;
22588c2ecf20Sopenharmony_ci		if (ioc->dbg_fwsave_len) {
22598c2ecf20Sopenharmony_ci			tlen = ioc->dbg_fwsave_len;
22608c2ecf20Sopenharmony_ci			bfa_nw_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
22618c2ecf20Sopenharmony_ci		}
22628c2ecf20Sopenharmony_ci	}
22638c2ecf20Sopenharmony_ci}
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci/* Retrieve saved firmware trace from a prior IOC failure. */
22668c2ecf20Sopenharmony_ciint
22678c2ecf20Sopenharmony_cibfa_nw_ioc_debug_fwsave(struct bfa_ioc *ioc, void *trcdata, int *trclen)
22688c2ecf20Sopenharmony_ci{
22698c2ecf20Sopenharmony_ci	int tlen;
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	if (ioc->dbg_fwsave_len == 0)
22728c2ecf20Sopenharmony_ci		return BFA_STATUS_ENOFSAVE;
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci	tlen = *trclen;
22758c2ecf20Sopenharmony_ci	if (tlen > ioc->dbg_fwsave_len)
22768c2ecf20Sopenharmony_ci		tlen = ioc->dbg_fwsave_len;
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci	memcpy(trcdata, ioc->dbg_fwsave, tlen);
22798c2ecf20Sopenharmony_ci	*trclen = tlen;
22808c2ecf20Sopenharmony_ci	return BFA_STATUS_OK;
22818c2ecf20Sopenharmony_ci}
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_cistatic void
22848c2ecf20Sopenharmony_cibfa_ioc_fail_notify(struct bfa_ioc *ioc)
22858c2ecf20Sopenharmony_ci{
22868c2ecf20Sopenharmony_ci	/**
22878c2ecf20Sopenharmony_ci	 * Notify driver and common modules registered for notification.
22888c2ecf20Sopenharmony_ci	 */
22898c2ecf20Sopenharmony_ci	ioc->cbfn->hbfail_cbfn(ioc->bfa);
22908c2ecf20Sopenharmony_ci	bfa_ioc_event_notify(ioc, BFA_IOC_E_FAILED);
22918c2ecf20Sopenharmony_ci	bfa_nw_ioc_debug_save_ftrc(ioc);
22928c2ecf20Sopenharmony_ci}
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci/* IOCPF to IOC interface */
22958c2ecf20Sopenharmony_cistatic void
22968c2ecf20Sopenharmony_cibfa_ioc_pf_enabled(struct bfa_ioc *ioc)
22978c2ecf20Sopenharmony_ci{
22988c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_ENABLED);
22998c2ecf20Sopenharmony_ci}
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_cistatic void
23028c2ecf20Sopenharmony_cibfa_ioc_pf_disabled(struct bfa_ioc *ioc)
23038c2ecf20Sopenharmony_ci{
23048c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_DISABLED);
23058c2ecf20Sopenharmony_ci}
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_cistatic void
23088c2ecf20Sopenharmony_cibfa_ioc_pf_failed(struct bfa_ioc *ioc)
23098c2ecf20Sopenharmony_ci{
23108c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_PFFAILED);
23118c2ecf20Sopenharmony_ci}
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_cistatic void
23148c2ecf20Sopenharmony_cibfa_ioc_pf_hwfailed(struct bfa_ioc *ioc)
23158c2ecf20Sopenharmony_ci{
23168c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_HWFAILED);
23178c2ecf20Sopenharmony_ci}
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_cistatic void
23208c2ecf20Sopenharmony_cibfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc)
23218c2ecf20Sopenharmony_ci{
23228c2ecf20Sopenharmony_ci	/**
23238c2ecf20Sopenharmony_ci	 * Provide enable completion callback and AEN notification.
23248c2ecf20Sopenharmony_ci	 */
23258c2ecf20Sopenharmony_ci	ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
23268c2ecf20Sopenharmony_ci}
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci/* IOC public */
23298c2ecf20Sopenharmony_cistatic enum bfa_status
23308c2ecf20Sopenharmony_cibfa_ioc_pll_init(struct bfa_ioc *ioc)
23318c2ecf20Sopenharmony_ci{
23328c2ecf20Sopenharmony_ci	/*
23338c2ecf20Sopenharmony_ci	 *  Hold semaphore so that nobody can access the chip during init.
23348c2ecf20Sopenharmony_ci	 */
23358c2ecf20Sopenharmony_ci	bfa_nw_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg);
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	bfa_ioc_pll_init_asic(ioc);
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	ioc->pllinit = true;
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	/* Initialize LMEM */
23428c2ecf20Sopenharmony_ci	bfa_ioc_lmem_init(ioc);
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	/*
23458c2ecf20Sopenharmony_ci	 *  release semaphore.
23468c2ecf20Sopenharmony_ci	 */
23478c2ecf20Sopenharmony_ci	bfa_nw_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg);
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	return BFA_STATUS_OK;
23508c2ecf20Sopenharmony_ci}
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ci/* Interface used by diag module to do firmware boot with memory test
23538c2ecf20Sopenharmony_ci * as the entry vector.
23548c2ecf20Sopenharmony_ci */
23558c2ecf20Sopenharmony_cistatic enum bfa_status
23568c2ecf20Sopenharmony_cibfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type,
23578c2ecf20Sopenharmony_ci		u32 boot_env)
23588c2ecf20Sopenharmony_ci{
23598c2ecf20Sopenharmony_ci	struct bfi_ioc_image_hdr *drv_fwhdr;
23608c2ecf20Sopenharmony_ci	enum bfa_status status;
23618c2ecf20Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_boots);
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
23648c2ecf20Sopenharmony_ci		return BFA_STATUS_FAILED;
23658c2ecf20Sopenharmony_ci	if (boot_env == BFI_FWBOOT_ENV_OS &&
23668c2ecf20Sopenharmony_ci	    boot_type == BFI_FWBOOT_TYPE_NORMAL) {
23678c2ecf20Sopenharmony_ci		drv_fwhdr = (struct bfi_ioc_image_hdr *)
23688c2ecf20Sopenharmony_ci			bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);
23698c2ecf20Sopenharmony_ci		/* Work with Flash iff flash f/w is better than driver f/w.
23708c2ecf20Sopenharmony_ci		 * Otherwise push drivers firmware.
23718c2ecf20Sopenharmony_ci		 */
23728c2ecf20Sopenharmony_ci		if (bfa_ioc_flash_fwver_cmp(ioc, drv_fwhdr) ==
23738c2ecf20Sopenharmony_ci			BFI_IOC_IMG_VER_BETTER)
23748c2ecf20Sopenharmony_ci			boot_type = BFI_FWBOOT_TYPE_FLASH;
23758c2ecf20Sopenharmony_ci	}
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci	/**
23788c2ecf20Sopenharmony_ci	 * Initialize IOC state of all functions on a chip reset.
23798c2ecf20Sopenharmony_ci	 */
23808c2ecf20Sopenharmony_ci	if (boot_type == BFI_FWBOOT_TYPE_MEMTEST) {
23818c2ecf20Sopenharmony_ci		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_MEMTEST);
23828c2ecf20Sopenharmony_ci		bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_MEMTEST);
23838c2ecf20Sopenharmony_ci	} else {
23848c2ecf20Sopenharmony_ci		bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_INITING);
23858c2ecf20Sopenharmony_ci		bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_INITING);
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	bfa_ioc_msgflush(ioc);
23898c2ecf20Sopenharmony_ci	status = bfa_ioc_download_fw(ioc, boot_type, boot_env);
23908c2ecf20Sopenharmony_ci	if (status == BFA_STATUS_OK)
23918c2ecf20Sopenharmony_ci		bfa_ioc_lpu_start(ioc);
23928c2ecf20Sopenharmony_ci	else
23938c2ecf20Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	return status;
23968c2ecf20Sopenharmony_ci}
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci/* Enable/disable IOC failure auto recovery. */
23998c2ecf20Sopenharmony_civoid
24008c2ecf20Sopenharmony_cibfa_nw_ioc_auto_recover(bool auto_recover)
24018c2ecf20Sopenharmony_ci{
24028c2ecf20Sopenharmony_ci	bfa_nw_auto_recover = auto_recover;
24038c2ecf20Sopenharmony_ci}
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_cistatic bool
24068c2ecf20Sopenharmony_cibfa_ioc_msgget(struct bfa_ioc *ioc, void *mbmsg)
24078c2ecf20Sopenharmony_ci{
24088c2ecf20Sopenharmony_ci	u32	*msgp = mbmsg;
24098c2ecf20Sopenharmony_ci	u32	r32;
24108c2ecf20Sopenharmony_ci	int		i;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);
24138c2ecf20Sopenharmony_ci	if ((r32 & 1) == 0)
24148c2ecf20Sopenharmony_ci		return false;
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	/**
24178c2ecf20Sopenharmony_ci	 * read the MBOX msg
24188c2ecf20Sopenharmony_ci	 */
24198c2ecf20Sopenharmony_ci	for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
24208c2ecf20Sopenharmony_ci	     i++) {
24218c2ecf20Sopenharmony_ci		r32 = readl(ioc->ioc_regs.lpu_mbox +
24228c2ecf20Sopenharmony_ci				   i * sizeof(u32));
24238c2ecf20Sopenharmony_ci		msgp[i] = htonl(r32);
24248c2ecf20Sopenharmony_ci	}
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_ci	/**
24278c2ecf20Sopenharmony_ci	 * turn off mailbox interrupt by clearing mailbox status
24288c2ecf20Sopenharmony_ci	 */
24298c2ecf20Sopenharmony_ci	writel(1, ioc->ioc_regs.lpu_mbox_cmd);
24308c2ecf20Sopenharmony_ci	readl(ioc->ioc_regs.lpu_mbox_cmd);
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	return true;
24338c2ecf20Sopenharmony_ci}
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_cistatic void
24368c2ecf20Sopenharmony_cibfa_ioc_isr(struct bfa_ioc *ioc, struct bfi_mbmsg *m)
24378c2ecf20Sopenharmony_ci{
24388c2ecf20Sopenharmony_ci	union bfi_ioc_i2h_msg_u	*msg;
24398c2ecf20Sopenharmony_ci	struct bfa_iocpf *iocpf = &ioc->iocpf;
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	msg = (union bfi_ioc_i2h_msg_u *) m;
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_isrs);
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	switch (msg->mh.msg_id) {
24468c2ecf20Sopenharmony_ci	case BFI_IOC_I2H_HBEAT:
24478c2ecf20Sopenharmony_ci		break;
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_ci	case BFI_IOC_I2H_ENABLE_REPLY:
24508c2ecf20Sopenharmony_ci		bfa_ioc_enable_reply(ioc,
24518c2ecf20Sopenharmony_ci			(enum bfa_mode)msg->fw_event.port_mode,
24528c2ecf20Sopenharmony_ci			msg->fw_event.cap_bm);
24538c2ecf20Sopenharmony_ci		break;
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci	case BFI_IOC_I2H_DISABLE_REPLY:
24568c2ecf20Sopenharmony_ci		bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_DISABLE);
24578c2ecf20Sopenharmony_ci		break;
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	case BFI_IOC_I2H_GETATTR_REPLY:
24608c2ecf20Sopenharmony_ci		bfa_ioc_getattr_reply(ioc);
24618c2ecf20Sopenharmony_ci		break;
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci	default:
24648c2ecf20Sopenharmony_ci		BUG_ON(1);
24658c2ecf20Sopenharmony_ci	}
24668c2ecf20Sopenharmony_ci}
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci/**
24698c2ecf20Sopenharmony_ci * bfa_nw_ioc_attach - IOC attach time initialization and setup.
24708c2ecf20Sopenharmony_ci *
24718c2ecf20Sopenharmony_ci * @ioc:	memory for IOC
24728c2ecf20Sopenharmony_ci * @bfa:	driver instance structure
24738c2ecf20Sopenharmony_ci * @cbfn:	callback function
24748c2ecf20Sopenharmony_ci */
24758c2ecf20Sopenharmony_civoid
24768c2ecf20Sopenharmony_cibfa_nw_ioc_attach(struct bfa_ioc *ioc, void *bfa, struct bfa_ioc_cbfn *cbfn)
24778c2ecf20Sopenharmony_ci{
24788c2ecf20Sopenharmony_ci	ioc->bfa	= bfa;
24798c2ecf20Sopenharmony_ci	ioc->cbfn	= cbfn;
24808c2ecf20Sopenharmony_ci	ioc->fcmode	= false;
24818c2ecf20Sopenharmony_ci	ioc->pllinit	= false;
24828c2ecf20Sopenharmony_ci	ioc->dbg_fwsave_once = true;
24838c2ecf20Sopenharmony_ci	ioc->iocpf.ioc  = ioc;
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	bfa_ioc_mbox_attach(ioc);
24868c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ioc->notify_q);
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);
24898c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_RESET);
24908c2ecf20Sopenharmony_ci}
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci/* Driver detach time IOC cleanup. */
24938c2ecf20Sopenharmony_civoid
24948c2ecf20Sopenharmony_cibfa_nw_ioc_detach(struct bfa_ioc *ioc)
24958c2ecf20Sopenharmony_ci{
24968c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_DETACH);
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_ci	/* Done with detach, empty the notify_q. */
24998c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ioc->notify_q);
25008c2ecf20Sopenharmony_ci}
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci/**
25038c2ecf20Sopenharmony_ci * bfa_nw_ioc_pci_init - Setup IOC PCI properties.
25048c2ecf20Sopenharmony_ci *
25058c2ecf20Sopenharmony_ci * @ioc:	memory for IOC
25068c2ecf20Sopenharmony_ci * @pcidev:	PCI device information for this IOC
25078c2ecf20Sopenharmony_ci * @clscode:	class code
25088c2ecf20Sopenharmony_ci */
25098c2ecf20Sopenharmony_civoid
25108c2ecf20Sopenharmony_cibfa_nw_ioc_pci_init(struct bfa_ioc *ioc, struct bfa_pcidev *pcidev,
25118c2ecf20Sopenharmony_ci		 enum bfi_pcifn_class clscode)
25128c2ecf20Sopenharmony_ci{
25138c2ecf20Sopenharmony_ci	ioc->clscode	= clscode;
25148c2ecf20Sopenharmony_ci	ioc->pcidev	= *pcidev;
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	/**
25178c2ecf20Sopenharmony_ci	 * Initialize IOC and device personality
25188c2ecf20Sopenharmony_ci	 */
25198c2ecf20Sopenharmony_ci	ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_FC;
25208c2ecf20Sopenharmony_ci	ioc->asic_mode  = BFI_ASIC_MODE_FC;
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	switch (pcidev->device_id) {
25238c2ecf20Sopenharmony_ci	case PCI_DEVICE_ID_BROCADE_CT:
25248c2ecf20Sopenharmony_ci		ioc->asic_gen = BFI_ASIC_GEN_CT;
25258c2ecf20Sopenharmony_ci		ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH;
25268c2ecf20Sopenharmony_ci		ioc->asic_mode  = BFI_ASIC_MODE_ETH;
25278c2ecf20Sopenharmony_ci		ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_CNA;
25288c2ecf20Sopenharmony_ci		ioc->ad_cap_bm = BFA_CM_CNA;
25298c2ecf20Sopenharmony_ci		break;
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	case BFA_PCI_DEVICE_ID_CT2:
25328c2ecf20Sopenharmony_ci		ioc->asic_gen = BFI_ASIC_GEN_CT2;
25338c2ecf20Sopenharmony_ci		if (clscode == BFI_PCIFN_CLASS_FC &&
25348c2ecf20Sopenharmony_ci			pcidev->ssid == BFA_PCI_CT2_SSID_FC) {
25358c2ecf20Sopenharmony_ci			ioc->asic_mode  = BFI_ASIC_MODE_FC16;
25368c2ecf20Sopenharmony_ci			ioc->fcmode = true;
25378c2ecf20Sopenharmony_ci			ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA;
25388c2ecf20Sopenharmony_ci			ioc->ad_cap_bm = BFA_CM_HBA;
25398c2ecf20Sopenharmony_ci		} else {
25408c2ecf20Sopenharmony_ci			ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH;
25418c2ecf20Sopenharmony_ci			ioc->asic_mode  = BFI_ASIC_MODE_ETH;
25428c2ecf20Sopenharmony_ci			if (pcidev->ssid == BFA_PCI_CT2_SSID_FCoE) {
25438c2ecf20Sopenharmony_ci				ioc->port_mode =
25448c2ecf20Sopenharmony_ci				ioc->port_mode_cfg = BFA_MODE_CNA;
25458c2ecf20Sopenharmony_ci				ioc->ad_cap_bm = BFA_CM_CNA;
25468c2ecf20Sopenharmony_ci			} else {
25478c2ecf20Sopenharmony_ci				ioc->port_mode =
25488c2ecf20Sopenharmony_ci				ioc->port_mode_cfg = BFA_MODE_NIC;
25498c2ecf20Sopenharmony_ci				ioc->ad_cap_bm = BFA_CM_NIC;
25508c2ecf20Sopenharmony_ci			}
25518c2ecf20Sopenharmony_ci		}
25528c2ecf20Sopenharmony_ci		break;
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci	default:
25558c2ecf20Sopenharmony_ci		BUG_ON(1);
25568c2ecf20Sopenharmony_ci	}
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci	/**
25598c2ecf20Sopenharmony_ci	 * Set asic specific interfaces.
25608c2ecf20Sopenharmony_ci	 */
25618c2ecf20Sopenharmony_ci	if (ioc->asic_gen == BFI_ASIC_GEN_CT)
25628c2ecf20Sopenharmony_ci		bfa_nw_ioc_set_ct_hwif(ioc);
25638c2ecf20Sopenharmony_ci	else {
25648c2ecf20Sopenharmony_ci		WARN_ON(ioc->asic_gen != BFI_ASIC_GEN_CT2);
25658c2ecf20Sopenharmony_ci		bfa_nw_ioc_set_ct2_hwif(ioc);
25668c2ecf20Sopenharmony_ci		bfa_nw_ioc_ct2_poweron(ioc);
25678c2ecf20Sopenharmony_ci	}
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	bfa_ioc_map_port(ioc);
25708c2ecf20Sopenharmony_ci	bfa_ioc_reg_init(ioc);
25718c2ecf20Sopenharmony_ci}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci/**
25748c2ecf20Sopenharmony_ci * bfa_nw_ioc_mem_claim - Initialize IOC dma memory
25758c2ecf20Sopenharmony_ci *
25768c2ecf20Sopenharmony_ci * @ioc:	memory for IOC
25778c2ecf20Sopenharmony_ci * @dm_kva:	kernel virtual address of IOC dma memory
25788c2ecf20Sopenharmony_ci * @dm_pa:	physical address of IOC dma memory
25798c2ecf20Sopenharmony_ci */
25808c2ecf20Sopenharmony_civoid
25818c2ecf20Sopenharmony_cibfa_nw_ioc_mem_claim(struct bfa_ioc *ioc,  u8 *dm_kva, u64 dm_pa)
25828c2ecf20Sopenharmony_ci{
25838c2ecf20Sopenharmony_ci	/**
25848c2ecf20Sopenharmony_ci	 * dma memory for firmware attribute
25858c2ecf20Sopenharmony_ci	 */
25868c2ecf20Sopenharmony_ci	ioc->attr_dma.kva = dm_kva;
25878c2ecf20Sopenharmony_ci	ioc->attr_dma.pa = dm_pa;
25888c2ecf20Sopenharmony_ci	ioc->attr = (struct bfi_ioc_attr *) dm_kva;
25898c2ecf20Sopenharmony_ci}
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci/* Return size of dma memory required. */
25928c2ecf20Sopenharmony_ciu32
25938c2ecf20Sopenharmony_cibfa_nw_ioc_meminfo(void)
25948c2ecf20Sopenharmony_ci{
25958c2ecf20Sopenharmony_ci	return roundup(sizeof(struct bfi_ioc_attr), BFA_DMA_ALIGN_SZ);
25968c2ecf20Sopenharmony_ci}
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_civoid
25998c2ecf20Sopenharmony_cibfa_nw_ioc_enable(struct bfa_ioc *ioc)
26008c2ecf20Sopenharmony_ci{
26018c2ecf20Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_enables);
26028c2ecf20Sopenharmony_ci	ioc->dbg_fwsave_once = true;
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_ENABLE);
26058c2ecf20Sopenharmony_ci}
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_civoid
26088c2ecf20Sopenharmony_cibfa_nw_ioc_disable(struct bfa_ioc *ioc)
26098c2ecf20Sopenharmony_ci{
26108c2ecf20Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_disables);
26118c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_DISABLE);
26128c2ecf20Sopenharmony_ci}
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci/* Initialize memory for saving firmware trace. */
26158c2ecf20Sopenharmony_civoid
26168c2ecf20Sopenharmony_cibfa_nw_ioc_debug_memclaim(struct bfa_ioc *ioc, void *dbg_fwsave)
26178c2ecf20Sopenharmony_ci{
26188c2ecf20Sopenharmony_ci	ioc->dbg_fwsave = dbg_fwsave;
26198c2ecf20Sopenharmony_ci	ioc->dbg_fwsave_len = ioc->iocpf.auto_recover ? BNA_DBG_FWTRC_LEN : 0;
26208c2ecf20Sopenharmony_ci}
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_cistatic u32
26238c2ecf20Sopenharmony_cibfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr)
26248c2ecf20Sopenharmony_ci{
26258c2ecf20Sopenharmony_ci	return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
26268c2ecf20Sopenharmony_ci}
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci/* Register mailbox message handler function, to be called by common modules */
26298c2ecf20Sopenharmony_civoid
26308c2ecf20Sopenharmony_cibfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
26318c2ecf20Sopenharmony_ci		    bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg)
26328c2ecf20Sopenharmony_ci{
26338c2ecf20Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci	mod->mbhdlr[mc].cbfn	= cbfn;
26368c2ecf20Sopenharmony_ci	mod->mbhdlr[mc].cbarg = cbarg;
26378c2ecf20Sopenharmony_ci}
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_ci/**
26408c2ecf20Sopenharmony_ci * bfa_nw_ioc_mbox_queue - Queue a mailbox command request to firmware.
26418c2ecf20Sopenharmony_ci *
26428c2ecf20Sopenharmony_ci * @ioc:	IOC instance
26438c2ecf20Sopenharmony_ci * @cmd:	Mailbox command
26448c2ecf20Sopenharmony_ci * @cbfn:	callback function
26458c2ecf20Sopenharmony_ci * @cbarg:	arguments to callback
26468c2ecf20Sopenharmony_ci *
26478c2ecf20Sopenharmony_ci * Waits if mailbox is busy. Responsibility of caller to serialize
26488c2ecf20Sopenharmony_ci */
26498c2ecf20Sopenharmony_cibool
26508c2ecf20Sopenharmony_cibfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd,
26518c2ecf20Sopenharmony_ci			bfa_mbox_cmd_cbfn_t cbfn, void *cbarg)
26528c2ecf20Sopenharmony_ci{
26538c2ecf20Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
26548c2ecf20Sopenharmony_ci	u32			stat;
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	cmd->cbfn = cbfn;
26578c2ecf20Sopenharmony_ci	cmd->cbarg = cbarg;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	/**
26608c2ecf20Sopenharmony_ci	 * If a previous command is pending, queue new command
26618c2ecf20Sopenharmony_ci	 */
26628c2ecf20Sopenharmony_ci	if (!list_empty(&mod->cmd_q)) {
26638c2ecf20Sopenharmony_ci		list_add_tail(&cmd->qe, &mod->cmd_q);
26648c2ecf20Sopenharmony_ci		return true;
26658c2ecf20Sopenharmony_ci	}
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci	/**
26688c2ecf20Sopenharmony_ci	 * If mailbox is busy, queue command for poll timer
26698c2ecf20Sopenharmony_ci	 */
26708c2ecf20Sopenharmony_ci	stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
26718c2ecf20Sopenharmony_ci	if (stat) {
26728c2ecf20Sopenharmony_ci		list_add_tail(&cmd->qe, &mod->cmd_q);
26738c2ecf20Sopenharmony_ci		return true;
26748c2ecf20Sopenharmony_ci	}
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	/**
26778c2ecf20Sopenharmony_ci	 * mailbox is free -- queue command to firmware
26788c2ecf20Sopenharmony_ci	 */
26798c2ecf20Sopenharmony_ci	bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
26808c2ecf20Sopenharmony_ci
26818c2ecf20Sopenharmony_ci	return false;
26828c2ecf20Sopenharmony_ci}
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci/* Handle mailbox interrupts */
26858c2ecf20Sopenharmony_civoid
26868c2ecf20Sopenharmony_cibfa_nw_ioc_mbox_isr(struct bfa_ioc *ioc)
26878c2ecf20Sopenharmony_ci{
26888c2ecf20Sopenharmony_ci	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
26898c2ecf20Sopenharmony_ci	struct bfi_mbmsg m;
26908c2ecf20Sopenharmony_ci	int				mc;
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	if (bfa_ioc_msgget(ioc, &m)) {
26938c2ecf20Sopenharmony_ci		/**
26948c2ecf20Sopenharmony_ci		 * Treat IOC message class as special.
26958c2ecf20Sopenharmony_ci		 */
26968c2ecf20Sopenharmony_ci		mc = m.mh.msg_class;
26978c2ecf20Sopenharmony_ci		if (mc == BFI_MC_IOC) {
26988c2ecf20Sopenharmony_ci			bfa_ioc_isr(ioc, &m);
26998c2ecf20Sopenharmony_ci			return;
27008c2ecf20Sopenharmony_ci		}
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci		if ((mc >= BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL))
27038c2ecf20Sopenharmony_ci			return;
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci		mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
27068c2ecf20Sopenharmony_ci	}
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	bfa_ioc_lpu_read_stat(ioc);
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci	/**
27118c2ecf20Sopenharmony_ci	 * Try to send pending mailbox commands
27128c2ecf20Sopenharmony_ci	 */
27138c2ecf20Sopenharmony_ci	bfa_ioc_mbox_poll(ioc);
27148c2ecf20Sopenharmony_ci}
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_civoid
27178c2ecf20Sopenharmony_cibfa_nw_ioc_error_isr(struct bfa_ioc *ioc)
27188c2ecf20Sopenharmony_ci{
27198c2ecf20Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_hbfails);
27208c2ecf20Sopenharmony_ci	bfa_ioc_stats_hb_count(ioc, ioc->hb_count);
27218c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_HWERROR);
27228c2ecf20Sopenharmony_ci}
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci/* return true if IOC is disabled */
27258c2ecf20Sopenharmony_cibool
27268c2ecf20Sopenharmony_cibfa_nw_ioc_is_disabled(struct bfa_ioc *ioc)
27278c2ecf20Sopenharmony_ci{
27288c2ecf20Sopenharmony_ci	return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling) ||
27298c2ecf20Sopenharmony_ci		bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled);
27308c2ecf20Sopenharmony_ci}
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci/* return true if IOC is operational */
27338c2ecf20Sopenharmony_cibool
27348c2ecf20Sopenharmony_cibfa_nw_ioc_is_operational(struct bfa_ioc *ioc)
27358c2ecf20Sopenharmony_ci{
27368c2ecf20Sopenharmony_ci	return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
27378c2ecf20Sopenharmony_ci}
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci/* Add to IOC heartbeat failure notification queue. To be used by common
27408c2ecf20Sopenharmony_ci * modules such as cee, port, diag.
27418c2ecf20Sopenharmony_ci */
27428c2ecf20Sopenharmony_civoid
27438c2ecf20Sopenharmony_cibfa_nw_ioc_notify_register(struct bfa_ioc *ioc,
27448c2ecf20Sopenharmony_ci			struct bfa_ioc_notify *notify)
27458c2ecf20Sopenharmony_ci{
27468c2ecf20Sopenharmony_ci	list_add_tail(&notify->qe, &ioc->notify_q);
27478c2ecf20Sopenharmony_ci}
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci#define BFA_MFG_NAME "QLogic"
27508c2ecf20Sopenharmony_cistatic void
27518c2ecf20Sopenharmony_cibfa_ioc_get_adapter_attr(struct bfa_ioc *ioc,
27528c2ecf20Sopenharmony_ci			 struct bfa_adapter_attr *ad_attr)
27538c2ecf20Sopenharmony_ci{
27548c2ecf20Sopenharmony_ci	struct bfi_ioc_attr *ioc_attr;
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci	ioc_attr = ioc->attr;
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	bfa_ioc_get_adapter_serial_num(ioc, ad_attr->serial_num);
27598c2ecf20Sopenharmony_ci	bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver);
27608c2ecf20Sopenharmony_ci	bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver);
27618c2ecf20Sopenharmony_ci	bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer);
27628c2ecf20Sopenharmony_ci	memcpy(&ad_attr->vpd, &ioc_attr->vpd,
27638c2ecf20Sopenharmony_ci		      sizeof(struct bfa_mfg_vpd));
27648c2ecf20Sopenharmony_ci
27658c2ecf20Sopenharmony_ci	ad_attr->nports = bfa_ioc_get_nports(ioc);
27668c2ecf20Sopenharmony_ci	ad_attr->max_speed = bfa_ioc_speed_sup(ioc);
27678c2ecf20Sopenharmony_ci
27688c2ecf20Sopenharmony_ci	bfa_ioc_get_adapter_model(ioc, ad_attr->model);
27698c2ecf20Sopenharmony_ci	/* For now, model descr uses same model string */
27708c2ecf20Sopenharmony_ci	bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr);
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_ci	ad_attr->card_type = ioc_attr->card_type;
27738c2ecf20Sopenharmony_ci	ad_attr->is_mezz = bfa_mfg_is_mezz(ioc_attr->card_type);
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ci	if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
27768c2ecf20Sopenharmony_ci		ad_attr->prototype = 1;
27778c2ecf20Sopenharmony_ci	else
27788c2ecf20Sopenharmony_ci		ad_attr->prototype = 0;
27798c2ecf20Sopenharmony_ci
27808c2ecf20Sopenharmony_ci	ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
27818c2ecf20Sopenharmony_ci	bfa_nw_ioc_get_mac(ioc, ad_attr->mac);
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_ci	ad_attr->pcie_gen = ioc_attr->pcie_gen;
27848c2ecf20Sopenharmony_ci	ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
27858c2ecf20Sopenharmony_ci	ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;
27868c2ecf20Sopenharmony_ci	ad_attr->asic_rev = ioc_attr->asic_rev;
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver);
27898c2ecf20Sopenharmony_ci}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_cistatic enum bfa_ioc_type
27928c2ecf20Sopenharmony_cibfa_ioc_get_type(struct bfa_ioc *ioc)
27938c2ecf20Sopenharmony_ci{
27948c2ecf20Sopenharmony_ci	if (ioc->clscode == BFI_PCIFN_CLASS_ETH)
27958c2ecf20Sopenharmony_ci		return BFA_IOC_TYPE_LL;
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	BUG_ON(!(ioc->clscode == BFI_PCIFN_CLASS_FC));
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	return (ioc->attr->port_mode == BFI_PORT_MODE_FC)
28008c2ecf20Sopenharmony_ci		? BFA_IOC_TYPE_FC : BFA_IOC_TYPE_FCoE;
28018c2ecf20Sopenharmony_ci}
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_cistatic void
28048c2ecf20Sopenharmony_cibfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, char *serial_num)
28058c2ecf20Sopenharmony_ci{
28068c2ecf20Sopenharmony_ci	memcpy(serial_num,
28078c2ecf20Sopenharmony_ci			(void *)ioc->attr->brcd_serialnum,
28088c2ecf20Sopenharmony_ci			BFA_ADAPTER_SERIAL_NUM_LEN);
28098c2ecf20Sopenharmony_ci}
28108c2ecf20Sopenharmony_ci
28118c2ecf20Sopenharmony_cistatic void
28128c2ecf20Sopenharmony_cibfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc, char *fw_ver)
28138c2ecf20Sopenharmony_ci{
28148c2ecf20Sopenharmony_ci	memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);
28158c2ecf20Sopenharmony_ci}
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_cistatic void
28188c2ecf20Sopenharmony_cibfa_ioc_get_pci_chip_rev(struct bfa_ioc *ioc, char *chip_rev)
28198c2ecf20Sopenharmony_ci{
28208c2ecf20Sopenharmony_ci	BUG_ON(!(chip_rev));
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_ci	memset(chip_rev, 0, BFA_IOC_CHIP_REV_LEN);
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	chip_rev[0] = 'R';
28258c2ecf20Sopenharmony_ci	chip_rev[1] = 'e';
28268c2ecf20Sopenharmony_ci	chip_rev[2] = 'v';
28278c2ecf20Sopenharmony_ci	chip_rev[3] = '-';
28288c2ecf20Sopenharmony_ci	chip_rev[4] = ioc->attr->asic_rev;
28298c2ecf20Sopenharmony_ci	chip_rev[5] = '\0';
28308c2ecf20Sopenharmony_ci}
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_cistatic void
28338c2ecf20Sopenharmony_cibfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc, char *optrom_ver)
28348c2ecf20Sopenharmony_ci{
28358c2ecf20Sopenharmony_ci	memcpy(optrom_ver, ioc->attr->optrom_version,
28368c2ecf20Sopenharmony_ci		      BFA_VERSION_LEN);
28378c2ecf20Sopenharmony_ci}
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_cistatic void
28408c2ecf20Sopenharmony_cibfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer)
28418c2ecf20Sopenharmony_ci{
28428c2ecf20Sopenharmony_ci	strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
28438c2ecf20Sopenharmony_ci}
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_cistatic void
28468c2ecf20Sopenharmony_cibfa_ioc_get_adapter_model(struct bfa_ioc *ioc, char *model)
28478c2ecf20Sopenharmony_ci{
28488c2ecf20Sopenharmony_ci	struct bfi_ioc_attr *ioc_attr;
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci	BUG_ON(!(model));
28518c2ecf20Sopenharmony_ci	memset(model, 0, BFA_ADAPTER_MODEL_NAME_LEN);
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_ci	ioc_attr = ioc->attr;
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_ci	snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",
28568c2ecf20Sopenharmony_ci		BFA_MFG_NAME, ioc_attr->card_type);
28578c2ecf20Sopenharmony_ci}
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_cistatic enum bfa_ioc_state
28608c2ecf20Sopenharmony_cibfa_ioc_get_state(struct bfa_ioc *ioc)
28618c2ecf20Sopenharmony_ci{
28628c2ecf20Sopenharmony_ci	enum bfa_iocpf_state iocpf_st;
28638c2ecf20Sopenharmony_ci	enum bfa_ioc_state ioc_st = bfa_sm_to_state(ioc_sm_table, ioc->fsm);
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	if (ioc_st == BFA_IOC_ENABLING ||
28668c2ecf20Sopenharmony_ci		ioc_st == BFA_IOC_FAIL || ioc_st == BFA_IOC_INITFAIL) {
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci		iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm);
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_ci		switch (iocpf_st) {
28718c2ecf20Sopenharmony_ci		case BFA_IOCPF_SEMWAIT:
28728c2ecf20Sopenharmony_ci			ioc_st = BFA_IOC_SEMWAIT;
28738c2ecf20Sopenharmony_ci			break;
28748c2ecf20Sopenharmony_ci
28758c2ecf20Sopenharmony_ci		case BFA_IOCPF_HWINIT:
28768c2ecf20Sopenharmony_ci			ioc_st = BFA_IOC_HWINIT;
28778c2ecf20Sopenharmony_ci			break;
28788c2ecf20Sopenharmony_ci
28798c2ecf20Sopenharmony_ci		case BFA_IOCPF_FWMISMATCH:
28808c2ecf20Sopenharmony_ci			ioc_st = BFA_IOC_FWMISMATCH;
28818c2ecf20Sopenharmony_ci			break;
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci		case BFA_IOCPF_FAIL:
28848c2ecf20Sopenharmony_ci			ioc_st = BFA_IOC_FAIL;
28858c2ecf20Sopenharmony_ci			break;
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_ci		case BFA_IOCPF_INITFAIL:
28888c2ecf20Sopenharmony_ci			ioc_st = BFA_IOC_INITFAIL;
28898c2ecf20Sopenharmony_ci			break;
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci		default:
28928c2ecf20Sopenharmony_ci			break;
28938c2ecf20Sopenharmony_ci		}
28948c2ecf20Sopenharmony_ci	}
28958c2ecf20Sopenharmony_ci	return ioc_st;
28968c2ecf20Sopenharmony_ci}
28978c2ecf20Sopenharmony_ci
28988c2ecf20Sopenharmony_civoid
28998c2ecf20Sopenharmony_cibfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr)
29008c2ecf20Sopenharmony_ci{
29018c2ecf20Sopenharmony_ci	memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr));
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	ioc_attr->state = bfa_ioc_get_state(ioc);
29048c2ecf20Sopenharmony_ci	ioc_attr->port_id = bfa_ioc_portid(ioc);
29058c2ecf20Sopenharmony_ci	ioc_attr->port_mode = ioc->port_mode;
29068c2ecf20Sopenharmony_ci
29078c2ecf20Sopenharmony_ci	ioc_attr->port_mode_cfg = ioc->port_mode_cfg;
29088c2ecf20Sopenharmony_ci	ioc_attr->cap_bm = ioc->ad_cap_bm;
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci	ioc_attr->ioc_type = bfa_ioc_get_type(ioc);
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_ci	bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
29138c2ecf20Sopenharmony_ci
29148c2ecf20Sopenharmony_ci	ioc_attr->pci_attr.device_id = bfa_ioc_devid(ioc);
29158c2ecf20Sopenharmony_ci	ioc_attr->pci_attr.pcifn = bfa_ioc_pcifn(ioc);
29168c2ecf20Sopenharmony_ci	ioc_attr->def_fn = bfa_ioc_is_default(ioc);
29178c2ecf20Sopenharmony_ci	bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
29188c2ecf20Sopenharmony_ci}
29198c2ecf20Sopenharmony_ci
29208c2ecf20Sopenharmony_ci/* WWN public */
29218c2ecf20Sopenharmony_cistatic u64
29228c2ecf20Sopenharmony_cibfa_ioc_get_pwwn(struct bfa_ioc *ioc)
29238c2ecf20Sopenharmony_ci{
29248c2ecf20Sopenharmony_ci	return ioc->attr->pwwn;
29258c2ecf20Sopenharmony_ci}
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_civoid
29288c2ecf20Sopenharmony_cibfa_nw_ioc_get_mac(struct bfa_ioc *ioc, u8 *mac)
29298c2ecf20Sopenharmony_ci{
29308c2ecf20Sopenharmony_ci	ether_addr_copy(mac, ioc->attr->mac);
29318c2ecf20Sopenharmony_ci}
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci/* Firmware failure detected. Start recovery actions. */
29348c2ecf20Sopenharmony_cistatic void
29358c2ecf20Sopenharmony_cibfa_ioc_recover(struct bfa_ioc *ioc)
29368c2ecf20Sopenharmony_ci{
29378c2ecf20Sopenharmony_ci	pr_crit("Heart Beat of IOC has failed\n");
29388c2ecf20Sopenharmony_ci	bfa_ioc_stats(ioc, ioc_hbfails);
29398c2ecf20Sopenharmony_ci	bfa_ioc_stats_hb_count(ioc, ioc->hb_count);
29408c2ecf20Sopenharmony_ci	bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
29418c2ecf20Sopenharmony_ci}
29428c2ecf20Sopenharmony_ci
29438c2ecf20Sopenharmony_ci/* BFA IOC PF private functions */
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_cistatic void
29468c2ecf20Sopenharmony_cibfa_iocpf_enable(struct bfa_ioc *ioc)
29478c2ecf20Sopenharmony_ci{
29488c2ecf20Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE);
29498c2ecf20Sopenharmony_ci}
29508c2ecf20Sopenharmony_ci
29518c2ecf20Sopenharmony_cistatic void
29528c2ecf20Sopenharmony_cibfa_iocpf_disable(struct bfa_ioc *ioc)
29538c2ecf20Sopenharmony_ci{
29548c2ecf20Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);
29558c2ecf20Sopenharmony_ci}
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_cistatic void
29588c2ecf20Sopenharmony_cibfa_iocpf_fail(struct bfa_ioc *ioc)
29598c2ecf20Sopenharmony_ci{
29608c2ecf20Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);
29618c2ecf20Sopenharmony_ci}
29628c2ecf20Sopenharmony_ci
29638c2ecf20Sopenharmony_cistatic void
29648c2ecf20Sopenharmony_cibfa_iocpf_initfail(struct bfa_ioc *ioc)
29658c2ecf20Sopenharmony_ci{
29668c2ecf20Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);
29678c2ecf20Sopenharmony_ci}
29688c2ecf20Sopenharmony_ci
29698c2ecf20Sopenharmony_cistatic void
29708c2ecf20Sopenharmony_cibfa_iocpf_getattrfail(struct bfa_ioc *ioc)
29718c2ecf20Sopenharmony_ci{
29728c2ecf20Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL);
29738c2ecf20Sopenharmony_ci}
29748c2ecf20Sopenharmony_ci
29758c2ecf20Sopenharmony_cistatic void
29768c2ecf20Sopenharmony_cibfa_iocpf_stop(struct bfa_ioc *ioc)
29778c2ecf20Sopenharmony_ci{
29788c2ecf20Sopenharmony_ci	bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);
29798c2ecf20Sopenharmony_ci}
29808c2ecf20Sopenharmony_ci
29818c2ecf20Sopenharmony_civoid
29828c2ecf20Sopenharmony_cibfa_nw_iocpf_timeout(struct bfa_ioc *ioc)
29838c2ecf20Sopenharmony_ci{
29848c2ecf20Sopenharmony_ci	enum bfa_iocpf_state iocpf_st;
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm);
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	if (iocpf_st == BFA_IOCPF_HWINIT)
29898c2ecf20Sopenharmony_ci		bfa_ioc_poll_fwinit(ioc);
29908c2ecf20Sopenharmony_ci	else
29918c2ecf20Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
29928c2ecf20Sopenharmony_ci}
29938c2ecf20Sopenharmony_ci
29948c2ecf20Sopenharmony_civoid
29958c2ecf20Sopenharmony_cibfa_nw_iocpf_sem_timeout(struct bfa_ioc *ioc)
29968c2ecf20Sopenharmony_ci{
29978c2ecf20Sopenharmony_ci	bfa_ioc_hw_sem_get(ioc);
29988c2ecf20Sopenharmony_ci}
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_cistatic void
30018c2ecf20Sopenharmony_cibfa_ioc_poll_fwinit(struct bfa_ioc *ioc)
30028c2ecf20Sopenharmony_ci{
30038c2ecf20Sopenharmony_ci	u32 fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_ci	if (fwstate == BFI_IOC_DISABLED) {
30068c2ecf20Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);
30078c2ecf20Sopenharmony_ci		return;
30088c2ecf20Sopenharmony_ci	}
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci	if (ioc->iocpf.poll_time >= BFA_IOC_TOV) {
30118c2ecf20Sopenharmony_ci		bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);
30128c2ecf20Sopenharmony_ci	} else {
30138c2ecf20Sopenharmony_ci		ioc->iocpf.poll_time += BFA_IOC_POLL_TOV;
30148c2ecf20Sopenharmony_ci		mod_timer(&ioc->iocpf_timer, jiffies +
30158c2ecf20Sopenharmony_ci			msecs_to_jiffies(BFA_IOC_POLL_TOV));
30168c2ecf20Sopenharmony_ci	}
30178c2ecf20Sopenharmony_ci}
30188c2ecf20Sopenharmony_ci
30198c2ecf20Sopenharmony_ci/*
30208c2ecf20Sopenharmony_ci *	Flash module specific
30218c2ecf20Sopenharmony_ci */
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_ci/*
30248c2ecf20Sopenharmony_ci * FLASH DMA buffer should be big enough to hold both MFG block and
30258c2ecf20Sopenharmony_ci * asic block(64k) at the same time and also should be 2k aligned to
30268c2ecf20Sopenharmony_ci * avoid write segement to cross sector boundary.
30278c2ecf20Sopenharmony_ci */
30288c2ecf20Sopenharmony_ci#define BFA_FLASH_SEG_SZ	2048
30298c2ecf20Sopenharmony_ci#define BFA_FLASH_DMA_BUF_SZ	\
30308c2ecf20Sopenharmony_ci	roundup(0x010000 + sizeof(struct bfa_mfg_block), BFA_FLASH_SEG_SZ)
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_cistatic void
30338c2ecf20Sopenharmony_cibfa_flash_cb(struct bfa_flash *flash)
30348c2ecf20Sopenharmony_ci{
30358c2ecf20Sopenharmony_ci	flash->op_busy = 0;
30368c2ecf20Sopenharmony_ci	if (flash->cbfn)
30378c2ecf20Sopenharmony_ci		flash->cbfn(flash->cbarg, flash->status);
30388c2ecf20Sopenharmony_ci}
30398c2ecf20Sopenharmony_ci
30408c2ecf20Sopenharmony_cistatic void
30418c2ecf20Sopenharmony_cibfa_flash_notify(void *cbarg, enum bfa_ioc_event event)
30428c2ecf20Sopenharmony_ci{
30438c2ecf20Sopenharmony_ci	struct bfa_flash *flash = cbarg;
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci	switch (event) {
30468c2ecf20Sopenharmony_ci	case BFA_IOC_E_DISABLED:
30478c2ecf20Sopenharmony_ci	case BFA_IOC_E_FAILED:
30488c2ecf20Sopenharmony_ci		if (flash->op_busy) {
30498c2ecf20Sopenharmony_ci			flash->status = BFA_STATUS_IOC_FAILURE;
30508c2ecf20Sopenharmony_ci			flash->cbfn(flash->cbarg, flash->status);
30518c2ecf20Sopenharmony_ci			flash->op_busy = 0;
30528c2ecf20Sopenharmony_ci		}
30538c2ecf20Sopenharmony_ci		break;
30548c2ecf20Sopenharmony_ci	default:
30558c2ecf20Sopenharmony_ci		break;
30568c2ecf20Sopenharmony_ci	}
30578c2ecf20Sopenharmony_ci}
30588c2ecf20Sopenharmony_ci
30598c2ecf20Sopenharmony_ci/*
30608c2ecf20Sopenharmony_ci * Send flash write request.
30618c2ecf20Sopenharmony_ci */
30628c2ecf20Sopenharmony_cistatic void
30638c2ecf20Sopenharmony_cibfa_flash_write_send(struct bfa_flash *flash)
30648c2ecf20Sopenharmony_ci{
30658c2ecf20Sopenharmony_ci	struct bfi_flash_write_req *msg =
30668c2ecf20Sopenharmony_ci			(struct bfi_flash_write_req *) flash->mb.msg;
30678c2ecf20Sopenharmony_ci	u32	len;
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_ci	msg->type = be32_to_cpu(flash->type);
30708c2ecf20Sopenharmony_ci	msg->instance = flash->instance;
30718c2ecf20Sopenharmony_ci	msg->offset = be32_to_cpu(flash->addr_off + flash->offset);
30728c2ecf20Sopenharmony_ci	len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ?
30738c2ecf20Sopenharmony_ci	       flash->residue : BFA_FLASH_DMA_BUF_SZ;
30748c2ecf20Sopenharmony_ci	msg->length = be32_to_cpu(len);
30758c2ecf20Sopenharmony_ci
30768c2ecf20Sopenharmony_ci	/* indicate if it's the last msg of the whole write operation */
30778c2ecf20Sopenharmony_ci	msg->last = (len == flash->residue) ? 1 : 0;
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_ci	bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_WRITE_REQ,
30808c2ecf20Sopenharmony_ci		    bfa_ioc_portid(flash->ioc));
30818c2ecf20Sopenharmony_ci	bfa_alen_set(&msg->alen, len, flash->dbuf_pa);
30828c2ecf20Sopenharmony_ci	memcpy(flash->dbuf_kva, flash->ubuf + flash->offset, len);
30838c2ecf20Sopenharmony_ci	bfa_nw_ioc_mbox_queue(flash->ioc, &flash->mb, NULL, NULL);
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ci	flash->residue -= len;
30868c2ecf20Sopenharmony_ci	flash->offset += len;
30878c2ecf20Sopenharmony_ci}
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci/**
30908c2ecf20Sopenharmony_ci * bfa_flash_read_send - Send flash read request.
30918c2ecf20Sopenharmony_ci *
30928c2ecf20Sopenharmony_ci * @cbarg: callback argument
30938c2ecf20Sopenharmony_ci */
30948c2ecf20Sopenharmony_cistatic void
30958c2ecf20Sopenharmony_cibfa_flash_read_send(void *cbarg)
30968c2ecf20Sopenharmony_ci{
30978c2ecf20Sopenharmony_ci	struct bfa_flash *flash = cbarg;
30988c2ecf20Sopenharmony_ci	struct bfi_flash_read_req *msg =
30998c2ecf20Sopenharmony_ci			(struct bfi_flash_read_req *) flash->mb.msg;
31008c2ecf20Sopenharmony_ci	u32	len;
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci	msg->type = be32_to_cpu(flash->type);
31038c2ecf20Sopenharmony_ci	msg->instance = flash->instance;
31048c2ecf20Sopenharmony_ci	msg->offset = be32_to_cpu(flash->addr_off + flash->offset);
31058c2ecf20Sopenharmony_ci	len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ?
31068c2ecf20Sopenharmony_ci	       flash->residue : BFA_FLASH_DMA_BUF_SZ;
31078c2ecf20Sopenharmony_ci	msg->length = be32_to_cpu(len);
31088c2ecf20Sopenharmony_ci	bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_READ_REQ,
31098c2ecf20Sopenharmony_ci		    bfa_ioc_portid(flash->ioc));
31108c2ecf20Sopenharmony_ci	bfa_alen_set(&msg->alen, len, flash->dbuf_pa);
31118c2ecf20Sopenharmony_ci	bfa_nw_ioc_mbox_queue(flash->ioc, &flash->mb, NULL, NULL);
31128c2ecf20Sopenharmony_ci}
31138c2ecf20Sopenharmony_ci
31148c2ecf20Sopenharmony_ci/**
31158c2ecf20Sopenharmony_ci * bfa_flash_intr - Process flash response messages upon receiving interrupts.
31168c2ecf20Sopenharmony_ci *
31178c2ecf20Sopenharmony_ci * @flasharg: flash structure
31188c2ecf20Sopenharmony_ci * @msg: message structure
31198c2ecf20Sopenharmony_ci */
31208c2ecf20Sopenharmony_cistatic void
31218c2ecf20Sopenharmony_cibfa_flash_intr(void *flasharg, struct bfi_mbmsg *msg)
31228c2ecf20Sopenharmony_ci{
31238c2ecf20Sopenharmony_ci	struct bfa_flash *flash = flasharg;
31248c2ecf20Sopenharmony_ci	u32	status;
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_ci	union {
31278c2ecf20Sopenharmony_ci		struct bfi_flash_query_rsp *query;
31288c2ecf20Sopenharmony_ci		struct bfi_flash_write_rsp *write;
31298c2ecf20Sopenharmony_ci		struct bfi_flash_read_rsp *read;
31308c2ecf20Sopenharmony_ci		struct bfi_mbmsg   *msg;
31318c2ecf20Sopenharmony_ci	} m;
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci	m.msg = msg;
31348c2ecf20Sopenharmony_ci
31358c2ecf20Sopenharmony_ci	/* receiving response after ioc failure */
31368c2ecf20Sopenharmony_ci	if (!flash->op_busy && msg->mh.msg_id != BFI_FLASH_I2H_EVENT)
31378c2ecf20Sopenharmony_ci		return;
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ci	switch (msg->mh.msg_id) {
31408c2ecf20Sopenharmony_ci	case BFI_FLASH_I2H_QUERY_RSP:
31418c2ecf20Sopenharmony_ci		status = be32_to_cpu(m.query->status);
31428c2ecf20Sopenharmony_ci		if (status == BFA_STATUS_OK) {
31438c2ecf20Sopenharmony_ci			u32	i;
31448c2ecf20Sopenharmony_ci			struct bfa_flash_attr *attr, *f;
31458c2ecf20Sopenharmony_ci
31468c2ecf20Sopenharmony_ci			attr = (struct bfa_flash_attr *) flash->ubuf;
31478c2ecf20Sopenharmony_ci			f = (struct bfa_flash_attr *) flash->dbuf_kva;
31488c2ecf20Sopenharmony_ci			attr->status = be32_to_cpu(f->status);
31498c2ecf20Sopenharmony_ci			attr->npart = be32_to_cpu(f->npart);
31508c2ecf20Sopenharmony_ci			for (i = 0; i < attr->npart; i++) {
31518c2ecf20Sopenharmony_ci				attr->part[i].part_type =
31528c2ecf20Sopenharmony_ci					be32_to_cpu(f->part[i].part_type);
31538c2ecf20Sopenharmony_ci				attr->part[i].part_instance =
31548c2ecf20Sopenharmony_ci					be32_to_cpu(f->part[i].part_instance);
31558c2ecf20Sopenharmony_ci				attr->part[i].part_off =
31568c2ecf20Sopenharmony_ci					be32_to_cpu(f->part[i].part_off);
31578c2ecf20Sopenharmony_ci				attr->part[i].part_size =
31588c2ecf20Sopenharmony_ci					be32_to_cpu(f->part[i].part_size);
31598c2ecf20Sopenharmony_ci				attr->part[i].part_len =
31608c2ecf20Sopenharmony_ci					be32_to_cpu(f->part[i].part_len);
31618c2ecf20Sopenharmony_ci				attr->part[i].part_status =
31628c2ecf20Sopenharmony_ci					be32_to_cpu(f->part[i].part_status);
31638c2ecf20Sopenharmony_ci			}
31648c2ecf20Sopenharmony_ci		}
31658c2ecf20Sopenharmony_ci		flash->status = status;
31668c2ecf20Sopenharmony_ci		bfa_flash_cb(flash);
31678c2ecf20Sopenharmony_ci		break;
31688c2ecf20Sopenharmony_ci	case BFI_FLASH_I2H_WRITE_RSP:
31698c2ecf20Sopenharmony_ci		status = be32_to_cpu(m.write->status);
31708c2ecf20Sopenharmony_ci		if (status != BFA_STATUS_OK || flash->residue == 0) {
31718c2ecf20Sopenharmony_ci			flash->status = status;
31728c2ecf20Sopenharmony_ci			bfa_flash_cb(flash);
31738c2ecf20Sopenharmony_ci		} else
31748c2ecf20Sopenharmony_ci			bfa_flash_write_send(flash);
31758c2ecf20Sopenharmony_ci		break;
31768c2ecf20Sopenharmony_ci	case BFI_FLASH_I2H_READ_RSP:
31778c2ecf20Sopenharmony_ci		status = be32_to_cpu(m.read->status);
31788c2ecf20Sopenharmony_ci		if (status != BFA_STATUS_OK) {
31798c2ecf20Sopenharmony_ci			flash->status = status;
31808c2ecf20Sopenharmony_ci			bfa_flash_cb(flash);
31818c2ecf20Sopenharmony_ci		} else {
31828c2ecf20Sopenharmony_ci			u32 len = be32_to_cpu(m.read->length);
31838c2ecf20Sopenharmony_ci			memcpy(flash->ubuf + flash->offset,
31848c2ecf20Sopenharmony_ci			       flash->dbuf_kva, len);
31858c2ecf20Sopenharmony_ci			flash->residue -= len;
31868c2ecf20Sopenharmony_ci			flash->offset += len;
31878c2ecf20Sopenharmony_ci			if (flash->residue == 0) {
31888c2ecf20Sopenharmony_ci				flash->status = status;
31898c2ecf20Sopenharmony_ci				bfa_flash_cb(flash);
31908c2ecf20Sopenharmony_ci			} else
31918c2ecf20Sopenharmony_ci				bfa_flash_read_send(flash);
31928c2ecf20Sopenharmony_ci		}
31938c2ecf20Sopenharmony_ci		break;
31948c2ecf20Sopenharmony_ci	case BFI_FLASH_I2H_BOOT_VER_RSP:
31958c2ecf20Sopenharmony_ci	case BFI_FLASH_I2H_EVENT:
31968c2ecf20Sopenharmony_ci		break;
31978c2ecf20Sopenharmony_ci	default:
31988c2ecf20Sopenharmony_ci		WARN_ON(1);
31998c2ecf20Sopenharmony_ci	}
32008c2ecf20Sopenharmony_ci}
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci/*
32038c2ecf20Sopenharmony_ci * Flash memory info API.
32048c2ecf20Sopenharmony_ci */
32058c2ecf20Sopenharmony_ciu32
32068c2ecf20Sopenharmony_cibfa_nw_flash_meminfo(void)
32078c2ecf20Sopenharmony_ci{
32088c2ecf20Sopenharmony_ci	return roundup(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
32098c2ecf20Sopenharmony_ci}
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci/**
32128c2ecf20Sopenharmony_ci * bfa_nw_flash_attach - Flash attach API.
32138c2ecf20Sopenharmony_ci *
32148c2ecf20Sopenharmony_ci * @flash: flash structure
32158c2ecf20Sopenharmony_ci * @ioc: ioc structure
32168c2ecf20Sopenharmony_ci * @dev: device structure
32178c2ecf20Sopenharmony_ci */
32188c2ecf20Sopenharmony_civoid
32198c2ecf20Sopenharmony_cibfa_nw_flash_attach(struct bfa_flash *flash, struct bfa_ioc *ioc, void *dev)
32208c2ecf20Sopenharmony_ci{
32218c2ecf20Sopenharmony_ci	flash->ioc = ioc;
32228c2ecf20Sopenharmony_ci	flash->cbfn = NULL;
32238c2ecf20Sopenharmony_ci	flash->cbarg = NULL;
32248c2ecf20Sopenharmony_ci	flash->op_busy = 0;
32258c2ecf20Sopenharmony_ci
32268c2ecf20Sopenharmony_ci	bfa_nw_ioc_mbox_regisr(flash->ioc, BFI_MC_FLASH, bfa_flash_intr, flash);
32278c2ecf20Sopenharmony_ci	bfa_ioc_notify_init(&flash->ioc_notify, bfa_flash_notify, flash);
32288c2ecf20Sopenharmony_ci	list_add_tail(&flash->ioc_notify.qe, &flash->ioc->notify_q);
32298c2ecf20Sopenharmony_ci}
32308c2ecf20Sopenharmony_ci
32318c2ecf20Sopenharmony_ci/**
32328c2ecf20Sopenharmony_ci * bfa_nw_flash_memclaim - Claim memory for flash
32338c2ecf20Sopenharmony_ci *
32348c2ecf20Sopenharmony_ci * @flash: flash structure
32358c2ecf20Sopenharmony_ci * @dm_kva: pointer to virtual memory address
32368c2ecf20Sopenharmony_ci * @dm_pa: physical memory address
32378c2ecf20Sopenharmony_ci */
32388c2ecf20Sopenharmony_civoid
32398c2ecf20Sopenharmony_cibfa_nw_flash_memclaim(struct bfa_flash *flash, u8 *dm_kva, u64 dm_pa)
32408c2ecf20Sopenharmony_ci{
32418c2ecf20Sopenharmony_ci	flash->dbuf_kva = dm_kva;
32428c2ecf20Sopenharmony_ci	flash->dbuf_pa = dm_pa;
32438c2ecf20Sopenharmony_ci	memset(flash->dbuf_kva, 0, BFA_FLASH_DMA_BUF_SZ);
32448c2ecf20Sopenharmony_ci	dm_kva += roundup(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
32458c2ecf20Sopenharmony_ci	dm_pa += roundup(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
32468c2ecf20Sopenharmony_ci}
32478c2ecf20Sopenharmony_ci
32488c2ecf20Sopenharmony_ci/**
32498c2ecf20Sopenharmony_ci * bfa_nw_flash_get_attr - Get flash attribute.
32508c2ecf20Sopenharmony_ci *
32518c2ecf20Sopenharmony_ci * @flash: flash structure
32528c2ecf20Sopenharmony_ci * @attr: flash attribute structure
32538c2ecf20Sopenharmony_ci * @cbfn: callback function
32548c2ecf20Sopenharmony_ci * @cbarg: callback argument
32558c2ecf20Sopenharmony_ci *
32568c2ecf20Sopenharmony_ci * Return status.
32578c2ecf20Sopenharmony_ci */
32588c2ecf20Sopenharmony_cienum bfa_status
32598c2ecf20Sopenharmony_cibfa_nw_flash_get_attr(struct bfa_flash *flash, struct bfa_flash_attr *attr,
32608c2ecf20Sopenharmony_ci		      bfa_cb_flash cbfn, void *cbarg)
32618c2ecf20Sopenharmony_ci{
32628c2ecf20Sopenharmony_ci	struct bfi_flash_query_req *msg =
32638c2ecf20Sopenharmony_ci			(struct bfi_flash_query_req *) flash->mb.msg;
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	if (!bfa_nw_ioc_is_operational(flash->ioc))
32668c2ecf20Sopenharmony_ci		return BFA_STATUS_IOC_NON_OP;
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	if (flash->op_busy)
32698c2ecf20Sopenharmony_ci		return BFA_STATUS_DEVBUSY;
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci	flash->op_busy = 1;
32728c2ecf20Sopenharmony_ci	flash->cbfn = cbfn;
32738c2ecf20Sopenharmony_ci	flash->cbarg = cbarg;
32748c2ecf20Sopenharmony_ci	flash->ubuf = (u8 *) attr;
32758c2ecf20Sopenharmony_ci
32768c2ecf20Sopenharmony_ci	bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_QUERY_REQ,
32778c2ecf20Sopenharmony_ci		    bfa_ioc_portid(flash->ioc));
32788c2ecf20Sopenharmony_ci	bfa_alen_set(&msg->alen, sizeof(struct bfa_flash_attr), flash->dbuf_pa);
32798c2ecf20Sopenharmony_ci	bfa_nw_ioc_mbox_queue(flash->ioc, &flash->mb, NULL, NULL);
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_ci	return BFA_STATUS_OK;
32828c2ecf20Sopenharmony_ci}
32838c2ecf20Sopenharmony_ci
32848c2ecf20Sopenharmony_ci/**
32858c2ecf20Sopenharmony_ci * bfa_nw_flash_update_part - Update flash partition.
32868c2ecf20Sopenharmony_ci *
32878c2ecf20Sopenharmony_ci * @flash: flash structure
32888c2ecf20Sopenharmony_ci * @type: flash partition type
32898c2ecf20Sopenharmony_ci * @instance: flash partition instance
32908c2ecf20Sopenharmony_ci * @buf: update data buffer
32918c2ecf20Sopenharmony_ci * @len: data buffer length
32928c2ecf20Sopenharmony_ci * @offset: offset relative to the partition starting address
32938c2ecf20Sopenharmony_ci * @cbfn: callback function
32948c2ecf20Sopenharmony_ci * @cbarg: callback argument
32958c2ecf20Sopenharmony_ci *
32968c2ecf20Sopenharmony_ci * Return status.
32978c2ecf20Sopenharmony_ci */
32988c2ecf20Sopenharmony_cienum bfa_status
32998c2ecf20Sopenharmony_cibfa_nw_flash_update_part(struct bfa_flash *flash, u32 type, u8 instance,
33008c2ecf20Sopenharmony_ci			 void *buf, u32 len, u32 offset,
33018c2ecf20Sopenharmony_ci			 bfa_cb_flash cbfn, void *cbarg)
33028c2ecf20Sopenharmony_ci{
33038c2ecf20Sopenharmony_ci	if (!bfa_nw_ioc_is_operational(flash->ioc))
33048c2ecf20Sopenharmony_ci		return BFA_STATUS_IOC_NON_OP;
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	/*
33078c2ecf20Sopenharmony_ci	 * 'len' must be in word (4-byte) boundary
33088c2ecf20Sopenharmony_ci	 */
33098c2ecf20Sopenharmony_ci	if (!len || (len & 0x03))
33108c2ecf20Sopenharmony_ci		return BFA_STATUS_FLASH_BAD_LEN;
33118c2ecf20Sopenharmony_ci
33128c2ecf20Sopenharmony_ci	if (type == BFA_FLASH_PART_MFG)
33138c2ecf20Sopenharmony_ci		return BFA_STATUS_EINVAL;
33148c2ecf20Sopenharmony_ci
33158c2ecf20Sopenharmony_ci	if (flash->op_busy)
33168c2ecf20Sopenharmony_ci		return BFA_STATUS_DEVBUSY;
33178c2ecf20Sopenharmony_ci
33188c2ecf20Sopenharmony_ci	flash->op_busy = 1;
33198c2ecf20Sopenharmony_ci	flash->cbfn = cbfn;
33208c2ecf20Sopenharmony_ci	flash->cbarg = cbarg;
33218c2ecf20Sopenharmony_ci	flash->type = type;
33228c2ecf20Sopenharmony_ci	flash->instance = instance;
33238c2ecf20Sopenharmony_ci	flash->residue = len;
33248c2ecf20Sopenharmony_ci	flash->offset = 0;
33258c2ecf20Sopenharmony_ci	flash->addr_off = offset;
33268c2ecf20Sopenharmony_ci	flash->ubuf = buf;
33278c2ecf20Sopenharmony_ci
33288c2ecf20Sopenharmony_ci	bfa_flash_write_send(flash);
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	return BFA_STATUS_OK;
33318c2ecf20Sopenharmony_ci}
33328c2ecf20Sopenharmony_ci
33338c2ecf20Sopenharmony_ci/**
33348c2ecf20Sopenharmony_ci * bfa_nw_flash_read_part - Read flash partition.
33358c2ecf20Sopenharmony_ci *
33368c2ecf20Sopenharmony_ci * @flash: flash structure
33378c2ecf20Sopenharmony_ci * @type: flash partition type
33388c2ecf20Sopenharmony_ci * @instance: flash partition instance
33398c2ecf20Sopenharmony_ci * @buf: read data buffer
33408c2ecf20Sopenharmony_ci * @len: data buffer length
33418c2ecf20Sopenharmony_ci * @offset: offset relative to the partition starting address
33428c2ecf20Sopenharmony_ci * @cbfn: callback function
33438c2ecf20Sopenharmony_ci * @cbarg: callback argument
33448c2ecf20Sopenharmony_ci *
33458c2ecf20Sopenharmony_ci * Return status.
33468c2ecf20Sopenharmony_ci */
33478c2ecf20Sopenharmony_cienum bfa_status
33488c2ecf20Sopenharmony_cibfa_nw_flash_read_part(struct bfa_flash *flash, u32 type, u8 instance,
33498c2ecf20Sopenharmony_ci		       void *buf, u32 len, u32 offset,
33508c2ecf20Sopenharmony_ci		       bfa_cb_flash cbfn, void *cbarg)
33518c2ecf20Sopenharmony_ci{
33528c2ecf20Sopenharmony_ci	if (!bfa_nw_ioc_is_operational(flash->ioc))
33538c2ecf20Sopenharmony_ci		return BFA_STATUS_IOC_NON_OP;
33548c2ecf20Sopenharmony_ci
33558c2ecf20Sopenharmony_ci	/*
33568c2ecf20Sopenharmony_ci	 * 'len' must be in word (4-byte) boundary
33578c2ecf20Sopenharmony_ci	 */
33588c2ecf20Sopenharmony_ci	if (!len || (len & 0x03))
33598c2ecf20Sopenharmony_ci		return BFA_STATUS_FLASH_BAD_LEN;
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_ci	if (flash->op_busy)
33628c2ecf20Sopenharmony_ci		return BFA_STATUS_DEVBUSY;
33638c2ecf20Sopenharmony_ci
33648c2ecf20Sopenharmony_ci	flash->op_busy = 1;
33658c2ecf20Sopenharmony_ci	flash->cbfn = cbfn;
33668c2ecf20Sopenharmony_ci	flash->cbarg = cbarg;
33678c2ecf20Sopenharmony_ci	flash->type = type;
33688c2ecf20Sopenharmony_ci	flash->instance = instance;
33698c2ecf20Sopenharmony_ci	flash->residue = len;
33708c2ecf20Sopenharmony_ci	flash->offset = 0;
33718c2ecf20Sopenharmony_ci	flash->addr_off = offset;
33728c2ecf20Sopenharmony_ci	flash->ubuf = buf;
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci	bfa_flash_read_send(flash);
33758c2ecf20Sopenharmony_ci
33768c2ecf20Sopenharmony_ci	return BFA_STATUS_OK;
33778c2ecf20Sopenharmony_ci}
3378