/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
 * Copyright(c) 2017 Huawei Technologies Co., Ltd
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 */

#ifndef HINIC_HWDEV_H_
#define HINIC_HWDEV_H_

#include "hinic_port_cmd.h"

/* to use 0-level CLA, page size must be: 64B(wqebb) * 4096(max_q_depth) */
#define HINIC_DEFAULT_WQ_PAGE_SIZE	0x40000
#define HINIC_HW_WQ_PAGE_SIZE		0x1000

#define HINIC_MSG_TO_MGMT_MAX_LEN	2016

#define HINIC_MGMT_STATUS_ERR_OK          0   /* Ok */
#define HINIC_MGMT_STATUS_ERR_PARAM       1   /* Invalid parameter */
#define HINIC_MGMT_STATUS_ERR_FAILED      2   /* Operation failed */
#define HINIC_MGMT_STATUS_ERR_PORT        3   /* Invalid port */
#define HINIC_MGMT_STATUS_ERR_TIMEOUT     4   /* Operation time out */
#define HINIC_MGMT_STATUS_ERR_NOMATCH     5   /* Version not match */
#define HINIC_MGMT_STATUS_ERR_EXIST       6   /* Entry exists */
#define HINIC_MGMT_STATUS_ERR_NOMEM       7   /* Out of memory */
#define HINIC_MGMT_STATUS_ERR_INIT        8   /* Feature not initialized */
#define HINIC_MGMT_STATUS_ERR_FAULT       9   /* Invalid address */
#define HINIC_MGMT_STATUS_ERR_PERM        10  /* Operation not permitted */
#define HINIC_MGMT_STATUS_ERR_EMPTY       11  /* Table empty */
#define HINIC_MGMT_STATUS_ERR_FULL        12  /* Table full */
#define HINIC_MGMT_STATUS_ERR_NOT_FOUND   13  /* Not found */
#define HINIC_MGMT_STATUS_ERR_BUSY        14  /* Device or resource busy */
#define HINIC_MGMT_STATUS_ERR_RESOURCE    15  /* No resources for operation */
#define HINIC_MGMT_STATUS_ERR_CONFIG      16  /* Invalid configuration */
#define HINIC_MGMT_STATUS_ERR_UNAVAIL     17  /* Feature unavailable */
#define HINIC_MGMT_STATUS_ERR_CRC         18  /* CRC check failed */
#define HINIC_MGMT_STATUS_ERR_NXIO        19  /* No such device or address */
#define HINIC_MGMT_STATUS_ERR_ROLLBACK    20  /* Chip rollback fail */
#define HINIC_MGMT_STATUS_ERR_LEN         32  /* Length too short or too long */
#define HINIC_MGMT_STATUS_ERR_UNSUPPORT   0xFF /* Feature not supported */

#define HINIC_CHIP_PRESENT		1
#define HINIC_CHIP_ABSENT		0

struct cfg_mgmt_info;
struct rdma_comp_resource;

struct hinic_hwif;
struct hinic_nic_io;
struct hinic_wqs;
struct hinic_aeqs;
struct hinic_ceqs;
struct hinic_mbox_func_to_func;
struct hinic_msg_pf_to_mgmt;
struct hinic_cmdqs;
struct hinic_multi_host_mgmt;

struct hinic_root_ctxt {
	u8	status;
	u8	version;
	u8	rsvd0[6];

	u16	func_idx;
	u16	rsvd1;
	u8	set_cmdq_depth;
	u8	cmdq_depth;
	u8	lro_en;
	u8	rsvd2;
	u8	ppf_idx;
	u8	rsvd3;
	u16	rq_depth;
	u16	rx_buf_sz;
	u16	sq_depth;
};

struct hinic_page_addr {
	void *virt_addr;
	u64 phys_addr;
};

struct mqm_addr_trans_tbl_info {
	u32 chunk_num;
	u32 search_gpa_num;
	u32 page_size;
	u32 page_num;
	struct hinic_page_addr *brm_srch_page_addr;
};

#define HINIC_PCIE_LINK_DOWN		0xFFFFFFFF

#define HINIC_DEV_ACTIVE_FW_TIMEOUT	(35 * 1000)
#define HINIC_DEV_BUSY_ACTIVE_FW	0xFE

#define HINIC_HW_WQ_NAME		"hinic_hardware"
#define HINIC_HEARTBEAT_PERIOD		1000
#define HINIC_HEARTBEAT_START_EXPIRE	5000

#define HINIC_CHIP_ERROR_TYPE_MAX	1024
#define HINIC_CHIP_FAULT_SIZE		\
	(HINIC_NODE_ID_MAX * FAULT_LEVEL_MAX * HINIC_CHIP_ERROR_TYPE_MAX)

enum hinic_node_id {
	HINIC_NODE_ID_CPI = 0,
	HINIC_NODE_ID_IPSU = 4,
	HINIC_NODE_ID_MGMT_HOST = 21, /* Host CPU send API to uP */
	HINIC_NODE_ID_MAX = 22
};

#define HINIC_HWDEV_INIT_MODES_MASK	((1UL << HINIC_HWDEV_ALL_INITED) - 1)

enum hinic_hwdev_func_state {
	HINIC_HWDEV_FUNC_INITED = HINIC_HWDEV_ALL_INITED,

	HINIC_HWDEV_FUNC_DEINIT,

	HINIC_HWDEV_STATE_BUSY = 31,
};

struct hinic_cqm_stats {
	atomic_t cqm_cmd_alloc_cnt;
	atomic_t cqm_cmd_free_cnt;
	atomic_t cqm_send_cmd_box_cnt;
	atomic_t cqm_send_cmd_imm_cnt;
	atomic_t cqm_db_addr_alloc_cnt;
	atomic_t cqm_db_addr_free_cnt;

	atomic_t cqm_fc_srq_create_cnt;
	atomic_t cqm_srq_create_cnt;
	atomic_t cqm_rq_create_cnt;

	atomic_t cqm_qpc_mpt_create_cnt;
	atomic_t cqm_nonrdma_queue_create_cnt;
	atomic_t cqm_rdma_queue_create_cnt;
	atomic_t cqm_rdma_table_create_cnt;

	atomic_t cqm_qpc_mpt_delete_cnt;
	atomic_t cqm_nonrdma_queue_delete_cnt;
	atomic_t cqm_rdma_queue_delete_cnt;
	atomic_t cqm_rdma_table_delete_cnt;

	atomic_t cqm_func_timer_clear_cnt;
	atomic_t cqm_func_hash_buf_clear_cnt;

	atomic_t cqm_scq_callback_cnt;
	atomic_t cqm_ecq_callback_cnt;
	atomic_t cqm_nocq_callback_cnt;
	atomic_t cqm_aeq_callback_cnt[112];
};

struct hinic_link_event_stats {
	atomic_t link_down_stats;
	atomic_t link_up_stats;
};

struct hinic_fault_event_stats {
	atomic_t chip_fault_stats[HINIC_NODE_ID_MAX][FAULT_LEVEL_MAX];
	atomic_t fault_type_stat[FAULT_TYPE_MAX];
	atomic_t pcie_fault_stats;
};

struct hinic_hw_stats {
	atomic_t heart_lost_stats;
	atomic_t nic_ucode_event_stats[HINIC_NIC_FATAL_ERROR_MAX];
	struct hinic_cqm_stats cqm_stats;
	struct hinic_link_event_stats link_event_stats;
	struct hinic_fault_event_stats fault_event_stats;
};

#define HINIC_NORMAL_HOST_CAP	(HINIC_FUNC_MGMT | HINIC_FUNC_PORT | \
				 HINIC_FUNC_SUPP_RATE_LIMIT | \
				 HINIC_FUNC_SUPP_DFX_REG | \
				 HINIC_FUNC_SUPP_RX_MODE | \
				 HINIC_FUNC_SUPP_SET_VF_MAC_VLAN | \
				 HINIC_FUNC_SUPP_CHANGE_MAC | \
				 HINIC_FUNC_SUPP_ENCAP_TSO_CSUM)
#define HINIC_MULTI_BM_MASTER	(HINIC_FUNC_MGMT | HINIC_FUNC_PORT | \
				 HINIC_FUNC_SUPP_DFX_REG | \
				 HINIC_FUNC_SUPP_RX_MODE | \
				 HINIC_FUNC_SUPP_SET_VF_MAC_VLAN | \
				 HINIC_FUNC_SUPP_CHANGE_MAC)
#define HINIC_MULTI_BM_SLAVE	(HINIC_FUNC_SRIOV_EN_DFLT | \
				 HINIC_FUNC_SRIOV_NUM_FIX | \
				 HINIC_FUNC_FORCE_LINK_UP | \
				 HINIC_FUNC_OFFLOAD_OVS_UNSUPP)
#define HINIC_MULTI_VM_MASTER	(HINIC_FUNC_MGMT | HINIC_FUNC_PORT | \
				 HINIC_FUNC_SUPP_DFX_REG | \
				 HINIC_FUNC_SUPP_RX_MODE | \
				 HINIC_FUNC_SUPP_SET_VF_MAC_VLAN | \
				 HINIC_FUNC_SUPP_CHANGE_MAC)
#define HINIC_MULTI_VM_SLAVE	(HINIC_FUNC_MGMT | \
				 HINIC_FUNC_SUPP_DFX_REG | \
				 HINIC_FUNC_SRIOV_EN_DFLT | \
				 HINIC_FUNC_SUPP_RX_MODE | \
				 HINIC_FUNC_SUPP_CHANGE_MAC | \
				 HINIC_FUNC_OFFLOAD_OVS_UNSUPP)

#define MULTI_HOST_CHIP_MODE_SHIFT		0
#define MULTI_HOST_MASTER_MBX_STS_SHIFT		0x4
#define MULTI_HOST_PRIV_DATA_SHIFT		0x8

#define MULTI_HOST_CHIP_MODE_MASK		0xF
#define MULTI_HOST_MASTER_MBX_STS_MASK		0xF
#define MULTI_HOST_PRIV_DATA_MASK		0xFFFF

#define MULTI_HOST_REG_SET(val, member)			\
				(((val) & MULTI_HOST_##member##_MASK) \
					<< MULTI_HOST_##member##_SHIFT)
#define MULTI_HOST_REG_GET(val, member)			\
				(((val) >> MULTI_HOST_##member##_SHIFT) \
					& MULTI_HOST_##member##_MASK)
#define MULTI_HOST_REG_CLEAR(val, member)	\
				((val) & (~(MULTI_HOST_##member##_MASK \
					<< MULTI_HOST_##member##_SHIFT)))

#define HINIC_BOARD_TYPE_MULTI_HOST_ETH_25GE	12

/* new version of roce qp not limited by power of 2 */
#define HINIC_CMD_VER_ROCE_QP			1
/* new version for add function id in multi-host */
#define HINIC_CMD_VER_FUNC_ID			2

struct hinic_hwdev {
	void *adapter_hdl;  /* pointer to hinic_pcidev or NDIS_Adapter */
	void *pcidev_hdl;   /* pointer to pcidev or Handler */
	void *dev_hdl;      /* pointer to pcidev->dev or Handler, for
			     * sdk_err() or dma_alloc()
			     */
	u32 wq_page_size;

	void *cqm_hdl;
	void *chip_node;

	struct hinic_hwif *hwif; /* include void __iomem *bar */
	struct hinic_nic_io *nic_io;
	struct cfg_mgmt_info *cfg_mgmt;
	struct rdma_comp_resource  *rdma_comp_res;
	struct hinic_wqs *wqs;	/* for FC slq */
	struct mqm_addr_trans_tbl_info mqm_att;

	struct hinic_aeqs *aeqs;
	struct hinic_ceqs *ceqs;

	struct hinic_mbox_func_to_func *func_to_func;

	struct hinic_msg_pf_to_mgmt *pf_to_mgmt;
	struct hinic_clp_pf_to_mgmt *clp_pf_to_mgmt;

	struct hinic_cmdqs *cmdqs;

	struct hinic_page_addr page_pa0;
	struct hinic_page_addr page_pa1;

	hinic_event_handler event_callback;
	void *event_pri_handle;

	struct work_struct timer_work;
	struct workqueue_struct *workq;
	struct timer_list heartbeat_timer;
	/* true represent heartbeat lost, false represent heartbeat restore */
	u32 heartbeat_lost;
	int chip_present_flag;
	struct hinic_hw_stats hw_stats;
	u8 *chip_fault_stats;

	u32 statufull_ref_cnt;
	ulong func_state;

	u64 feature_cap;	/* enum hinic_func_cap */
	enum hinic_func_mode	func_mode;

	struct hinic_multi_host_mgmt	*mhost_mgmt;

	/* In bmgw x86 host, driver can't send message to mgmt cpu directly,
	 * need to trasmit message ppf mbox to bmgw arm host.
	 */
	struct semaphore ppf_sem;
	void *ppf_hwdev;

	struct semaphore func_sem;
	int func_ref;
	struct hinic_board_info board_info;
#define MGMT_VERSION_MAX_LEN	32
	u8	mgmt_ver[MGMT_VERSION_MAX_LEN];
	u64	fw_support_func_flag;
};

int hinic_init_comm_ch(struct hinic_hwdev *hwdev);

void hinic_uninit_comm_ch(struct hinic_hwdev *hwdev);

int hinic_ppf_ext_db_init(void *dev);

int hinic_ppf_ext_db_deinit(void *dev);

enum hinic_set_arm_type {
	HINIC_SET_ARM_CMDQ,
	HINIC_SET_ARM_SQ,
	HINIC_SET_ARM_TYPE_NUM,
};

int hinic_set_arm_bit(void *hwdev, enum hinic_set_arm_type q_type, u16 q_id);

void hinic_set_chip_present(void *hwdev);
void hinic_force_complete_all(void *hwdev);

void hinic_init_heartbeat(struct hinic_hwdev *hwdev);
void hinic_destroy_heartbeat(struct hinic_hwdev *hwdev);

u8 hinic_nic_sw_aeqe_handler(void *handle, u8 event, u64 data);

int hinic_enable_fast_recycle(void *hwdev, bool enable);
int hinic_l2nic_reset_base(struct hinic_hwdev *hwdev, u16 reset_flag);

enum l2nic_resource_type {
	RES_TYPE_NIC_FUNC = 0,
	RES_TYPE_FLUSH_BIT,
	RES_TYPE_PF_BW_CFG,
	RES_TYPE_MQM,
	RES_TYPE_SMF,
	RES_TYPE_CMDQ_ROOTCTX,
	RES_TYPE_SQ_CI_TABLE,
	RES_TYPE_CEQ,
	RES_TYPE_MBOX,
	RES_TYPE_AEQ,
};

void hinic_notify_dcb_state_event(struct hinic_hwdev *hwdev,
				  struct hinic_dcb_state *dcb_state);

int hinic_pf_msg_to_mgmt_sync(void *hwdev, enum hinic_mod_type mod, u8 cmd,
			      void *buf_in, u16 in_size,
			      void *buf_out, u16 *out_size, u32 timeout);

int hinic_pf_send_clp_cmd(void *hwdev, enum hinic_mod_type mod, u8 cmd,
			  void *buf_in, u16 in_size,
			  void *buf_out, u16 *out_size);

int hinic_get_bios_pf_bw_limit(void *hwdev, u32 *pf_bw_limit);

bool hinic_mgmt_event_ack_first(u8 mod, u8 cmd);

int hinic_set_wq_page_size(struct hinic_hwdev *hwdev, u16 func_idx,
			   u32 page_size);

int hinic_phy_init_status_judge(void *hwdev);

int hinic_hilink_info_show(struct hinic_hwdev *hwdev);
int hinic_api_csr_rd32(void *hwdev, u8 dest, u32 addr, u32 *val);
int hinic_api_csr_wr32(void *hwdev, u8 dest, u32 addr, u32 val);

int hinic_ppf_process_mbox_msg(struct hinic_hwdev *hwdev, u16 pf_idx, u16 vf_id,
			       enum hinic_mod_type mod, u8 cmd, void *buf_in,
			       u16 in_size, void *buf_out, u16 *out_size);

#define HINIC_SDI_MODE_UNKNOWN		0
#define HINIC_SDI_MODE_BM		1
#define HINIC_SDI_MODE_VM		2
#define HINIC_SDI_MODE_MAX		3
int hinic_get_sdi_mode(struct hinic_hwdev *hwdev, u16 *cur_mode);

#endif
