From 0c4c3ee2e4947ad6ec346dc37fa133f4fecafd76 Mon Sep 17 00:00:00 2001 From: Steven Song Date: Fri, 11 Aug 2023 14:57:22 +0800 Subject: [PATCH] Net: ethernet: Support management channel of the host tool in 3snic 3s9xx network driver 3snic inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I7MVPN -------------------------------- The driver supports 3snic 3s9xx serial network cards (100GE (40GE compatible)-3S930 and 25GE (10GE compatible)-3S910/3S920). Feature: 1. Support firmware update and active 2. Support online log collection 3. Network card information query: Gemini information, version, Optical module information, tx/rx queue information, Serdes information, bond information, etc 4. Support Relevant parameter settings: tx speed limit, port rate, port adaptive mode, setting lro aggregation time and number, Factory reset, etc Reviewed-by: Chen Mou Reviewed-by: Wan Renyong Reviewed-by: Yang Gan Reviewed-by: Wen Liang Signed-off-by: Steven Song --- drivers/net/ethernet/3snic/sssnic/hw/Makefile | 9 +- .../3snic/sssnic/hw/include/sss_adapter.h | 13 +- .../3snic/sssnic/hw/include/sss_adm_info.h | 2 +- .../3snic/sssnic/hw/include/sss_csr.h | 66 +- .../3snic/sssnic/hw/include/sss_hwdev.h | 16 + .../sssnic/hw/include/sss_mgmt_channel.h | 30 +- .../3snic/sssnic/hw/include/sss_mgmt_info.h | 5 + .../3snic/sssnic/hw/sss_adapter_mgmt.c | 443 +++++++++- .../3snic/sssnic/hw/sss_adapter_mgmt.h | 57 ++ .../ethernet/3snic/sssnic/hw/sss_hw_main.c | 1 - .../ethernet/3snic/sssnic/hw/sss_hwdev_cap.c | 4 +- .../3snic/sssnic/hw/sss_hwdev_export.c | 35 +- .../ethernet/3snic/sssnic/hw/sss_hwdev_link.c | 1 + .../3snic/sssnic/hw/sss_hwdev_mgmt_channel.c | 6 +- .../ethernet/3snic/sssnic/hw/sss_hwif_adm.c | 356 ++++++-- .../ethernet/3snic/sssnic/hw/sss_hwif_adm.h | 4 + .../3snic/sssnic/hw/sss_hwif_adm_common.h | 56 ++ .../3snic/sssnic/hw/sss_hwif_adm_init.c | 131 ++- .../ethernet/3snic/sssnic/hw/sss_hwif_ctrlq.c | 73 +- .../3snic/sssnic/hw/sss_hwif_export.c | 9 + .../3snic/sssnic/hw/sss_hwif_mbx_init.c | 23 +- .../ethernet/3snic/sssnic/hw/sss_pci_error.c | 2 +- .../ethernet/3snic/sssnic/hw/sss_pci_probe.c | 14 + .../ethernet/3snic/sssnic/hw/sss_pci_remove.c | 5 + .../ethernet/3snic/sssnic/hw/tool/sss_tool.h | 30 + .../3snic/sssnic/hw/tool/sss_tool_chip.c | 802 ++++++++++++++++++ .../3snic/sssnic/hw/tool/sss_tool_chip.h | 15 + .../3snic/sssnic/hw/tool/sss_tool_hw.h | 212 +++++ .../3snic/sssnic/hw/tool/sss_tool_main.c | 736 ++++++++++++++++ .../3snic/sssnic/hw/tool/sss_tool_sdk.c | 527 ++++++++++++ .../3snic/sssnic/hw/tool/sss_tool_sdk.h | 16 + .../3snic/sssnic/hw/tool/sss_tool_sm.c | 383 +++++++++ .../3snic/sssnic/hw/tool/sss_tool_sm.h | 21 + .../3snic/sssnic/include/hw/sss_hw_export.h | 4 + .../3snic/sssnic/include/hw/sss_hw_mbx.h | 2 +- .../sssnic/include/hw/sss_hw_statistics.h | 10 +- .../3snic/sssnic/include/hw/sss_hw_svc_cap.h | 2 +- .../3snic/sssnic/include/hw/sss_hwif_export.h | 2 + .../3snic/sssnic/include/sss_tool_comm.h | 115 +++ .../net/ethernet/3snic/sssnic/nic/Makefile | 11 +- .../nic/include/sss_nic_cfg_mag_define.h | 2 + .../sssnic/nic/include/sss_nic_tx_define.h | 2 +- .../ethernet/3snic/sssnic/nic/sss_nic_cfg.c | 39 + .../ethernet/3snic/sssnic/nic/sss_nic_cfg.h | 2 + .../ethernet/3snic/sssnic/nic/sss_nic_dcb.c | 4 +- .../ethernet/3snic/sssnic/nic/sss_nic_dcb.h | 7 + .../sssnic/nic/sss_nic_ethtool_stats_api.c | 97 +++ .../sssnic/nic/sss_nic_ethtool_stats_api.h | 2 + .../ethernet/3snic/sssnic/nic/sss_nic_event.c | 2 +- .../3snic/sssnic/nic/sss_nic_mag_cfg.c | 23 +- .../3snic/sssnic/nic/sss_nic_mag_cfg.h | 7 + .../ethernet/3snic/sssnic/nic/sss_nic_main.c | 3 + .../3snic/sssnic/nic/sss_nic_netdev_ops.c | 2 +- .../3snic/sssnic/nic/sss_nic_netdev_ops_api.h | 2 + .../3snic/sssnic/nic/tool/sss_tool_nic.h | 112 +++ .../3snic/sssnic/nic/tool/sss_tool_nic_dcb.c | 458 ++++++++++ .../3snic/sssnic/nic/tool/sss_tool_nic_dcb.h | 17 + .../3snic/sssnic/nic/tool/sss_tool_nic_func.c | 109 +++ .../3snic/sssnic/nic/tool/sss_tool_nic_func.h | 10 + .../sssnic/nic/tool/sss_tool_nic_phy_attr.c | 416 +++++++++ .../sssnic/nic/tool/sss_tool_nic_phy_attr.h | 38 + .../sssnic/nic/tool/sss_tool_nic_qp_info.c | 324 +++++++ .../sssnic/nic/tool/sss_tool_nic_qp_info.h | 29 + .../sssnic/nic/tool/sss_tool_nic_stats.c | 137 +++ .../sssnic/nic/tool/sss_tool_nic_stats.h | 17 + 65 files changed, 5868 insertions(+), 242 deletions(-) create mode 100644 drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool.h create mode 100644 drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_chip.c create mode 100644 drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_chip.h create mode 100644 drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_hw.h create mode 100644 drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_main.c create mode 100644 drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sdk.c create mode 100644 drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sdk.h create mode 100644 drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sm.c create mode 100644 drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sm.h create mode 100644 drivers/net/ethernet/3snic/sssnic/include/sss_tool_comm.h create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic.h create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_dcb.c create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_dcb.h create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_func.c create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_func.h create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_phy_attr.c create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_phy_attr.h create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_qp_info.c create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_qp_info.h create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_stats.c create mode 100644 drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_stats.h diff --git a/drivers/net/ethernet/3snic/sssnic/hw/Makefile b/drivers/net/ethernet/3snic/sssnic/hw/Makefile index f0016d354ce8..989527da46a3 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/Makefile +++ b/drivers/net/ethernet/3snic/sssnic/hw/Makefile @@ -1,8 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2023 3SNIC # +SYS_TIME=$(shell date +%Y-%m-%d_%H:%M:%S) +ccflags-y += -D __TIME_STR__=\"$(SYS_TIME)\" ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/hw +ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/hw/tool ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/include ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/include/hw ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/include/kernel @@ -45,4 +48,8 @@ sssdk-y := sss_hw_main.o \ sss_common.o \ sss_wq.o \ sss_hwif_ceq.o \ - sss_adapter_mgmt.o + sss_adapter_mgmt.o \ + ./tool/sss_tool_main.o \ + ./tool/sss_tool_chip.o \ + ./tool/sss_tool_sdk.o \ + ./tool/sss_tool_sm.o diff --git a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_adapter.h b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_adapter.h index a8b788c72dfe..afc5ff37f4a3 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_adapter.h +++ b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_adapter.h @@ -15,7 +15,7 @@ #include "sss_hw_svc_cap.h" #include "sss_sriov_info.h" -#define SSS_MAX_FUNCTION_NUM 4096 +#define SSS_MAX_FUNC 4096 struct sss_card_node { struct list_head node; @@ -23,7 +23,10 @@ struct sss_card_node { char chip_name[IFNAMSIZ]; u8 bus_id; u8 resvd[7]; + u16 func_num; atomic_t channel_timeout_cnt; + void *func_handle_array[SSS_MAX_FUNC]; + void *dbgtool_info; }; /* Structure pcidev private */ @@ -57,6 +60,11 @@ struct sss_pci_adapter { struct sss_sriov_info sriov_info; + atomic_t ref_cnt; + + atomic_t uld_ref_cnt[SSS_SERVICE_TYPE_MAX]; + spinlock_t uld_lock; /* protect uld probe and remove */ + /* set when uld driver processing event */ unsigned long uld_run_state; @@ -65,7 +73,6 @@ struct sss_pci_adapter { /* lock for attach/detach uld */ struct mutex uld_attach_mutex; - /* spin lock for uld_attach_state access */ - spinlock_t dettach_uld_lock; + spinlock_t dettach_uld_lock; /* spin lock for uld_attach_state access */ }; #endif diff --git a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_adm_info.h b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_adm_info.h index 688b7e22bc40..fbcf0b007194 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_adm_info.h +++ b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_adm_info.h @@ -93,7 +93,7 @@ struct sss_adm_msg { u32 ci; struct semaphore sem; - + spinlock_t async_lock; /* protect adm msg async and sync */ dma_addr_t wb_state_paddr; dma_addr_t head_elem_paddr; diff --git a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_csr.h b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_csr.h index e307cd6a3382..08e438995796 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_csr.h +++ b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_csr.h @@ -4,11 +4,11 @@ #ifndef SSS_CSR_H #define SSS_CSR_H -#define SSS_CSR_CFG_FLAG 0x40000000 +#define SSS_CSR_CFG_FLAG 0x40000000 #define SSS_MGMT_FLAG 0xC0000000 -#define SSS_CSR_FLAG_MASK 0x3FFFFFFF +#define SSS_CSR_FLAG_MASK 0x3FFFFFFF #define SSS_VF_CFG_REG_OFFSET 0x2000 @@ -25,7 +25,7 @@ #define SSS_CSR_HW_ATTR6_ADDR (SSS_CSR_CFG_FLAG + 0x18) #define SSS_HW_CSR_MBX_DATA_OFF 0x80 -#define SSS_HW_CSR_MBX_CTRL_OFF (SSS_CSR_CFG_FLAG + 0x0100) +#define SSS_HW_CSR_MBX_CTRL_OFF (SSS_CSR_CFG_FLAG + 0x0100) #define SSS_HW_CSR_MBX_INT_OFFSET_OFF (SSS_CSR_CFG_FLAG + 0x0104) #define SSS_HW_CSR_MBX_RES_H_OFF (SSS_CSR_CFG_FLAG + 0x0108) #define SSS_HW_CSR_MBX_RES_L_OFF (SSS_CSR_CFG_FLAG + 0x010C) @@ -46,27 +46,41 @@ (SSS_CSR_HW_PPF_ELECT_BASE_ADDR + \ (host_id) * SSS_CSR_HW_PPF_ELECT_PORT_STRIDE) -#define SSS_CSR_DMA_ATTR_TBL_ADDR (SSS_CSR_CFG_FLAG + 0x380) +#define SSS_CSR_DMA_ATTR_TBL_ADDR (SSS_CSR_CFG_FLAG + 0x380) #define SSS_CSR_DMA_ATTR_INDIR_ID_ADDR (SSS_CSR_CFG_FLAG + 0x390) +/* CLP registers */ +#define SSS_BAR3_CLP_BASE_ADDR (SSS_MGMT_FLAG + 0x0000) + +#define SSS_UCPU_CLP_SIZE_REG (SSS_HOST_CSR_BASE_ADDR + 0x40) +#define SSS_UCPU_CLP_REQBASE_REG (SSS_HOST_CSR_BASE_ADDR + 0x44) +#define SSS_UCPU_CLP_RSPBASE_REG (SSS_HOST_CSR_BASE_ADDR + 0x48) +#define SSS_UCPU_CLP_REQ_REG (SSS_HOST_CSR_BASE_ADDR + 0x4c) +#define SSS_UCPU_CLP_RSP_REG (SSS_HOST_CSR_BASE_ADDR + 0x50) +#define SSS_CLP_REG(member) (SSS_UCPU_CLP_##member##_REG) + +#define SSS_CLP_REQ_DATA SSS_BAR3_CLP_BASE_ADDR +#define SSS_CLP_RSP_DATA (SSS_BAR3_CLP_BASE_ADDR + 0x1000) +#define SSS_CLP_DATA(member) (SSS_CLP_##member##_DATA) + /* MSI-X registers */ #define SSS_CSR_MSIX_INDIR_ID_ADDR (SSS_CSR_CFG_FLAG + 0x310) #define SSS_CSR_MSIX_CTRL_ADDR (SSS_CSR_CFG_FLAG + 0x300) #define SSS_CSR_MSIX_CNT_ADDR (SSS_CSR_CFG_FLAG + 0x304) -#define SSS_CSR_FUNC_MSI_CLR_WR_ADDR (SSS_CSR_CFG_FLAG + 0x58) +#define SSS_CSR_FUNC_MSI_CLR_WR_ADDR (SSS_CSR_CFG_FLAG + 0x58) #define SSS_MSI_CLR_INDIR_RESEND_TIMER_CLR_SHIFT 0 -#define SSS_MSI_CLR_INDIR_INT_MSK_SET_SHIFT 1 -#define SSS_MSI_CLR_INDIR_INT_MSK_CLR_SHIFT 2 +#define SSS_MSI_CLR_INDIR_INT_MSK_SET_SHIFT 1 +#define SSS_MSI_CLR_INDIR_INT_MSK_CLR_SHIFT 2 #define SSS_MSI_CLR_INDIR_AUTO_MSK_SET_SHIFT 3 #define SSS_MSI_CLR_INDIR_AUTO_MSK_CLR_SHIFT 4 #define SSS_MSI_CLR_INDIR_SIMPLE_INDIR_ID_SHIFT 22 #define SSS_MSI_CLR_INDIR_RESEND_TIMER_CLR_MASK 0x1U -#define SSS_MSI_CLR_INDIR_INT_MSK_SET_MASK 0x1U -#define SSS_MSI_CLR_INDIR_INT_MSK_CLR_MASK 0x1U -#define SSS_MSI_CLR_INDIR_AUTO_MSK_SET_MASK 0x1U -#define SSS_MSI_CLR_INDIR_AUTO_MSK_CLR_MASK 0x1U +#define SSS_MSI_CLR_INDIR_INT_MSK_SET_MASK 0x1U +#define SSS_MSI_CLR_INDIR_INT_MSK_CLR_MASK 0x1U +#define SSS_MSI_CLR_INDIR_AUTO_MSK_SET_MASK 0x1U +#define SSS_MSI_CLR_INDIR_AUTO_MSK_CLR_MASK 0x1U #define SSS_MSI_CLR_INDIR_SIMPLE_INDIR_ID_MASK 0x3FFU #define SSS_SET_MSI_CLR_INDIR(val, member) \ @@ -80,8 +94,8 @@ #define SSS_EQ_INDIR_ID_ADDR(type) \ ((type == SSS_AEQ) ? SSS_AEQ_INDIR_ID_ADDR : SSS_CEQ_INDIR_ID_ADDR) -#define SSS_AEQ_MTT_OFF_BASE_ADDR (SSS_CSR_CFG_FLAG + 0x240) -#define SSS_CEQ_MTT_OFF_BASE_ADDR (SSS_CSR_CFG_FLAG + 0x2C0) +#define SSS_AEQ_MTT_OFF_BASE_ADDR (SSS_CSR_CFG_FLAG + 0x240) +#define SSS_CEQ_MTT_OFF_BASE_ADDR (SSS_CSR_CFG_FLAG + 0x2C0) #define SSS_CSR_EQ_PAGE_OFF_STRIDE 8 @@ -98,20 +112,20 @@ (SSS_CEQ_MTT_OFF_BASE_ADDR + \ (pg_num) * SSS_CSR_EQ_PAGE_OFF_STRIDE + 4) -#define SSS_CSR_AEQ_CTRL_0_ADDR (SSS_CSR_CFG_FLAG + 0x200) -#define SSS_CSR_AEQ_CTRL_1_ADDR (SSS_CSR_CFG_FLAG + 0x204) -#define SSS_CSR_AEQ_CI_ADDR (SSS_CSR_CFG_FLAG + 0x208) -#define SSS_CSR_AEQ_PI_ADDR (SSS_CSR_CFG_FLAG + 0x20C) +#define SSS_CSR_AEQ_CTRL_0_ADDR (SSS_CSR_CFG_FLAG + 0x200) +#define SSS_CSR_AEQ_CTRL_1_ADDR (SSS_CSR_CFG_FLAG + 0x204) +#define SSS_CSR_AEQ_CI_ADDR (SSS_CSR_CFG_FLAG + 0x208) +#define SSS_CSR_AEQ_PI_ADDR (SSS_CSR_CFG_FLAG + 0x20C) #define SSS_CSR_AEQ_CI_SIMPLE_INDIR_ADDR (SSS_CSR_CFG_FLAG + 0x50) -#define SSS_CSR_CEQ_CTRL_0_ADDR (SSS_CSR_CFG_FLAG + 0x280) -#define SSS_CSR_CEQ_CTRL_1_ADDR (SSS_CSR_CFG_FLAG + 0x284) -#define SSS_CSR_CEQ_CI_ADDR (SSS_CSR_CFG_FLAG + 0x288) -#define SSS_CSR_CEQ_PI_ADDR (SSS_CSR_CFG_FLAG + 0x28c) +#define SSS_CSR_CEQ_CTRL_0_ADDR (SSS_CSR_CFG_FLAG + 0x280) +#define SSS_CSR_CEQ_CTRL_1_ADDR (SSS_CSR_CFG_FLAG + 0x284) +#define SSS_CSR_CEQ_CI_ADDR (SSS_CSR_CFG_FLAG + 0x288) +#define SSS_CSR_CEQ_PI_ADDR (SSS_CSR_CFG_FLAG + 0x28c) #define SSS_CSR_CEQ_CI_SIMPLE_INDIR_ADDR (SSS_CSR_CFG_FLAG + 0x54) /* ADM MSG registers */ -#define SSS_CSR_ADM_MSG_BASE (SSS_MGMT_FLAG + 0x2000) +#define SSS_CSR_ADM_MSG_BASE (SSS_MGMT_FLAG + 0x2000) #define SSS_CSR_ADM_MSG_STRIDE 0x80 @@ -143,12 +157,12 @@ (SSS_CSR_ADM_MSG_BASE + 0x30 + (id) * SSS_CSR_ADM_MSG_STRIDE) /* self test register */ -#define SSS_MGMT_HEALTH_STATUS_ADDR (SSS_MGMT_FLAG + 0x983c) +#define SSS_MGMT_HEALTH_STATUS_ADDR (SSS_MGMT_FLAG + 0x983c) -#define SSS_CHIP_BASE_INFO_ADDR (SSS_MGMT_FLAG + 0xB02C) +#define SSS_CHIP_BASE_INFO_ADDR (SSS_MGMT_FLAG + 0xB02C) -#define SSS_CHIP_ERR_STATUS0_ADDR (SSS_MGMT_FLAG + 0xC0EC) -#define SSS_CHIP_ERR_STATUS1_ADDR (SSS_MGMT_FLAG + 0xC0F0) +#define SSS_CHIP_ERR_STATUS0_ADDR (SSS_MGMT_FLAG + 0xC0EC) +#define SSS_CHIP_ERR_STATUS1_ADDR (SSS_MGMT_FLAG + 0xC0F0) #define SSS_ERR_INFO0_ADDR (SSS_MGMT_FLAG + 0xC0F4) #define SSS_ERR_INFO1_ADDR (SSS_MGMT_FLAG + 0xC0F8) diff --git a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_hwdev.h b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_hwdev.h index 9d0473ecc46e..913533099631 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_hwdev.h +++ b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_hwdev.h @@ -24,6 +24,8 @@ #include "sss_mbx_info.h" #include "sss_mgmt_channel.h" +#define SSSNIC_CHANNEL_DETECT_PERIOD (5 * 1000) + enum sss_func_mode { SSS_FUNC_MOD_MIN, @@ -81,6 +83,11 @@ struct sss_aeq_stat { u64 last_recv_cnt; }; +struct sss_clp_pf_to_mgmt { + struct semaphore clp_msg_lock; + void *clp_msg_buf; +}; + struct sss_hwdev { void *adapter_hdl; /* pointer to sss_pci_adapter or NDIS_Adapter */ void *pcidev_hdl; /* pointer to pcidev or Handler */ @@ -108,6 +115,7 @@ struct sss_hwdev { struct sss_ceq_info *ceq_info; struct sss_mbx *mbx; // mbx struct sss_msg_pf_to_mgmt *pf_to_mgmt; // adm + struct sss_clp_pf_to_mgmt *clp_pf_to_mgmt; struct sss_hw_stats hw_stats; u8 *chip_fault_stats; @@ -132,6 +140,8 @@ struct sss_hwdev { enum sss_func_mode func_mode; struct sss_aeq_stat aeq_stat; + + u16 aeq_busy_cnt; }; #define SSS_TO_HWDEV(ptr) ((struct sss_hwdev *)(ptr)->hwdev) @@ -220,6 +230,8 @@ enum sss_servic_bit_define { #define SSS_IS_PPF(dev) \ (SSS_GET_FUNC_TYPE(dev) == SSS_FUNC_TYPE_PPF) +#define SSS_GET_FUNC_ID(hwdev) ((hwdev)->hwif->attr.func_id) + #define SSS_IS_BMGW_MASTER_HOST(hwdev) \ ((hwdev)->func_mode == SSS_FUNC_MOD_MULTI_BM_MASTER) #define SSS_IS_BMGW_SLAVE_HOST(hwdev) \ @@ -248,6 +260,10 @@ enum sss_servic_bit_define { ((hwdev)->features[0] & SSS_COMM_F_CTRLQ_NUM) #define SSS_SUPPORT_VIRTIO_VQ_SIZE(hwdev) \ ((hwdev)->features[0] & SSS_COMM_F_VIRTIO_VQ_SIZE) +#define SSS_SUPPORT_CHANNEL_DETECT(hwdev) \ + ((hwdev)->features[0] & SSS_COMM_F_CHANNEL_DETECT) +#define SSS_SUPPORT_CLP(hwdev) \ + ((hwdev)->features[0] & SSS_COMM_F_CLP) enum { SSS_CFG_FREE = 0, diff --git a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_mgmt_channel.h b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_mgmt_channel.h index bae3a4489895..4c0c3c482dde 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_mgmt_channel.h +++ b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_mgmt_channel.h @@ -109,29 +109,33 @@ struct sss_recv_msg { }; struct sss_msg_pf_to_mgmt { - void *hwdev; + void *hwdev; + spinlock_t async_msg_lock; /* protect msg async and sync */ - struct semaphore sync_lock; + struct semaphore sync_lock; - struct workqueue_struct *workq; + struct workqueue_struct *workq; + void *async_msg_buf; void *sync_buf; void *ack_buf; - struct sss_recv_msg recv_msg; - struct sss_recv_msg recv_resp_msg; + struct sss_recv_msg recv_msg; + struct sss_recv_msg recv_resp_msg; - u16 rsvd; - u16 sync_msg_id; - struct sss_adm_msg adm_msg; + u16 rsvd; + u16 async_msg_id; + u16 sync_msg_id; + struct sss_adm_msg *adm_msg[SSS_ADM_MSG_MAX]; - sss_mgmt_msg_handler_t recv_handler[SSS_MOD_TYPE_HW_MAX]; - void *recv_data[SSS_MOD_TYPE_HW_MAX]; - unsigned long recv_handler_state[SSS_MOD_TYPE_HW_MAX]; + sss_mgmt_msg_handler_t recv_handler[SSS_MOD_TYPE_HW_MAX]; + void *recv_data[SSS_MOD_TYPE_HW_MAX]; + unsigned long recv_handler_state[SSS_MOD_TYPE_HW_MAX]; + void *async_msg_cb_data[SSS_MOD_TYPE_HW_MAX]; /* lock when sending msg */ - spinlock_t sync_event_lock; - enum sss_pf_to_mgmt_event_state event_state; + spinlock_t sync_event_lock; /* protect event async and sync */ + enum sss_pf_to_mgmt_event_state event_state; }; #endif diff --git a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_mgmt_info.h b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_mgmt_info.h index 8fb900f848ab..f3b50b0d4f1d 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/include/sss_mgmt_info.h +++ b/drivers/net/ethernet/3snic/sssnic/hw/include/sss_mgmt_info.h @@ -107,6 +107,11 @@ struct sss_service_cap { struct sss_vbs_service_cap vbs_cap; /* VBS capability */ }; +struct sss_svc_cap_info { + u32 func_id; + struct sss_service_cap cap; +}; + struct sss_mgmt_info { void *hwdev; struct sss_service_cap svc_cap; diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_adapter_mgmt.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_adapter_mgmt.c index 9abffd91deaa..b9e202e4ee08 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_adapter_mgmt.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_adapter_mgmt.c @@ -17,21 +17,31 @@ #include "sss_kernel.h" #include "sss_hw.h" +#include "sss_hwdev.h" #include "sss_pci_sriov.h" #include "sss_pci_id_tbl.h" +#include "sss_adapter.h" #include "sss_adapter_mgmt.h" #include "sss_pci_global.h" +#include "sss_tool_comm.h" +#include "sss_hw_export.h" +#include "sss_tool_hw.h" +#include "sss_tool.h" + +#ifndef SSS_PF_NUM_MAX +#define SSS_PF_NUM_MAX (16) +#endif #define SSS_ADAPTER_CNT_TIMEOUT 10000 #define SSS_WAIT_ADAPTER_USLEEP_MIN 9900 #define SSS_WAIT_ADAPTER_USLEEP_MAX 10000 -#define SSS_CHIP_NODE_HOLD_TIMEOUT (10 * 60 * 1000) -#define SSS_WAIT_CHIP_NODE_CHANGED (10 * 60 * 1000) -#define SSS_PRINT_TIMEOUT_INTERVAL 10000 -#define SSS_MICRO_SECOND 1000 -#define SSS_CHIP_NODE_USLEEP_MIN 900 -#define SSS_CHIP_NODE_USLEEP_MAX 1000 +#define SSS_CHIP_NODE_HOLD_TIMEOUT (10 * 60 * 1000) +#define SSS_WAIT_CHIP_NODE_CHANGED (10 * 60 * 1000) +#define SSS_PRINT_TIMEOUT_INTERVAL 10000 +#define SSS_MICRO_SECOND 1000 +#define SSS_CHIP_NODE_USLEEP_MIN 900 +#define SSS_CHIP_NODE_USLEEP_MAX 1000 #define SSS_CARD_CNT_MAX 64 @@ -42,10 +52,9 @@ enum sss_node_state { }; struct sss_chip_node_lock { - /* lock for chip list */ - struct mutex chip_mutex; - unsigned long state; - atomic_t ref_cnt; + struct mutex chip_mutex; /* lock for chip list */ + unsigned long state; + atomic_t ref_cnt; }; static struct sss_chip_node_lock g_chip_node_lock; @@ -59,7 +68,21 @@ struct list_head *sss_get_chip_list(void) return &g_chip_list; } -static void sss_chip_node_lock(void) +void lld_dev_hold(struct sss_hal_dev *dev) +{ + struct sss_pci_adapter *pci_adapter = pci_get_drvdata(dev->pdev); + + atomic_inc(&pci_adapter->ref_cnt); +} + +void lld_dev_put(struct sss_hal_dev *dev) +{ + struct sss_pci_adapter *pci_adapter = pci_get_drvdata(dev->pdev); + + atomic_dec(&pci_adapter->ref_cnt); +} + +void sss_chip_node_lock(void) { unsigned long end; bool timeout = true; @@ -81,8 +104,7 @@ static void sss_chip_node_lock(void) loop_cnt / SSS_MICRO_SECOND); /* if sleep 1ms, use usleep_range to be more precise */ - usleep_range(SSS_CHIP_NODE_USLEEP_MIN, - SSS_CHIP_NODE_USLEEP_MAX); + usleep_range(SSS_CHIP_NODE_USLEEP_MIN, SSS_CHIP_NODE_USLEEP_MAX); } while (time_before(jiffies, end)); if (timeout && test_and_set_bit(SSS_NODE_CHANGE, &g_chip_node_lock.state)) @@ -113,7 +135,7 @@ static void sss_chip_node_lock(void) mutex_unlock(&g_chip_node_lock.chip_mutex); } -static void sss_chip_node_unlock(void) +void sss_chip_node_unlock(void) { clear_bit(SSS_NODE_CHANGE, &g_chip_node_lock.state); } @@ -136,8 +158,7 @@ void sss_hold_chip_node(void) pr_warn("Wait adapter change complete for %us\n", loop_cnt / SSS_MICRO_SECOND); /* if sleep 1ms, use usleep_range to be more precise */ - usleep_range(SSS_CHIP_NODE_USLEEP_MIN, - SSS_CHIP_NODE_USLEEP_MAX); + usleep_range(SSS_CHIP_NODE_USLEEP_MIN, SSS_CHIP_NODE_USLEEP_MAX); } while (time_before(jiffies, end)); if (test_bit(SSS_NODE_CHANGE, &g_chip_node_lock.state)) @@ -295,8 +316,7 @@ void sss_free_chip_node(struct sss_pci_adapter *adapter) if (ret < 0) sdk_err(&adapter->pcidev->dev, "Fail to get nic id\n"); - clear_bit(id, &g_index_bit_map); - + sss_free_card_id(id); kfree(chip_node); } sss_chip_node_unlock(); @@ -315,3 +335,390 @@ void sss_del_func_list(struct sss_pci_adapter *adapter) list_del(&adapter->node); sss_chip_node_unlock(); } + +static struct sss_card_node *sss_get_chip_node_by_hwdev(const void *hwdev) +{ + struct sss_card_node *chip_node = NULL; + struct sss_card_node *node_tmp = NULL; + struct sss_pci_adapter *dev = NULL; + + if (!hwdev) + return NULL; + + sss_hold_chip_node(); + + list_for_each_entry(node_tmp, &g_chip_list, node) { + if (!chip_node) { + list_for_each_entry(dev, &node_tmp->func_list, node) { + if (dev->hwdev == hwdev) { + chip_node = node_tmp; + break; + } + } + } + } + + sss_put_chip_node(); + + return chip_node; +} + +static bool sss_is_func_valid(struct sss_pci_adapter *dev) +{ + if (sss_get_func_type(dev->hwdev) == SSS_FUNC_TYPE_VF) + return false; + + return true; +} + +static int sss_get_dynamic_uld_dev_name(struct sss_pci_adapter *dev, enum sss_service_type type, + char *ifname) +{ + u32 out_size = IFNAMSIZ; + struct sss_uld_info *uld_info = sss_get_uld_info(); + + if (!uld_info[type].ioctl) + return -EFAULT; + + return uld_info[type].ioctl(dev->uld_dev[type], SSS_TOOL_GET_ULD_DEV_NAME, + NULL, 0, ifname, &out_size); +} + +static bool sss_support_service_type(void *hwdev) +{ + struct sss_hwdev *dev = hwdev; + + if (!hwdev) + return false; + + return !dev->mgmt_info->svc_cap.chip_svc_type; +} + +void sss_get_card_info(const void *hwdev, void *bufin) +{ + struct sss_card_node *chip_node = NULL; + struct sss_tool_card_info *info = (struct sss_tool_card_info *)bufin; + struct sss_pci_adapter *dev = NULL; + void *fun_hwdev = NULL; + u32 i = 0; + + info->pf_num = 0; + + chip_node = sss_get_chip_node_by_hwdev(hwdev); + if (!chip_node) + return; + + sss_hold_chip_node(); + + list_for_each_entry(dev, &chip_node->func_list, node) { + if (!sss_is_func_valid(dev)) + continue; + + fun_hwdev = dev->hwdev; + + if (sss_support_nic(fun_hwdev)) { + if (dev->uld_dev[SSS_SERVICE_TYPE_NIC]) { + info->pf[i].pf_type |= (u32)BIT(SSS_SERVICE_TYPE_NIC); + sss_get_dynamic_uld_dev_name(dev, SSS_SERVICE_TYPE_NIC, + info->pf[i].name); + } + } + + if (sss_support_ppa(fun_hwdev, NULL)) { + if (dev->uld_dev[SSS_SERVICE_TYPE_PPA]) { + info->pf[i].pf_type |= (u32)BIT(SSS_SERVICE_TYPE_PPA); + sss_get_dynamic_uld_dev_name(dev, SSS_SERVICE_TYPE_PPA, + info->pf[i].name); + } + } + + if (sss_support_service_type(fun_hwdev)) + strlcpy(info->pf[i].name, "FOR_MGMT", IFNAMSIZ); + + strlcpy(info->pf[i].bus_info, pci_name(dev->pcidev), + sizeof(info->pf[i].bus_info)); + info->pf_num++; + i = info->pf_num; + } + + sss_put_chip_node(); +} + +bool sss_is_in_host(void) +{ + struct sss_card_node *node = NULL; + struct sss_pci_adapter *adapter = NULL; + + sss_hold_chip_node(); + list_for_each_entry(node, &g_chip_list, node) { + list_for_each_entry(adapter, &node->func_list, node) { + if (sss_get_func_type(adapter->hwdev) != SSS_FUNC_TYPE_VF) { + sss_put_chip_node(); + return true; + } + } + } + sss_put_chip_node(); + + return false; +} + +void sss_get_all_chip_id(void *id_info) +{ + int i = 0; + int id; + int ret; + struct sss_card_id *card_id = (struct sss_card_id *)id_info; + struct sss_card_node *node = NULL; + + sss_hold_chip_node(); + list_for_each_entry(node, &g_chip_list, node) { + ret = sscanf(node->chip_name, SSS_CHIP_NAME "%d", &id); + if (ret < 0) { + pr_err("Fail to get chip id\n"); + continue; + } + card_id->id[i] = (u32)id; + i++; + } + sss_put_chip_node(); + + card_id->num = (u32)i; +} + +void *sss_get_pcidev_hdl(void *hwdev) +{ + struct sss_hwdev *dev = (struct sss_hwdev *)hwdev; + + if (!hwdev) + return NULL; + + return dev->pcidev_hdl; +} + +struct sss_card_node *sss_get_card_node(struct sss_hal_dev *hal_dev) +{ + struct sss_pci_adapter *adapter = pci_get_drvdata(hal_dev->pdev); + + return adapter->chip_node; +} + +void sss_get_card_func_info(const char *chip_name, struct sss_card_func_info *card_func) +{ + struct sss_card_node *card_node = NULL; + struct sss_pci_adapter *adapter = NULL; + struct sss_func_pdev_info *info = NULL; + + card_func->pf_num = 0; + + sss_hold_chip_node(); + + list_for_each_entry(card_node, &g_chip_list, node) { + if (strncmp(card_node->chip_name, chip_name, IFNAMSIZ)) + continue; + + list_for_each_entry(adapter, &card_node->func_list, node) { + if (sss_get_func_type(adapter->hwdev) == SSS_FUNC_TYPE_VF) + continue; + + info = &card_func->pdev_info[card_func->pf_num]; + info->bar1_size = + pci_resource_len(adapter->pcidev, SSS_PF_PCI_CFG_REG_BAR); + info->bar1_pa = + pci_resource_start(adapter->pcidev, SSS_PF_PCI_CFG_REG_BAR); + + info->bar3_size = + pci_resource_len(adapter->pcidev, SSS_PCI_MGMT_REG_BAR); + info->bar3_pa = + pci_resource_start(adapter->pcidev, SSS_PCI_MGMT_REG_BAR); + + card_func->pf_num++; + if (card_func->pf_num >= SSS_PF_NUM_MAX) { + sss_put_chip_node(); + return; + } + } + } + + sss_put_chip_node(); +} + +int sss_get_pf_id(struct sss_card_node *card_node, u32 port_id, u32 *pf_id, u32 *valid) +{ + struct sss_pci_adapter *adapter = NULL; + + sss_hold_chip_node(); + list_for_each_entry(adapter, &card_node->func_list, node) { + if (sss_get_func_type(adapter->hwdev) == SSS_FUNC_TYPE_VF) + continue; + + if (SSS_TO_PHY_PORT_ID(adapter->hwdev) == port_id) { + *pf_id = sss_get_func_id(adapter->hwdev); + *valid = 1; + break; + } + } + sss_put_chip_node(); + + return 0; +} + +void *sss_get_uld_dev(struct sss_hal_dev *hal_dev, enum sss_service_type type) +{ + struct sss_pci_adapter *dev = NULL; + void *uld = NULL; + + if (!hal_dev) + return NULL; + + dev = pci_get_drvdata(hal_dev->pdev); + if (!dev) + return NULL; + + spin_lock_bh(&dev->uld_lock); + if (!dev->uld_dev[type] || !test_bit(type, &dev->uld_attach_state)) { + spin_unlock_bh(&dev->uld_lock); + return NULL; + } + uld = dev->uld_dev[type]; + + atomic_inc(&dev->uld_ref_cnt[type]); + spin_unlock_bh(&dev->uld_lock); + + return uld; +} + +void sss_uld_dev_put(struct sss_hal_dev *hal_dev, enum sss_service_type type) +{ + struct sss_pci_adapter *pci_adapter = pci_get_drvdata(hal_dev->pdev); + + atomic_dec(&pci_adapter->uld_ref_cnt[type]); +} + +static bool sss_is_pcidev_match_dev_name(const char *dev_name, struct sss_pci_adapter *dev, + enum sss_service_type type) +{ + enum sss_service_type i; + char nic_uld_name[IFNAMSIZ] = {0}; + int err; + + if (type > SSS_SERVICE_TYPE_MAX) + return false; + + if (type == SSS_SERVICE_TYPE_MAX) { + for (i = SSS_SERVICE_TYPE_OVS; i < SSS_SERVICE_TYPE_MAX; i++) { + if (!strncmp(dev->uld_dev_name[i], dev_name, IFNAMSIZ)) + return true; + } + } else { + if (!strncmp(dev->uld_dev_name[type], dev_name, IFNAMSIZ)) + return true; + } + + err = sss_get_dynamic_uld_dev_name(dev, SSS_SERVICE_TYPE_NIC, (char *)nic_uld_name); + if (err == 0) { + if (!strncmp(nic_uld_name, dev_name, IFNAMSIZ)) + return true; + } + + return false; +} + +struct sss_hal_dev *sss_get_lld_dev_by_dev_name(const char *dev_name, enum sss_service_type type) +{ + struct sss_card_node *chip_node = NULL; + struct sss_pci_adapter *dev = NULL; + + sss_hold_chip_node(); + + list_for_each_entry(chip_node, &g_chip_list, node) { + list_for_each_entry(dev, &chip_node->func_list, node) { + if (sss_is_pcidev_match_dev_name(dev_name, dev, type)) { + lld_dev_hold(&dev->hal_dev); + sss_put_chip_node(); + return &dev->hal_dev; + } + } + } + + sss_put_chip_node(); + + return NULL; +} + +static bool sss_is_pcidev_match_chip_name(const char *ifname, struct sss_pci_adapter *dev, + struct sss_card_node *chip_node, enum sss_func_type type) +{ + if (!strncmp(chip_node->chip_name, ifname, IFNAMSIZ)) { + if (sss_get_func_type(dev->hwdev) != type) + return false; + return true; + } + + return false; +} + +static struct sss_hal_dev *sss_get_dst_type_lld_dev_by_chip_name(const char *ifname, + enum sss_func_type type) +{ + struct sss_card_node *chip_node = NULL; + struct sss_pci_adapter *dev = NULL; + + list_for_each_entry(chip_node, &g_chip_list, node) { + list_for_each_entry(dev, &chip_node->func_list, node) { + if (sss_is_pcidev_match_chip_name(ifname, dev, chip_node, type)) + return &dev->hal_dev; + } + } + + return NULL; +} + +struct sss_hal_dev *sss_get_lld_dev_by_chip_name(const char *chip_name) +{ + struct sss_hal_dev *dev = NULL; + + sss_hold_chip_node(); + + dev = sss_get_dst_type_lld_dev_by_chip_name(chip_name, SSS_FUNC_TYPE_PPF); + if (dev) + goto out; + + dev = sss_get_dst_type_lld_dev_by_chip_name(chip_name, SSS_FUNC_TYPE_PF); + if (dev) + goto out; + + dev = sss_get_dst_type_lld_dev_by_chip_name(chip_name, SSS_FUNC_TYPE_VF); +out: + if (dev) + lld_dev_hold(dev); + sss_put_chip_node(); + + return dev; +} + +struct sss_hal_dev *sss_get_lld_dev_by_chip_and_port(const char *chip_name, u8 port_id) +{ + struct sss_card_node *chip_node = NULL; + struct sss_pci_adapter *dev = NULL; + + sss_hold_chip_node(); + list_for_each_entry(chip_node, &g_chip_list, node) { + list_for_each_entry(dev, &chip_node->func_list, node) { + if (sss_get_func_type(dev->hwdev) == SSS_FUNC_TYPE_VF) + continue; + + if (SSS_TO_PHY_PORT_ID(dev->hwdev) == port_id && + !strncmp(chip_node->chip_name, chip_name, IFNAMSIZ)) { + lld_dev_hold(&dev->hal_dev); + sss_put_chip_node(); + + return &dev->hal_dev; + } + } + } + sss_put_chip_node(); + + return NULL; +} + diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_adapter_mgmt.h b/drivers/net/ethernet/3snic/sssnic/hw/sss_adapter_mgmt.h index 621ef1fb7bd6..44805eccff4f 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_adapter_mgmt.h +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_adapter_mgmt.h @@ -7,8 +7,11 @@ #include #include +#include "sss_version.h" #include "sss_adapter.h" +#define SSS_DRV_VERSION SSS_VERSION_STR + #define SSS_DRV_NAME "sssdk" #define SSS_CHIP_NAME "sssnic" @@ -21,6 +24,30 @@ #define SSS_IS_VF_DEV(pdev) ((pdev)->device == SSS_DEV_ID_VF) +#define SSS_CARD_MAX_SIZE (64) + +struct sss_card_id { + u32 id[SSS_CARD_MAX_SIZE]; + u32 num; +}; + +struct sss_func_pdev_info { + u64 bar0_pa; + u64 bar0_size; + u64 bar1_pa; + u64 bar1_size; + u64 bar3_pa; + u64 bar3_size; + u64 rsvd[4]; +}; + +struct sss_card_func_info { + u32 pf_num; + u32 rsvd; + u64 usr_adm_pa; + struct sss_func_pdev_info pdev_info[SSS_CARD_MAX_SIZE]; +}; + enum { SSS_NO_PROBE = 1, SSS_PROBE_START = 2, @@ -40,4 +67,34 @@ void sss_put_chip_node(void); void sss_set_adapter_probe_state(struct sss_pci_adapter *adapter, int state); +void lld_dev_hold(struct sss_hal_dev *dev); +void lld_dev_put(struct sss_hal_dev *dev); + +void sss_chip_node_lock(void); +void sss_chip_node_unlock(void); + +void *sss_get_pcidev_hdl(void *hwdev); +void *sss_get_uld_dev(struct sss_hal_dev *hal_dev, enum sss_service_type type); + +void sss_uld_dev_put(struct sss_hal_dev *hal_dev, enum sss_service_type type); + +struct sss_hal_dev *sss_get_lld_dev_by_dev_name(const char *dev_name, enum sss_service_type type); + +struct sss_hal_dev *sss_get_lld_dev_by_chip_name(const char *chip_name); + +struct sss_hal_dev *sss_get_lld_dev_by_chip_and_port(const char *chip_name, u8 port_id); + +void sss_get_all_chip_id(void *id_info); + +void sss_get_card_func_info + (const char *chip_name, struct sss_card_func_info *card_func); + +void sss_get_card_info(const void *hwdev, void *bufin); + +bool sss_is_in_host(void); + +int sss_get_pf_id(struct sss_card_node *chip_node, u32 port_id, u32 *pf_id, u32 *valid); + +struct sss_card_node *sss_get_card_node(struct sss_hal_dev *hal_dev); + #endif diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hw_main.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hw_main.c index 519ae6e72b65..8c30c6c52fe5 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hw_main.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hw_main.c @@ -27,7 +27,6 @@ #include "sss_pci_shutdown.h" #include "sss_pci_error.h" -#define SSS_DRV_VERSION SSS_VERSION_STR #define SSS_DRV_DESC "Intelligent Network Interface Card Driver" MODULE_AUTHOR("steven.song@3snic.com"); diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_cap.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_cap.c index f0ed1e7d7219..412cc574a563 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_cap.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_cap.c @@ -280,7 +280,7 @@ static void sss_print_pubic_cap(void *dev_hdl, const struct sss_service_cap *svc svc_cap->pseudo_vf_bfilter_start_addr, svc_cap->pseudo_vf_bfilter_len); } -static void sss_parse_cqm_cap(struct sss_hwdev *hwdev, +static void sss_parse_qmm_cap(struct sss_hwdev *hwdev, struct sss_service_cap *svc_cap, struct sss_cmd_dev_cap_cfg *cmd_cap) { struct sss_dev_sf_svc_attr *sf_svc_attr = &svc_cap->sf_svc_attr; @@ -346,7 +346,7 @@ static void sss_parse_pubic_cap(struct sss_hwdev *hwdev, svc_cap->sf_en = (type == SSS_FUNC_TYPE_PPF) ? (!!cmd_cap->host_sf_en) : (!!cmd_cap->func_sf_en); - sss_parse_cqm_cap(hwdev, svc_cap, cmd_cap); + sss_parse_qmm_cap(hwdev, svc_cap, cmd_cap); sss_print_pubic_cap(hwdev->dev_hdl, svc_cap); } diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_export.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_export.c index 33e8e997359e..046939246827 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_export.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_export.c @@ -12,6 +12,7 @@ #include "sss_hwdev.h" #include "sss_csr.h" #include "sss_hwif_api.h" +#include "sss_hw_svc_cap.h" #define SSS_DEFAULT_RX_BUF_SIZE_LEVEL ((u16)0xB) @@ -287,6 +288,23 @@ bool sss_support_nic(void *hwdev) } EXPORT_SYMBOL(sss_support_nic); +bool sss_support_ppa(void *hwdev, struct sss_ppa_service_cap *cap) +{ + struct sss_hwdev *dev = hwdev; + + if (!hwdev) + return false; + + if (!SSS_IS_PPA_TYPE(dev)) + return false; + + if (cap) + memcpy(cap, &dev->mgmt_info->svc_cap.ppa_cap, sizeof(*cap)); + + return true; +} +EXPORT_SYMBOL(sss_support_ppa); + u16 sss_get_max_sq_num(void *hwdev) { if (!hwdev) { @@ -320,6 +338,19 @@ u16 sss_get_max_vf_num(void *hwdev) } EXPORT_SYMBOL(sss_get_max_vf_num); +u16 sss_nic_intr_num(void *hwdev) +{ + struct sss_hwif *hwif = NULL; + + if (!hwdev) + return 0; + + hwif = ((struct sss_hwdev *)hwdev)->hwif; + + return hwif->attr.irq_num; +} +EXPORT_SYMBOL(sss_nic_intr_num); + int sss_get_cos_valid_bitmap(void *hwdev, u8 *func_cos_bitmap, u8 *port_cos_bitmap) { if (!hwdev) { @@ -561,8 +592,8 @@ void sss_update_link_stats(void *hwdev, bool link_state) return; if (link_state) - atomic_inc(&dev->hw_stats.sss_link_event_stats.link_up_stats); + atomic_inc(&dev->hw_stats.link_event_stats.link_up_stats); else - atomic_inc(&dev->hw_stats.sss_link_event_stats.link_down_stats); + atomic_inc(&dev->hw_stats.link_event_stats.link_down_stats); } EXPORT_SYMBOL(sss_update_link_stats); diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_link.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_link.c index e14b592193e6..f86da62a0015 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_link.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_link.c @@ -12,6 +12,7 @@ #include "sss_hw_common.h" #include "sss_hwdev_api.h" #include "sss_hwif_adm.h" +#include "sss_hwif_adm_common.h" #define SSS_FW_MAGIC_NUM 0x5a5a1100 #define SSS_FW_IMAGE_HEAD_SIZE 4096 diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_mgmt_channel.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_mgmt_channel.c index 91be1f517afa..42f0c1fa15ab 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_mgmt_channel.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwdev_mgmt_channel.c @@ -318,10 +318,10 @@ static void sss_print_chip_fault(struct sss_hwdev *hwdev, level_str = SSS_FAULT_LEVEL_STR_UNKNOWN; if (err_level == SSS_FAULT_LEVEL_SERIOUS_FLR) - dev_err(hwdev->dev_hdl, "Err_level: %u [%s], func_id: %u\n", + sdk_err(hwdev->dev_hdl, "Err_level: %u [%s], func_id: %u\n", err_level, level_str, fault_event->info.chip.func_id); - dev_err(hwdev->dev_hdl, "Node_id: 0x%x, err_type: 0x%x, err_level: %u[%s], err_csr_addr: 0x%08x, err_csr_value: 0x%08x\n", + sdk_err(hwdev->dev_hdl, "Node_id: 0x%x, err_type: 0x%x, err_level: %u[%s], err_csr_addr: 0x%08x, err_csr_value: 0x%08x\n", fault_event->info.chip.node_id, fault_event->info.chip.err_type, err_level, level_str, fault_event->info.chip.err_csr_addr, fault_event->info.chip.err_csr_value); @@ -362,7 +362,7 @@ static void sss_print_phy_err(struct sss_hwdev *hwdev, static void sss_print_fault_info(struct sss_hwdev *hwdev, struct sss_fault_event *fault_event) { - struct sss_fault_event_stats *event_stats = &hwdev->hw_stats.sss_fault_event_stats; + struct sss_fault_event_stats *event_stats = &hwdev->hw_stats.fault_event_stats; char *type = NULL; char *fault_type[SSS_FAULT_TYPE_MAX] = { SSS_FAULT_TYPE_STR_CHIP, SSS_FAULT_TYPE_STR_NPU, diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm.c index 3f768b9408f6..401186d3786a 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm.c @@ -25,63 +25,12 @@ #define SSS_ADM_MSG_ELEM_DESC_SIZE 8 #define SSS_ADM_MSG_ELEM_DATA_ADDR_SIZE 8 +#define SSS_ADM_MSG_ELEM_WB_ADDR_SIZE 8 #define SSS_ADM_MSG_ELEM_ALIGNMENT 8 #define SSS_ADM_MSG_STATE_TIMEOUT 10000 -#define SSS_WRITE_ADM_MSG_PRIV_DATA(id) (((u8)(id)) << 16) - -#define SSS_MASK_ID(adm_msg, id) \ - ((id) & ((adm_msg)->elem_num - 1)) - -#define SSS_SIZE_TO_4B(size) \ - (ALIGN((u32)(size), 4U) >> 2) -#define SSS_SIZE_TO_8B(size) \ - (ALIGN((u32)(size), 8U) >> 3) - -/* adm_msg_elem structure */ -#define SSS_ADM_MSG_ELEM_CTRL_ELEM_LEN_SHIFT 0 -#define SSS_ADM_MSG_ELEM_CTRL_RD_DMA_ATTR_OFF_SHIFT 16 -#define SSS_ADM_MSG_ELEM_CTRL_WR_DMA_ATTR_OFF_SHIFT 24 -#define SSS_ADM_MSG_ELEM_CTRL_XOR_CHKSUM_SHIFT 56 - -#define SSS_ADM_MSG_ELEM_CTRL_ELEM_LEN_MASK 0x3FU -#define SSS_ADM_MSG_ELEM_CTRL_RD_DMA_ATTR_OFF_MASK 0x3FU -#define SSS_ADM_MSG_ELEM_CTRL_WR_DMA_ATTR_OFF_MASK 0x3FU -#define SSS_ADM_MSG_ELEM_CTRL_XOR_CHKSUM_MASK 0xFFU - -#define SSS_ADM_MSG_ELEM_CTRL_SET(val, member) \ - ((((u64)(val)) & SSS_ADM_MSG_ELEM_CTRL_##member##_MASK) << \ - SSS_ADM_MSG_ELEM_CTRL_##member##_SHIFT) - -/* adm_msg_elem.desc structure */ -#define SSS_ADM_MSG_DESC_SGL_TYPE_SHIFT 0 -#define SSS_ADM_MSG_DESC_RD_WR_SHIFT 1 -#define SSS_ADM_MSG_DESC_MGMT_BYPASS_SHIFT 2 -#define SSS_ADM_MSG_DESC_REPLY_AEQE_EN_SHIFT 3 -#define SSS_ADM_MSG_DESC_MSG_VALID_SHIFT 4 -#define SSS_ADM_MSG_DESC_MSG_CHANNEL_SHIFT 6 -#define SSS_ADM_MSG_DESC_PRIV_DATA_SHIFT 8 -#define SSS_ADM_MSG_DESC_DEST_SHIFT 32 -#define SSS_ADM_MSG_DESC_SIZE_SHIFT 40 -#define SSS_ADM_MSG_DESC_XOR_CHKSUM_SHIFT 56 - -#define SSS_ADM_MSG_DESC_SGL_TYPE_MASK 0x1U -#define SSS_ADM_MSG_DESC_RD_WR_MASK 0x1U -#define SSS_ADM_MSG_DESC_MGMT_BYPASS_MASK 0x1U -#define SSS_ADM_MSG_DESC_REPLY_AEQE_EN_MASK 0x1U -#define SSS_ADM_MSG_DESC_MSG_VALID_MASK 0x3U -#define SSS_ADM_MSG_DESC_MSG_CHANNEL_MASK 0x3U -#define SSS_ADM_MSG_DESC_PRIV_DATA_MASK 0xFFFFFFU -#define SSS_ADM_MSG_DESC_DEST_MASK 0x1FU -#define SSS_ADM_MSG_DESC_SIZE_MASK 0x7FFU -#define SSS_ADM_MSG_DESC_XOR_CHKSUM_MASK 0xFFU - -#define SSS_ADM_MSG_DESC_SET(val, member) \ - ((((u64)(val)) & SSS_ADM_MSG_DESC_##member##_MASK) << \ - SSS_ADM_MSG_DESC_##member##_SHIFT) - /* adm_msg_state header */ #define SSS_ADM_MSG_STATE_HEAD_VALID_SHIFT 0 #define SSS_ADM_MSG_STATE_HEAD_MSG_ID_SHIFT 16 @@ -89,6 +38,9 @@ #define SSS_ADM_MSG_STATE_HEAD_VALID_MASK 0xFFU #define SSS_ADM_MSG_STATE_HEAD_MSG_ID_MASK 0xFFU +#define COMPLETION_TIMEOUT_DEFAULT 1000UL +#define POLLING_COMPLETION_TIMEOUT_DEFAULT 1000U + #define SSS_ADM_MSG_STATE_HEAD_GET(val, member) \ (((val) >> SSS_ADM_MSG_STATE_HEAD_##member##_SHIFT) & \ SSS_ADM_MSG_STATE_HEAD_##member##_MASK) @@ -130,8 +82,6 @@ struct sss_msg_head { u8 rsvd0[5]; }; -#define SSS_ADM_MSG_AEQ_ID 2 - #define SSS_MGMT_MSG_SIZE_MIN 20 #define SSS_MGMT_MSG_SIZE_STEP 16 #define SSS_MGMT_MSG_RSVD_FOR_DEV 8 @@ -164,6 +114,36 @@ struct sss_msg_head { SSS_SET_MSG_HEADER(func_id, SRC_GLB_FUNC_ID) | \ SSS_SET_MSG_HEADER(msg_id, MSG_ID)) +#define SSSNIC_API_CMD_RESP_HEAD_VALID_SHIFT 0 +#define SSSNIC_API_CMD_RESP_HEAD_STATUS_SHIFT 8 +#define SSSNIC_API_CMD_RESP_HEAD_CHAIN_ID_SHIFT 16 +#define SSSNIC_API_CMD_RESP_HEAD_RESP_LEN_SHIFT 24 +#define SSSNIC_API_CMD_RESP_HEAD_DRIVER_PRIV_SHIFT 40 + +#define SSSNIC_API_CMD_RESP_HEAD_VALID_MASK 0xFF +#define SSSNIC_API_CMD_RESP_HEAD_STATUS_MASK 0xFFU +#define SSSNIC_API_CMD_RESP_HEAD_CHAIN_ID_MASK 0xFFU +#define SSSNIC_API_CMD_RESP_HEAD_RESP_LEN_MASK 0x1FFU +#define SSSNIC_API_CMD_RESP_HEAD_DRIVER_PRIV_MASK 0xFFFFFFU + +#define SSSNIC_API_CMD_RESP_HEAD_VALID_CODE 0xFF + +#define SSSNIC_API_CMD_RESP_HEADER_VALID(val) \ + (((val) & SSSNIC_API_CMD_RESP_HEAD_VALID_MASK) == \ + SSSNIC_API_CMD_RESP_HEAD_VALID_CODE) + +#define SSSNIC_API_CMD_RESP_HEAD_GET(val, member) \ + (((val) >> SSSNIC_API_CMD_RESP_HEAD_##member##_SHIFT) & \ + SSSNIC_API_CMD_RESP_HEAD_##member##_MASK) + +#define SSSNIC_API_CMD_RESP_HEAD_CHAIN_ID(val) \ + (((val) >> SSSNIC_API_CMD_RESP_HEAD_CHAIN_ID_SHIFT) & \ + SSSNIC_API_CMD_RESP_HEAD_CHAIN_ID_MASK) + +#define SSSNIC_API_CMD_RESP_HEAD_DRIVER_PRIV(val) \ + ((u16)(((val) >> SSSNIC_API_CMD_RESP_HEAD_DRIVER_PRIV_SHIFT) & \ + SSSNIC_API_CMD_RESP_HEAD_DRIVER_PRIV_MASK)) + static u8 sss_xor_chksum_set(void *data) { int id; @@ -223,23 +203,65 @@ static void sss_dump_adm_msg_reg(struct sss_adm_msg *adm_msg) static int sss_adm_msg_busy(struct sss_adm_msg *adm_msg) { - adm_msg->ci = sss_chip_get_ci(adm_msg); - if (adm_msg->ci == SSS_MASK_ID(adm_msg, adm_msg->pi + 1)) { - sdk_err(SSS_TO_HWDEV(adm_msg)->dev_hdl, "Adm cmd is busy, ci = %u, pi = %u\n", - adm_msg->ci, adm_msg->pi); - sss_dump_adm_msg_reg(adm_msg); - return -EBUSY; + void *dev = SSS_TO_HWDEV(adm_msg)->dev_hdl; + struct sss_adm_msg_elem_ctx *ctx = &adm_msg->elem_ctx[adm_msg->pi]; + u64 resp_header; + + switch (adm_msg->msg_type) { + case SSS_ADM_MSG_MULTI_READ: + case SSS_ADM_MSG_POLL_READ: + resp_header = be64_to_cpu(ctx->reply_fmt->head); + if (ctx->state && !SSSNIC_API_CMD_RESP_HEADER_VALID(resp_header)) { + sdk_err(dev, "Context(0x%x) busy!, pi: %u, resp_header: 0x%08x%08x\n", + ctx->state, adm_msg->pi, + upper_32_bits(resp_header), + lower_32_bits(resp_header)); + sss_dump_adm_msg_reg(adm_msg); + return -EBUSY; + } + break; + case SSS_ADM_MSG_POLL_WRITE: + case SSS_ADM_MSG_WRITE_TO_MGMT_MODULE: + case SSS_ADM_MSG_WRITE_ASYNC_TO_MGMT_MODULE: + adm_msg->ci = sss_chip_get_ci(adm_msg); + + if (adm_msg->ci == SSS_MASK_ID(adm_msg, adm_msg->pi + 1)) { + sdk_err(dev, "API CMD chain %d is busy, cons_idx = %u, prod_idx = %u\n", + adm_msg->msg_type, adm_msg->ci, + adm_msg->pi); + sss_dump_adm_msg_reg(adm_msg); + return -EBUSY; + } + break; + default: + sdk_err(dev, "Unknown Chain type %d\n", adm_msg->msg_type); + return -EINVAL; } return 0; } -static void sss_prepare_elem_ctrl(u64 *elem_ctrl) +static void sss_prepare_elem_ctrl(u64 *elem_ctrl, enum sss_adm_msg_type msg_type) { u64 control; u8 chksum; - u16 elem_len = ALIGN(SSS_ADM_MSG_ELEM_DESC_SIZE + - SSS_ADM_MSG_ELEM_DATA_ADDR_SIZE, SSS_ADM_MSG_ELEM_ALIGNMENT); + u16 elem_len = 0; + + switch (msg_type) { + case SSS_ADM_MSG_POLL_READ: + elem_len = ALIGN(SSS_ADM_MSG_ELEM_DESC_SIZE + SSS_ADM_MSG_ELEM_WB_ADDR_SIZE + + SSS_ADM_MSG_ELEM_DATA_ADDR_SIZE, SSS_ADM_MSG_ELEM_ALIGNMENT); + break; + + case SSS_ADM_MSG_WRITE_TO_MGMT_MODULE: + case SSS_ADM_MSG_POLL_WRITE: + case SSS_ADM_MSG_WRITE_ASYNC_TO_MGMT_MODULE: + elem_len = ALIGN(SSS_ADM_MSG_ELEM_DESC_SIZE + + SSS_ADM_MSG_ELEM_DATA_ADDR_SIZE, SSS_ADM_MSG_ELEM_ALIGNMENT); + break; + default: + break; + } control = SSS_ADM_MSG_ELEM_CTRL_SET(SSS_SIZE_TO_8B(elem_len), ELEM_LEN) | SSS_ADM_MSG_ELEM_CTRL_SET(0ULL, RD_DMA_ATTR_OFF) | @@ -258,13 +280,41 @@ static void sss_prepare_elem_desc(struct sss_adm_msg *adm_msg, { u32 priv; struct sss_adm_msg_elem *elem = adm_msg->now_node; + struct sss_adm_msg_elem_ctx *ctx = &adm_msg->elem_ctx[adm_msg->pi]; + + switch (adm_msg->msg_type) { + case SSS_ADM_MSG_POLL_READ: + priv = SSS_READ_ADM_MSG_PRIV_DATA(adm_msg->msg_type, ctx->store_pi); + elem->desc = SSS_ADM_MSG_DESC_SET(SSS_SGL_TYPE, SGL_TYPE) | + SSS_ADM_MSG_DESC_SET(SSS_ADM_MSG_READ, RD_WR) | + SSS_ADM_MSG_DESC_SET(SSS_BYPASS, MGMT_BYPASS) | + SSS_ADM_MSG_DESC_SET(SSS_NO_TRIGGER, REPLY_AEQE_EN) | + SSS_ADM_MSG_DESC_SET(priv, PRIV_DATA); + break; + case SSS_ADM_MSG_POLL_WRITE: + priv = SSS_WRITE_ADM_MSG_PRIV_DATA(adm_msg->msg_type); + elem->desc = SSS_ADM_MSG_DESC_SET(SSS_SGL_TYPE, SGL_TYPE) | + SSS_ADM_MSG_DESC_SET(SSS_ADM_MSG_WRITE, RD_WR) | + SSS_ADM_MSG_DESC_SET(SSS_BYPASS, MGMT_BYPASS) | + SSS_ADM_MSG_DESC_SET(SSS_NO_TRIGGER, REPLY_AEQE_EN) | + SSS_ADM_MSG_DESC_SET(priv, PRIV_DATA); + break; + case SSS_ADM_MSG_WRITE_ASYNC_TO_MGMT_MODULE: + case SSS_ADM_MSG_WRITE_TO_MGMT_MODULE: + priv = SSS_WRITE_ADM_MSG_PRIV_DATA(adm_msg->msg_type); + elem->desc = SSS_ADM_MSG_DESC_SET(SSS_SGL_TYPE, SGL_TYPE) | + SSS_ADM_MSG_DESC_SET(SSS_ADM_MSG_WRITE, RD_WR) | + SSS_ADM_MSG_DESC_SET(SSS_NO_BYPASS, MGMT_BYPASS) | + SSS_ADM_MSG_DESC_SET(SSS_TRIGGER, REPLY_AEQE_EN) | + SSS_ADM_MSG_DESC_SET(priv, PRIV_DATA); + + break; + default: + sdk_err(((struct sss_hwdev *)adm_msg->hwdev)->dev_hdl, "Unknown Chain type: %d\n", + adm_msg->msg_type); + return; + } - priv = SSS_WRITE_ADM_MSG_PRIV_DATA(adm_msg->msg_type); - elem->desc = SSS_ADM_MSG_DESC_SET(SSS_SGL_TYPE, SGL_TYPE) | - SSS_ADM_MSG_DESC_SET(SSS_ADM_MSG_WRITE, RD_WR) | - SSS_ADM_MSG_DESC_SET(SSS_NO_BYPASS, MGMT_BYPASS) | - SSS_ADM_MSG_DESC_SET(SSS_TRIGGER, REPLY_AEQE_EN) | - SSS_ADM_MSG_DESC_SET(priv, PRIV_DATA); elem->desc |= SSS_ADM_MSG_DESC_SET(SSS_ADM_MSG_CHANNEL_0, MSG_CHANNEL) | SSS_ADM_MSG_DESC_SET(SSS_VALID_MSG_CHANNEL, MSG_VALID); @@ -291,7 +341,7 @@ static void sss_prepare_elem(struct sss_adm_msg *adm_msg, u8 node_id, { struct sss_adm_msg_elem *now_node = adm_msg->now_node; - sss_prepare_elem_ctrl(&now_node->control); + sss_prepare_elem_ctrl(&now_node->control, adm_msg->msg_type); sss_prepare_elem_desc(adm_msg, node_id, cmd_size); sss_prepare_elem_ctx(adm_msg, cmd, cmd_size); } @@ -345,21 +395,87 @@ static enum sss_process_ret sss_wait_for_state_poll_handler(void *priv_data) return SSS_PROCESS_DOING; } +static enum sss_process_ret check_cmd_resp_handler(void *priv_data) +{ + struct sss_adm_msg_elem_ctx *ctxt = priv_data; + u64 resp_header; + u8 resp_status; + + if (!SSS_TO_HWDEV(ctxt)->chip_present_flag) { + pr_err("Fail to resp chip present"); + return SSS_PROCESS_ERR; + } + + resp_header = be64_to_cpu(ctxt->reply_fmt->head); + rmb(); /* read the latest header */ + + if (SSSNIC_API_CMD_RESP_HEADER_VALID(resp_header)) { + resp_status = SSSNIC_API_CMD_RESP_HEAD_GET(resp_header, STATUS); + if (resp_status) { + pr_err("Api chain response data err, status: %u\n", + resp_status); + return SSS_PROCESS_ERR; + } + + return SSS_PROCESS_OK; + } + + return SSS_PROCESS_DOING; +} + static int sss_wait_for_state_poll(struct sss_adm_msg *adm_msg) { return sss_check_handler_timeout(adm_msg, sss_wait_for_state_poll_handler, SSS_ADM_MSG_STATE_TIMEOUT, 100); /* wait 100 us once */ } +static int wait_for_resp_polling(struct sss_adm_msg_elem_ctx *ctx) +{ + return sss_check_handler_timeout(ctx, check_cmd_resp_handler, + POLLING_COMPLETION_TIMEOUT_DEFAULT, + USEC_PER_MSEC); +} + +static void copy_resp_data(struct sss_adm_msg_elem_ctx *ctx, void *ack, + u16 ack_size) +{ + struct sss_adm_msg_reply_fmt *resp = ctx->reply_fmt; + + memcpy(ack, &resp->reply, ack_size); + ctx->state = 0; +} + static int sss_wait_for_adm_msg_completion(struct sss_adm_msg *adm_msg, - struct sss_adm_msg_elem_ctx *ctx) + struct sss_adm_msg_elem_ctx *ctx, + void *ack, u16 ack_size) { int ret = 0; - ret = sss_wait_for_state_poll(adm_msg); - if (ret != 0) { - sdk_err(SSS_TO_HWDEV(adm_msg)->dev_hdl, "Adm msg poll state timeout\n"); + switch (adm_msg->msg_type) { + case SSS_ADM_MSG_POLL_READ: + ret = wait_for_resp_polling(ctx); + if (ret == 0) + copy_resp_data(ctx, ack, ack_size); + else + sdk_err(SSS_TO_HWDEV(adm_msg)->dev_hdl, "API CMD poll response timeout\n"); + break; + case SSS_ADM_MSG_POLL_WRITE: + case SSS_ADM_MSG_WRITE_TO_MGMT_MODULE: + ret = sss_wait_for_state_poll(adm_msg); + break; + case SSS_ADM_MSG_WRITE_ASYNC_TO_MGMT_MODULE: + /* No need to wait */ + break; + default: + sdk_err(SSS_TO_HWDEV(adm_msg)->dev_hdl, "Unknown API CMD Chain type: %d\n", + adm_msg->msg_type); + ret = -EINVAL; + } + + if (ret) { sss_dump_adm_msg_reg(adm_msg); + sdk_err(SSS_TO_HWDEV(adm_msg)->dev_hdl, "Adm msg wait timeout,type :%d\n", + adm_msg->msg_type); } return ret; @@ -381,25 +497,25 @@ static inline void sss_update_adm_msg_ctx(struct sss_adm_msg *adm_msg) static void sss_adm_msg_lock(struct sss_adm_msg *adm_msg) { - down(&adm_msg->sem); + if (adm_msg->msg_type == SSS_ADM_MSG_WRITE_ASYNC_TO_MGMT_MODULE) + spin_lock(&adm_msg->async_lock); + else + down(&adm_msg->sem); } static void sss_adm_msg_unlock(struct sss_adm_msg *adm_msg) { - up(&adm_msg->sem); + if (adm_msg->msg_type == SSS_ADM_MSG_WRITE_ASYNC_TO_MGMT_MODULE) + spin_unlock(&adm_msg->async_lock); + else + up(&adm_msg->sem); } -static int sss_send_adm_cmd(struct sss_adm_msg *adm_msg, u8 node_id, - const void *cmd, u16 cmd_size) +static int sss_adm_msg_io(struct sss_adm_msg *adm_msg, u8 node_id, + const void *cmd, u16 cmd_size, void *ack, u16 ack_size) { struct sss_adm_msg_elem_ctx *ctx = NULL; - if (adm_msg->msg_type != SSS_ADM_MSG_WRITE_TO_MGMT_MODULE) { - sdk_err(SSS_TO_HWDEV(adm_msg)->dev_hdl, - "Unsupport adm cmd type: %d\n", adm_msg->msg_type); - return -EINVAL; - } - sss_adm_msg_lock(adm_msg); ctx = &adm_msg->elem_ctx[adm_msg->pi]; @@ -423,7 +539,19 @@ static int sss_send_adm_cmd(struct sss_adm_msg *adm_msg, u8 node_id, sss_adm_msg_unlock(adm_msg); - return sss_wait_for_adm_msg_completion(adm_msg, ctx); + return sss_wait_for_adm_msg_completion(adm_msg, ctx, ack, ack_size); +} + +int sss_adm_msg_write(struct sss_adm_msg *adm_msg, u8 node_id, + const void *cmd, u16 cmd_size) +{ + return sss_adm_msg_io(adm_msg, node_id, cmd, cmd_size, NULL, 0); +} + +int sss_adm_msg_read(struct sss_adm_msg *adm_msg, u8 node_id, + const void *cmd, u16 size, void *ack, u16 ack_size) +{ + return sss_adm_msg_io(adm_msg, node_id, cmd, size, ack, ack_size); } static void sss_set_adm_event_flag(struct sss_msg_pf_to_mgmt *pf_to_mgmt, @@ -464,15 +592,61 @@ static void sss_encapsulate_adm_msg(u8 *adm_msg, u64 *header, memcpy(adm_msg_new, body, (size_t)(u32)body_len); } +#define SSS_MAX_PF_MGMT_BUF_MAX 2048L + +int sss_adm_msg_read_ack(void *hwdev, u8 dest, const void *cmd, + u16 size, void *ack, u16 ack_size) +{ + struct sss_msg_pf_to_mgmt *pf_to_mgmt = NULL; + struct sss_adm_msg *adm_mag = NULL; + + if (!hwdev || !cmd || (ack_size && !ack) || size > SSS_MAX_PF_MGMT_BUF_MAX) + return -EINVAL; + + if (!SSS_SUPPORT_ADM_MSG((struct sss_hwdev *)hwdev)) + return -EPERM; + + pf_to_mgmt = ((struct sss_hwdev *)hwdev)->pf_to_mgmt; + adm_mag = pf_to_mgmt->adm_msg[SSS_ADM_MSG_POLL_READ]; + + if (!(((struct sss_hwdev *)hwdev)->chip_present_flag)) + return -EPERM; + + return sss_adm_msg_read(adm_mag, dest, cmd, size, ack, ack_size); +} + +int sss_adm_msg_write_nack(void *hwdev, u8 dest, const void *cmd, u16 size) +{ + struct sss_msg_pf_to_mgmt *pf_to_mgmt = NULL; + struct sss_adm_msg *adm_mag = NULL; + + if (!hwdev || !size || !cmd || size > SSS_MAX_PF_MGMT_BUF_MAX) + return -EINVAL; + + if (!SSS_SUPPORT_ADM_MSG((struct sss_hwdev *)hwdev)) + return -EPERM; + + pf_to_mgmt = ((struct sss_hwdev *)hwdev)->pf_to_mgmt; + adm_mag = pf_to_mgmt->adm_msg[SSS_ADM_MSG_POLL_WRITE]; + + if (!(((struct sss_hwdev *)hwdev)->chip_present_flag)) + return -EPERM; + + return sss_adm_msg_write(adm_mag, dest, cmd, size); +} + +#define SSS_MSG_NO_RESP 0xFFFF + static int sss_send_adm_msg(struct sss_msg_pf_to_mgmt *pf_to_mgmt, u8 mod, u16 cmd, const void *msg_body, u16 msg_body_len) { struct sss_hwif *hwif = SSS_TO_HWDEV(pf_to_mgmt)->hwif; - void *adm_msg = pf_to_mgmt->sync_buf; + void *msg_buf = pf_to_mgmt->sync_buf; u16 adm_msg_len = sss_align_adm_msg_len(msg_body_len); u32 func_id = SSS_GET_HWIF_GLOBAL_ID(hwif); u8 node_id = SSS_MGMT_CPU_NODE_ID(SSS_TO_HWDEV(pf_to_mgmt)); u64 header; + struct sss_adm_msg *adm_mag; if (sss_get_dev_present_flag(pf_to_mgmt->hwdev) == 0) return -EFAULT; @@ -481,13 +655,15 @@ static int sss_send_adm_msg(struct sss_msg_pf_to_mgmt *pf_to_mgmt, return -EFAULT; sss_set_adm_event_flag(pf_to_mgmt, SSS_ADM_EVENT_START); - SSS_INCREASE_SYNC_MSG_ID(pf_to_mgmt); header = SSS_ENCAPSULATE_ADM_MSG_HEAD(func_id, msg_body_len, mod, - cmd, SSS_SYNC_MSG_ID(pf_to_mgmt)); - sss_encapsulate_adm_msg((u8 *)adm_msg, &header, msg_body, msg_body_len); + cmd, SSS_INCREASE_SYNC_MSG_ID(pf_to_mgmt)); + + sss_encapsulate_adm_msg((u8 *)msg_buf, &header, msg_body, msg_body_len); + + adm_mag = pf_to_mgmt->adm_msg[SSS_ADM_MSG_WRITE_TO_MGMT_MODULE]; - return sss_send_adm_cmd(&pf_to_mgmt->adm_msg, node_id, adm_msg, adm_msg_len); + return sss_adm_msg_write(adm_mag, node_id, msg_buf, adm_msg_len); } static inline void sss_check_msg_body(u8 mod, void *buf_in) diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm.h b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm.h index d8574cfeca14..54cfe231e631 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm.h +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm.h @@ -5,6 +5,10 @@ #define SSS_HWIF_ADM_H #include +int sss_adm_msg_read_ack(void *hwdev, u8 dest, const void *cmd, + u16 size, void *ack, u16 ack_size); + +int sss_adm_msg_write_nack(void *hwdev, u8 dest, const void *cmd, u16 size); int sss_sync_send_adm_msg(void *hwdev, u8 mod, u16 cmd, void *buf_in, u16 in_size, void *buf_out, u16 *out_size, u32 timeout); diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm_common.h b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm_common.h index be75837fd033..fc0d99e326ad 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm_common.h +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm_common.h @@ -4,6 +4,19 @@ #ifndef SSS_HWIF_ADM_COMMON_H #define SSS_HWIF_ADM_COMMON_H +#define SSS_ADM_MSG_AEQ_ID 2 + +#define SSS_WRITE_ADM_MSG_PRIV_DATA(id) (((u8)(id)) << 16) +#define SSS_READ_ADM_MSG_PRIV_DATA(id, token) ((((u32)(id)) << 16) + (token)) + +#define SSS_MASK_ID(adm_msg, id) \ + ((id) & ((adm_msg)->elem_num - 1)) + +#define SSS_SIZE_TO_4B(size) \ + (ALIGN((u32)(size), 4U) >> 2) +#define SSS_SIZE_TO_8B(size) \ + (ALIGN((u32)(size), 8U) >> 3) + /* ADM_STATUS_0 CSR: 0x0030+adm msg id*0x080 */ #define SSS_ADM_MSG_STATE_CI_MASK 0xFFFFFFU #define SSS_ADM_MSG_STATE_CI_SHIFT 0 @@ -20,4 +33,47 @@ #define SSS_GET_ADM_MSG_STATE(val, member) \ (((val) >> SSS_ADM_MSG_STATE_##member##_SHIFT) & \ SSS_ADM_MSG_STATE_##member##_MASK) + +/* adm_msg_elem.desc structure */ +#define SSS_ADM_MSG_DESC_SGL_TYPE_SHIFT 0 +#define SSS_ADM_MSG_DESC_RD_WR_SHIFT 1 +#define SSS_ADM_MSG_DESC_MGMT_BYPASS_SHIFT 2 +#define SSS_ADM_MSG_DESC_REPLY_AEQE_EN_SHIFT 3 +#define SSS_ADM_MSG_DESC_MSG_VALID_SHIFT 4 +#define SSS_ADM_MSG_DESC_MSG_CHANNEL_SHIFT 6 +#define SSS_ADM_MSG_DESC_PRIV_DATA_SHIFT 8 +#define SSS_ADM_MSG_DESC_DEST_SHIFT 32 +#define SSS_ADM_MSG_DESC_SIZE_SHIFT 40 +#define SSS_ADM_MSG_DESC_XOR_CHKSUM_SHIFT 56 + +#define SSS_ADM_MSG_DESC_SGL_TYPE_MASK 0x1U +#define SSS_ADM_MSG_DESC_RD_WR_MASK 0x1U +#define SSS_ADM_MSG_DESC_MGMT_BYPASS_MASK 0x1U +#define SSS_ADM_MSG_DESC_REPLY_AEQE_EN_MASK 0x1U +#define SSS_ADM_MSG_DESC_MSG_VALID_MASK 0x3U +#define SSS_ADM_MSG_DESC_MSG_CHANNEL_MASK 0x3U +#define SSS_ADM_MSG_DESC_PRIV_DATA_MASK 0xFFFFFFU +#define SSS_ADM_MSG_DESC_DEST_MASK 0x1FU +#define SSS_ADM_MSG_DESC_SIZE_MASK 0x7FFU +#define SSS_ADM_MSG_DESC_XOR_CHKSUM_MASK 0xFFU + +#define SSS_ADM_MSG_DESC_SET(val, member) \ + ((((u64)(val)) & SSS_ADM_MSG_DESC_##member##_MASK) << \ + SSS_ADM_MSG_DESC_##member##_SHIFT) + +/* adm_msg_elem structure */ +#define SSS_ADM_MSG_ELEM_CTRL_ELEM_LEN_SHIFT 0 +#define SSS_ADM_MSG_ELEM_CTRL_RD_DMA_ATTR_OFF_SHIFT 16 +#define SSS_ADM_MSG_ELEM_CTRL_WR_DMA_ATTR_OFF_SHIFT 24 +#define SSS_ADM_MSG_ELEM_CTRL_XOR_CHKSUM_SHIFT 56 + +#define SSS_ADM_MSG_ELEM_CTRL_ELEM_LEN_MASK 0x3FU +#define SSS_ADM_MSG_ELEM_CTRL_RD_DMA_ATTR_OFF_MASK 0x3FU +#define SSS_ADM_MSG_ELEM_CTRL_WR_DMA_ATTR_OFF_MASK 0x3FU +#define SSS_ADM_MSG_ELEM_CTRL_XOR_CHKSUM_MASK 0xFFU + +#define SSS_ADM_MSG_ELEM_CTRL_SET(val, member) \ + ((((u64)(val)) & SSS_ADM_MSG_ELEM_CTRL_##member##_MASK) << \ + SSS_ADM_MSG_ELEM_CTRL_##member##_SHIFT) + #endif diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm_init.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm_init.c index 8109c34650c1..e418b29f4fc0 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm_init.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_adm_init.c @@ -310,9 +310,28 @@ static void sss_init_ctx_buf_reply_addr(struct sss_adm_msg *adm_msg, elem->read.hw_msg_paddr = cpu_to_be64(buf_paddr); } +static void sss_alloc_reply_buf(struct sss_adm_msg *adm_msg, + struct sss_adm_msg_elem *elem, u32 cell_idx) +{ + struct sss_adm_msg_elem_ctx *ctx = NULL; + void *resp_vaddr; + u64 resp_paddr; + + resp_vaddr = (u8 *)((u64)adm_msg->reply_vaddr_base + + adm_msg->reply_size_align * cell_idx); + resp_paddr = adm_msg->reply_paddr_base + + adm_msg->reply_size_align * cell_idx; + + ctx = &adm_msg->elem_ctx[cell_idx]; + + ctx->reply_fmt = resp_vaddr; + elem->read.hw_wb_reply_paddr = cpu_to_be64(resp_paddr); +} + static int sss_init_elem_ctx(struct sss_adm_msg *adm_msg, u32 elem_id) { struct sss_adm_msg_elem_ctx *ctx = NULL; + struct sss_adm_msg_elem *elem; sss_alloc_elem_buf_handler_t handler[] = { NULL, NULL, @@ -322,6 +341,11 @@ static int sss_init_elem_ctx(struct sss_adm_msg *adm_msg, u32 elem_id) sss_init_ctx_buf_reply_addr, sss_init_ctx_buf_addr }; + elem = (struct sss_adm_msg_elem *)SSS_GET_ADM_MSG_ELEM_VADDR(adm_msg, elem_id); + + if (adm_msg->msg_type == SSS_ADM_MSG_MULTI_READ || + adm_msg->msg_type == SSS_ADM_MSG_POLL_READ) + sss_alloc_reply_buf(adm_msg, elem, elem_id); ctx = &adm_msg->elem_ctx[elem_id]; ctx->elem_vaddr = @@ -379,17 +403,6 @@ static int sss_init_adm_msg_elem(struct sss_adm_msg *adm_msg) return 0; } -static void sss_init_adm_msg_param(struct sss_adm_msg *adm_msg, - struct sss_hwdev *hwdev) -{ - adm_msg->hwdev = hwdev; - adm_msg->elem_num = SSS_ADM_MSG_ELEM_NUM; - adm_msg->reply_size = SSS_ADM_MSG_REPLY_DATA_SIZE; - adm_msg->elem_size = SSS_ADM_MSG_ELEM_SIZE; - adm_msg->msg_type = SSS_ADM_MSG_WRITE_TO_MGMT_MODULE; - sema_init(&adm_msg->sem, 1); -} - static int sss_alloc_adm_msg_ctx(struct sss_adm_msg *adm_msg) { size_t ctx_size; @@ -512,46 +525,105 @@ static void sss_free_adm_msg_buf(struct sss_adm_msg *adm_msg) sss_free_adm_msg_ctx(adm_msg); } -static int sss_init_adm_msg(struct sss_hwdev *hwdev, - struct sss_adm_msg *adm_msg) +static void sss_init_adm_msg_param(struct sss_adm_msg *adm_msg, + struct sss_hwdev *hwdev, u8 msg_type) { + adm_msg->hwdev = hwdev; + adm_msg->elem_num = SSS_ADM_MSG_ELEM_NUM; + adm_msg->reply_size = SSS_ADM_MSG_REPLY_DATA_SIZE; + adm_msg->elem_size = SSS_ADM_MSG_ELEM_SIZE; + adm_msg->msg_type = msg_type; + adm_msg->pi = 0; + adm_msg->ci = 0; + if (adm_msg->msg_type == SSS_ADM_MSG_WRITE_ASYNC_TO_MGMT_MODULE) + spin_lock_init(&adm_msg->async_lock); + else + sema_init(&adm_msg->sem, 1); +} + +static int create_adm_msg(struct sss_hwdev *hwdev, struct sss_adm_msg **adm_msg, u8 msg_type) +{ + struct sss_adm_msg *msg; int ret; - if (!SSS_SUPPORT_ADM_MSG(hwdev)) - return 0; + msg = kzalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; - sss_init_adm_msg_param(adm_msg, hwdev); + sss_init_adm_msg_param(msg, hwdev, msg_type); - ret = sss_alloc_adm_msg_buf(adm_msg); + ret = sss_alloc_adm_msg_buf(msg); if (ret != 0) { sdk_err(hwdev->dev_hdl, "Fail to init adm msg buf\n"); return ret; } - ret = sss_init_adm_msg_elem(adm_msg); + ret = sss_init_adm_msg_elem(msg); if (ret != 0) { sdk_err(hwdev->dev_hdl, "Fail to init adm msg elem\n"); - sss_free_adm_msg_buf(adm_msg); + sss_free_adm_msg_buf(msg); return ret; } - ret = sss_chip_init_adm_msg(adm_msg); + ret = sss_chip_init_adm_msg(msg); if (ret != 0) { sdk_err(hwdev->dev_hdl, "Fail to init adm msg\n"); - sss_free_adm_msg_buf(adm_msg); + sss_free_adm_msg_buf(msg); return ret; } + *adm_msg = msg; + return 0; } +void sss_destroy_adm_msg(struct sss_adm_msg *adm_msg) +{ + sss_free_adm_msg_buf(adm_msg); + kfree(adm_msg); +} + +static int sss_init_adm_msg(struct sss_hwdev *hwdev, + struct sss_adm_msg **adm_msg) +{ + int ret; + u8 i; + u8 adm_msg_type; + void *dev = ((struct sss_hwdev *)hwdev)->dev_hdl; + + if (!SSS_SUPPORT_ADM_MSG(hwdev)) + return 0; + + for (adm_msg_type = SSS_ADM_MSG_WRITE_TO_MGMT_MODULE; + adm_msg_type < SSS_ADM_MSG_MAX; adm_msg_type++) { + ret = create_adm_msg(hwdev, &adm_msg[adm_msg_type], adm_msg_type); + if (ret) { + sdk_err(dev, "Failed to create adm msg %d\n", adm_msg_type); + goto create_adm_msg_err; + } + } + + return 0; + +create_adm_msg_err: + for (i = SSS_ADM_MSG_WRITE_TO_MGMT_MODULE; i < adm_msg_type; i++) + sss_destroy_adm_msg(hwdev->pf_to_mgmt->adm_msg[adm_msg_type]); + + return ret; +} + static void sss_deinit_adm_msg(const struct sss_hwdev *hwdev, - struct sss_adm_msg *adm_msg) + struct sss_adm_msg **adm_msg) { + u8 adm_msg_type; + if (!SSS_SUPPORT_ADM_MSG(hwdev)) return; - sss_free_adm_msg_buf(adm_msg); + for (adm_msg_type = SSS_ADM_MSG_WRITE_TO_MGMT_MODULE; + adm_msg_type < SSS_ADM_MSG_MAX; adm_msg_type++) + sss_destroy_adm_msg(adm_msg[adm_msg_type]); + } static int sss_alloc_msg_buf(struct sss_msg_pf_to_mgmt *mgmt_msg) @@ -578,8 +650,15 @@ static int sss_alloc_msg_buf(struct sss_msg_pf_to_mgmt *mgmt_msg) if (!mgmt_msg->sync_buf) goto alloc_sync_buf_err; + mgmt_msg->async_msg_buf = kzalloc(SSS_PF_MGMT_BUF_LEN_MAX, GFP_KERNEL); + if (!mgmt_msg->async_msg_buf) + goto alloc_async_msg_buf_err; + return 0; +alloc_async_msg_buf_err: + kfree(mgmt_msg->sync_buf); + mgmt_msg->sync_buf = NULL; alloc_sync_buf_err: kfree(mgmt_msg->ack_buf); mgmt_msg->ack_buf = NULL; @@ -600,6 +679,7 @@ static void sss_free_msg_buf(struct sss_msg_pf_to_mgmt *mgmt_msg) struct sss_recv_msg *recv_msg = &mgmt_msg->recv_msg; struct sss_recv_msg *resp_msg = &mgmt_msg->recv_resp_msg; + kfree(mgmt_msg->async_msg_buf); kfree(mgmt_msg->sync_buf); kfree(mgmt_msg->ack_buf); kfree(resp_msg->buf); @@ -615,6 +695,7 @@ int sss_hwif_init_adm(struct sss_hwdev *hwdev) if (!mgmt_msg) return -ENOMEM; + spin_lock_init(&mgmt_msg->async_msg_lock); spin_lock_init(&mgmt_msg->sync_event_lock); sema_init(&mgmt_msg->sync_lock, 1); mgmt_msg->hwdev = hwdev; @@ -633,7 +714,7 @@ int sss_hwif_init_adm(struct sss_hwdev *hwdev) goto alloc_msg_buf_err; } - ret = sss_init_adm_msg(hwdev, &mgmt_msg->adm_msg); + ret = sss_init_adm_msg(hwdev, mgmt_msg->adm_msg); if (ret != 0) { sdk_err(hwdev->dev_hdl, "Fail to init adm msg\n"); goto init_all_adm_err; @@ -660,7 +741,7 @@ void sss_hwif_deinit_adm(struct sss_hwdev *hwdev) destroy_workqueue(mgmt_msg->workq); - sss_deinit_adm_msg(hwdev, &mgmt_msg->adm_msg); + sss_deinit_adm_msg(hwdev, mgmt_msg->adm_msg); sss_free_msg_buf(mgmt_msg); diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_ctrlq.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_ctrlq.c index 432c57856b62..43386b7984b9 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_ctrlq.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_ctrlq.c @@ -261,7 +261,7 @@ struct sss_ctrlq_wqe { }; }; -typedef void (*sss_ctrlq_type_handler_t)(struct sss_ctrlq *ctrlq, +typedef int (*sss_ctrlq_type_handler_t)(struct sss_ctrlq *ctrlq, struct sss_ctrlq_wqe *wqe, u16 ci); void *sss_ctrlq_read_wqe(struct sss_wq *wq, u16 *ci) @@ -801,58 +801,66 @@ static void sss_ctrlq_update_cmd_info(struct sss_ctrlq *ctrlq, spin_unlock(&ctrlq->ctrlq_lock); } -static void sss_ctrlq_arm_ceq_handler(struct sss_ctrlq *ctrlq, - struct sss_ctrlq_wqe *wqe, u16 ci) +static int sss_ctrlq_arm_ceq_handler(struct sss_ctrlq *ctrlq, + struct sss_ctrlq_wqe *wqe, u16 ci) { struct sss_wqe_ctrl *ctrl = &wqe->inline_wqe.wqe_scmd.ctrl; u32 info = sss_hw_cpu32((ctrl)->info); if (!SSS_WQE_COMPLETE(info)) - return; + return -EBUSY; sss_erase_wqe_complete_bit(ctrlq, wqe, ci); + + return 0; } -static void sss_ctrlq_default_handler(struct sss_ctrlq *ctrlq, - struct sss_ctrlq_wqe *wqe, u16 ci) +static int sss_ctrlq_default_handler(struct sss_ctrlq *ctrlq, + struct sss_ctrlq_wqe *wqe, u16 ci) { struct sss_wqe_ctrl *ctrl = &wqe->wqe_lcmd.ctrl; u32 info = sss_hw_cpu32((ctrl)->info); if (!SSS_WQE_COMPLETE(info)) - return; + return -EBUSY; dma_rmb(); sss_ctrlq_update_cmd_info(ctrlq, wqe, ci); sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]); sss_erase_wqe_complete_bit(ctrlq, wqe, ci); + + return 0; } -static void sss_ctrlq_async_cmd_handler(struct sss_ctrlq *ctrlq, - struct sss_ctrlq_wqe *wqe, u16 ci) +static int sss_ctrlq_async_cmd_handler(struct sss_ctrlq *ctrlq, + struct sss_ctrlq_wqe *wqe, u16 ci) { struct sss_wqe_ctrl *ctrl = &wqe->wqe_lcmd.ctrl; u32 info = sss_hw_cpu32((ctrl)->info); if (!SSS_WQE_COMPLETE(info)) - return; + return -EBUSY; dma_rmb(); sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]); sss_erase_wqe_complete_bit(ctrlq, wqe, ci); + + return 0; } -static void sss_ctrlq_pseudo_timeout_handler(struct sss_ctrlq *ctrlq, - struct sss_ctrlq_wqe *wqe, u16 ci) +static int sss_ctrlq_pseudo_timeout_handler(struct sss_ctrlq *ctrlq, + struct sss_ctrlq_wqe *wqe, u16 ci) { sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]); sss_erase_wqe_complete_bit(ctrlq, wqe, ci); + + return 0; } -static void sss_ctrlq_timeout_handler(struct sss_ctrlq *ctrlq, - struct sss_ctrlq_wqe *wqe, u16 ci) +static int sss_ctrlq_timeout_handler(struct sss_ctrlq *ctrlq, + struct sss_ctrlq_wqe *wqe, u16 ci) { u32 i; u32 *data = (u32 *)wqe; @@ -868,17 +876,20 @@ static void sss_ctrlq_timeout_handler(struct sss_ctrlq *ctrlq, sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]); sss_erase_wqe_complete_bit(ctrlq, wqe, ci); + + return 0; } -static void sss_ctrlq_force_stop_handler(struct sss_ctrlq *ctrlq, - struct sss_ctrlq_wqe *wqe, u16 ci) +static int sss_ctrlq_force_stop_handler(struct sss_ctrlq *ctrlq, + struct sss_ctrlq_wqe *wqe, u16 ci) { - sss_ctrlq_async_cmd_handler(ctrlq, wqe, ci); + return sss_ctrlq_async_cmd_handler(ctrlq, wqe, ci); } void sss_ctrlq_ceq_handler(void *dev, u32 data) { u16 ci; + int ret; enum sss_ctrlq_type type = SSS_GET_CEQE_CTRLQ(data, TYPE); struct sss_ctrlq *ctrlq = &SSS_TO_CTRLQ_INFO(dev)->ctrlq[type]; struct sss_ctrlq_wqe *ctrlq_wqe = NULL; @@ -895,17 +906,23 @@ void sss_ctrlq_ceq_handler(void *dev, u32 data) sss_ctrlq_force_stop_handler, }; - ctrlq_wqe = sss_ctrlq_read_wqe(&ctrlq->wq, &ci); - if (!ctrlq_wqe) - return; + while ((ctrlq_wqe = sss_ctrlq_read_wqe(&ctrlq->wq, &ci)) != NULL) { + info = &ctrlq->cmd_info[ci]; - info = &ctrlq->cmd_info[ci]; - if (info->msg_type < SSS_MSG_TYPE_NONE || - info->msg_type >= SSS_MSG_TYPE_MAX) { - sss_ctrlq_default_handler(ctrlq, ctrlq_wqe, ci); - return; - } + if (info->msg_type < SSS_MSG_TYPE_NONE || + info->msg_type >= SSS_MSG_TYPE_MAX) { + ret = sss_ctrlq_default_handler(ctrlq, ctrlq_wqe, ci); + if (ret) + break; + + continue; + } + + if (!handler[info->msg_type]) + break; - if (handler[info->msg_type]) - handler[info->msg_type](ctrlq, ctrlq_wqe, ci); + ret = handler[info->msg_type](ctrlq, ctrlq_wqe, ci); + if (ret) + break; + } } diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_export.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_export.c index f84b05749718..c4639c18297b 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_export.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_export.c @@ -119,6 +119,15 @@ enum sss_func_type sss_get_func_type(void *hwdev) } EXPORT_SYMBOL(sss_get_func_type); +enum sss_func_type sss_get_func_id(void *hwdev) +{ + if (!hwdev) + return 0; + + return SSS_GET_FUNC_ID((struct sss_hwdev *)hwdev); +} +EXPORT_SYMBOL(sss_get_func_id); + u16 sss_get_glb_pf_vf_offset(void *hwdev) { if (!hwdev) diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_mbx_init.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_mbx_init.c index ba62f2772add..0725cf2cd4b1 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_mbx_init.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_hwif_mbx_init.c @@ -18,6 +18,7 @@ #include "sss_hwif_mbx.h" #include "sss_csr.h" #include "sss_common.h" +#include "sss_adapter_mgmt.h" #define SSS_MBX_WB_STATUS_SIZE 16UL @@ -25,8 +26,6 @@ #define SSS_MBX_WQ_NAME "sss_mbx" -#define SSS_MAX_FUNC 4096 - #define SSS_MBX_AREA(hwif) \ ((hwif)->cfg_reg_base + SSS_HW_CSR_MBX_DATA_OFF) @@ -449,18 +448,21 @@ int sss_hwif_init_mbx(struct sss_hwdev *hwdev) void sss_hwif_deinit_mbx(struct sss_hwdev *hwdev) { - struct sss_mbx *mdx = hwdev->mbx; + struct sss_mbx *mbx = hwdev->mbx; - destroy_workqueue(mdx->workq); - mdx->workq = NULL; + destroy_workqueue(mbx->workq); + mbx->workq = NULL; - sss_chip_reset_mbx_attr(mdx); + sss_chip_reset_mbx_attr(mbx); - sss_free_host_msg(mdx); + sss_free_host_msg(mbx); - sss_deinit_func_mbx_msg(mdx); + sss_deinit_func_mbx_msg(mbx); - sss_deinit_mbx_info(mdx); + sss_deinit_mbx_info(mbx); + + kfree(mbx); + hwdev->mbx = NULL; } static bool sss_check_mbx_msg_header(void *dev_hdl, @@ -725,7 +727,7 @@ static void sss_recv_mbx_handler(struct sss_mbx *mbx, int ret = 0; void *resp_buf = recv_mbx->resp_buf; u16 size = SSS_MBX_DATA_SIZE; - u16 src_func_id; + u16 src_func_id = recv_mbx->src_func_id; struct sss_hwdev *hwdev = SSS_TO_HWDEV(mbx); if (SSS_IS_VF(hwdev)) { @@ -733,7 +735,6 @@ static void sss_recv_mbx_handler(struct sss_mbx *mbx, goto out; } - src_func_id = recv_mbx->src_func_id; if (SSS_SRC_IS_PF_OR_PPF(hwdev, src_func_id)) { if (SSS_IS_PPF(hwdev)) ret = sss_recv_ppf_mbx_handler(mbx, recv_mbx, diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_error.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_error.c index 2d6494e8d58e..ead8a09435c6 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_error.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_error.c @@ -28,7 +28,7 @@ static void sss_record_pcie_error(void *dev) { struct sss_hwdev *hwdev = (struct sss_hwdev *)dev; - atomic_inc(&hwdev->hw_stats.sss_fault_event_stats.pcie_fault_stats); + atomic_inc(&hwdev->hw_stats.fault_event_stats.pcie_fault_stats); } pci_ers_result_t sss_detect_pci_error(struct pci_dev *pdev, diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_probe.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_probe.c index d1dff858d94e..4f1a865d638a 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_probe.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_probe.c @@ -26,6 +26,7 @@ #include "sss_hwdev_api.h" #include "sss_pci_remove.h" #include "sss_pci_global.h" +#include "sss_tool.h" #define SSS_SYNC_YEAR_OFFSET 1900 #define SSS_SYNC_MONTH_OFFSET 1 @@ -448,6 +449,15 @@ static int sss_init_function(struct pci_dev *pdev, struct sss_pci_adapter *adapt sss_sync_time_to_chip(adapter); } + sss_chip_node_lock(); + ret = sss_tool_init(adapter->hwdev, adapter->chip_node); + if (ret) { + sss_chip_node_unlock(); + sdk_err(&pdev->dev, "Failed to initialize dbgtool\n"); + goto nictool_init_err; + } + sss_chip_node_unlock(); + sss_add_func_list(adapter); ret = sss_attach_uld_dev(adapter); @@ -461,6 +471,10 @@ static int sss_init_function(struct pci_dev *pdev, struct sss_pci_adapter *adapt attach_uld_err: sss_del_func_list(adapter); + sss_chip_node_lock(); + sss_tool_uninit(adapter->hwdev, adapter->chip_node); + sss_chip_node_unlock(); +nictool_init_err: sss_unregister_dev_event(adapter->hwdev); sss_deinit_hwdev(adapter->hwdev); diff --git a/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_remove.c b/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_remove.c index 5622065518bf..8a9bf5277183 100644 --- a/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_remove.c +++ b/drivers/net/ethernet/3snic/sssnic/hw/sss_pci_remove.c @@ -26,6 +26,7 @@ #include "sss_hwdev_api.h" #include "sss_hwif_mgmt_init.h" #include "sss_pci_global.h" +#include "sss_tool.h" #define SSS_WAIT_SRIOV_CFG_TIMEOUT 15000 #define SSS_EVENT_PROCESS_TIMEOUT 10000 @@ -185,6 +186,10 @@ void sss_deinit_function(struct pci_dev *pdev) sss_del_func_list(adapter); + sss_chip_node_lock(); + sss_tool_uninit(adapter->hwdev, adapter->chip_node); + sss_chip_node_unlock(); + sss_dettach_uld_dev(adapter); sss_unregister_dev_event(adapter->hwdev); diff --git a/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool.h b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool.h new file mode 100644 index 000000000000..92e474e81ba8 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSSNIC_NICTOOL_H +#define SSSNIC_NICTOOL_H + +#include "sss_tool_chip.h" +#include "sss_tool_sdk.h" +#include "sss_tool_sm.h" +#include "sss_tool_comm.h" + +#ifndef _LLT_TEST_ +#define SSS_TOOL_PAGE_ORDER (10) +#else +#define SSS_TOOL_PAGE_ORDER (1) +#endif + +#define SSS_TOOL_MEM_MAP_SIZE (PAGE_SIZE * (1 << SSS_TOOL_PAGE_ORDER)) + +#define SSS_TOOL_CARD_MAX (64) + +int sss_tool_init(void *hwdev, void *chip_node); +void sss_tool_uninit(void *hwdev, void *chip_node); + +extern u64 g_card_pa[SSS_TOOL_CARD_MAX]; +extern void *g_card_va[SSS_TOOL_CARD_MAX]; +extern int g_card_id; + +#endif + diff --git a/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_chip.c b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_chip.c new file mode 100644 index 000000000000..21833df254b5 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_chip.c @@ -0,0 +1,802 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ +#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sss_kernel.h" +#include "sss_hwdev.h" +#include "sss_common.h" +#include "sss_pci_sriov.h" +#include "sss_adapter_mgmt.h" +#include "sss_hwif_adm.h" +#include "sss_hwif_adm_common.h" +#include "sss_hwif_mgmt_common.h" +#include "sss_hwif_ctrlq.h" +#include "sss_hwif_api.h" +#include "sss_hw_common.h" +#include "sss_mgmt_channel.h" +#include "sss_linux_kernel.h" +#include "sss_csr.h" +#include "sss_hw.h" +#include "sss_adapter.h" +#include "sss_tool.h" + +#define SSS_TOOL_DW_WIDTH 4 + +/* completion timeout interval, unit is millisecond */ +#define SSS_TOOL_UPDATE_MSG_TIMEOUT 50000U + +#define SSS_TOOL_CLP_REG_GAP 0x20 +#define SSS_TOOL_CLP_INPUT_BUF_LEN 4096UL +#define SSS_TOOL_CLP_DATA_UNIT 4UL +#define SSS_TOOL_CLP_MAX_DATA_SIZE (SSS_TOOL_CLP_INPUT_BUF_LEN / SSS_TOOL_CLP_DATA_UNIT) + +#define SSS_TOOL_CLP_REQ_SIZE_OFFSET 0 +#define SSS_TOOL_CLP_RSP_SIZE_OFFSET 16 +#define SSS_TOOL_CLP_BASE_OFFSET 0 +#define SSS_TOOL_CLP_LEN_OFFSET 0 +#define SSS_TOOL_CLP_START_OFFSET 31 +#define SSS_TOOL_CLP_READY_OFFSET 31 +#define SSS_TOOL_CLP_OFFSET(member) (SSS_TOOL_CLP_##member##_OFFSET) + +#define SSS_TOOL_CLP_SIZE_MASK 0x7ffUL +#define SSS_TOOL_CLP_BASE_MASK 0x7ffffffUL +#define SSS_TOOL_CLP_LEN_MASK 0x7ffUL +#define SSS_TOOL_CLP_START_MASK 0x1UL +#define SSS_TOOL_CLP_READY_MASK 0x1UL +#define SSS_TOOL_CLP_MASK(member) (SSS_TOOL_CLP_##member##_MASK) + +#define SSS_TOOL_CLP_DELAY_CNT_MAX 200UL +#define SSS_TOOL_CLP_SRAM_SIZE_REG_MAX 0x3ff +#define SSS_TOOL_CLP_SRAM_BASE_REG_MAX 0x7ffffff +#define SSS_TOOL_CLP_LEN_REG_MAX 0x3ff +#define SSS_TOOL_CLP_START_OR_READY_REG_MAX 0x1 + +#define SSS_TOOL_CLP_DATA_REAL_SIZE(in_size, header) \ + (((in_size) + (u16)sizeof(header) + \ + (((in_size) % SSS_TOOL_CLP_DATA_UNIT) ? SSS_TOOL_CLP_DATA_UNIT : 0)) / \ + SSS_TOOL_CLP_DATA_UNIT) + +#define SSS_TOOL_CLP_REG_VALUE(value, offset, mask) \ + (((value) >> SSS_TOOL_CLP_OFFSET(offset)) & SSS_TOOL_CLP_MASK(mask)) + +enum sss_tool_clp_data_type { + SSS_TOOL_CLP_REQ = 0, + SSS_TOOL_CLP_RSP = 1 +}; + +enum sss_tool_clp_reg_type { + SSS_TOOL_CLP_BASE = 0, + SSS_TOOL_CLP_SIZE = 1, + SSS_TOOL_CLP_LEN = 2, + SSS_TOOL_CLP_START_REQ = 3, + SSS_TOOL_CLP_READY_RSP = 4 +}; + +enum SSS_TOOL_ADM_CSR_DATA_OPERATION { + SSS_TOOL_ADM_CSR_WRITE = 0x1E, + SSS_TOOL_ADM_CSR_READ = 0x1F +}; + +enum SSS_TOOL_ADM_CSR_NEED_RESP_DATA { + SSS_TOOL_ADM_CSR_NO_RESP_DATA = 0, + SSS_TOOL_ADM_CSR_NEED_RESP_DATA = 1 +}; + +enum SSS_TOOL_ADM_CSR_DATA_SIZE { + SSS_TOOL_ADM_CSR_DATA_SZ_32 = 0, + SSS_TOOL_ADM_CSR_DATA_SZ_64 = 1 +}; + +struct sss_tool_csr_request_adm_data { + u32 dw0; + + union { + struct { + u32 reserved1:13; + /* this field indicates the write/read data size: + * 2'b00: 32 bits + * 2'b01: 64 bits + * 2'b10~2'b11:reserved + */ + u32 data_size:2; + /* this field indicates that requestor expect receive a + * response data or not. + * 1'b0: expect not to receive a response data. + * 1'b1: expect to receive a response data. + */ + u32 need_response:1; + /* this field indicates the operation that the requestor + * expected. + * 5'b1_1110: write value to csr space. + * 5'b1_1111: read register from csr space. + */ + u32 operation_id:5; + u32 reserved2:6; + /* this field specifies the Src node ID for this API + * request message. + */ + u32 src_node_id:5; + } bits; + + u32 val32; + } dw1; + + union { + struct { + /* it specifies the CSR address. */ + u32 csr_addr:26; + u32 reserved3:6; + } bits; + + u32 val32; + } dw2; + + /* if data_size=2'b01, it is high 32 bits of write data. else, it is + * 32'hFFFF_FFFF. + */ + u32 csr_write_data_h; + /* the low 32 bits of write data. */ + u32 csr_write_data_l; +}; + +struct sss_tool_csr_read { + u32 rd_len; + u32 addr; +}; + +struct sss_tool_csr_write { + u32 rd_len; + u32 addr; + u8 *data; +}; + +static u32 sss_tool_get_timeout_val(enum sss_mod_type mod, u16 cmd) +{ + if (mod == SSS_MOD_TYPE_COMM && + (cmd == SSS_COMM_MGMT_CMD_UPDATE_FW || + cmd == SSS_COMM_MGMT_CMD_UPDATE_BIOS || + cmd == SSS_COMM_MGMT_CMD_ACTIVE_FW || + cmd == SSS_COMM_MGMT_CMD_SWITCH_CFG || + cmd == SSS_COMM_MGMT_CMD_HOT_ACTIVE_FW)) + return SSS_TOOL_UPDATE_MSG_TIMEOUT; + + return 0; /* use default mbox/adm timeout time */ +} + +static int sss_tool_get_clp_reg(void *hwdev, enum sss_tool_clp_data_type data_type, + enum sss_tool_clp_reg_type type, u32 *addr) +{ + switch (type) { + case SSS_TOOL_CLP_BASE: + *addr = (data_type == SSS_TOOL_CLP_REQ) ? + SSS_CLP_REG(REQBASE) : SSS_CLP_REG(RSPBASE); + break; + + case SSS_TOOL_CLP_SIZE: + *addr = SSS_CLP_REG(SIZE); + break; + + case SSS_TOOL_CLP_LEN: + *addr = (data_type == SSS_TOOL_CLP_REQ) ? + SSS_CLP_REG(REQ) : SSS_CLP_REG(RSP); + break; + + case SSS_TOOL_CLP_START_REQ: + *addr = SSS_CLP_REG(REQ); + break; + + case SSS_TOOL_CLP_READY_RSP: + *addr = SSS_CLP_REG(RSP); + break; + + default: + *addr = 0; + break; + } + + return (*addr == 0) ? -EINVAL : 0; +} + +static inline int sss_tool_clp_param_valid(enum sss_tool_clp_data_type data_type, + enum sss_tool_clp_reg_type reg_type) +{ + if (data_type == SSS_TOOL_CLP_REQ && reg_type == SSS_TOOL_CLP_READY_RSP) + return -EINVAL; + + if (data_type == SSS_TOOL_CLP_RSP && reg_type == SSS_TOOL_CLP_START_REQ) + return -EINVAL; + + return 0; +} + +static u32 sss_tool_get_clp_reg_value(struct sss_hwdev *hwdev, + enum sss_tool_clp_data_type data_type, + enum sss_tool_clp_reg_type reg_type, u32 reg_addr) +{ + u32 value; + + value = sss_chip_read_reg(hwdev->hwif, reg_addr); + + switch (reg_type) { + case SSS_TOOL_CLP_BASE: + value = SSS_TOOL_CLP_REG_VALUE(value, BASE, BASE); + break; + + case SSS_TOOL_CLP_SIZE: + if (data_type == SSS_TOOL_CLP_REQ) + value = SSS_TOOL_CLP_REG_VALUE(value, REQ_SIZE, SIZE); + else + value = SSS_TOOL_CLP_REG_VALUE(value, RSP_SIZE, SIZE); + break; + + case SSS_TOOL_CLP_LEN: + value = SSS_TOOL_CLP_REG_VALUE(value, LEN, LEN); + break; + + case SSS_TOOL_CLP_START_REQ: + value = SSS_TOOL_CLP_REG_VALUE(value, START, START); + break; + + case SSS_TOOL_CLP_READY_RSP: + value = SSS_TOOL_CLP_REG_VALUE(value, READY, READY); + break; + + default: + break; + } + + return value; +} + +static int sss_tool_read_clp_reg(struct sss_hwdev *hwdev, + enum sss_tool_clp_data_type data_type, + enum sss_tool_clp_reg_type reg_type, u32 *read_value) +{ + u32 reg_addr; + int ret; + + ret = sss_tool_clp_param_valid(data_type, reg_type); + if (ret) + return ret; + + ret = sss_tool_get_clp_reg(hwdev, data_type, reg_type, ®_addr); + if (ret) + return ret; + + *read_value = sss_tool_get_clp_reg_value(hwdev, data_type, reg_type, reg_addr); + + return 0; +} + +static int sss_tool_check_reg_value(enum sss_tool_clp_reg_type reg_type, u32 value) +{ + if (reg_type == SSS_TOOL_CLP_BASE && + value > SSS_TOOL_CLP_SRAM_BASE_REG_MAX) + return -EINVAL; + + if (reg_type == SSS_TOOL_CLP_SIZE && + value > SSS_TOOL_CLP_SRAM_SIZE_REG_MAX) + return -EINVAL; + + if (reg_type == SSS_TOOL_CLP_LEN && + value > SSS_TOOL_CLP_LEN_REG_MAX) + return -EINVAL; + + if ((reg_type == SSS_TOOL_CLP_START_REQ || + reg_type == SSS_TOOL_CLP_READY_RSP) && + value > SSS_TOOL_CLP_START_OR_READY_REG_MAX) + return -EINVAL; + + return 0; +} + +static int sss_tool_check_clp_init_status(struct sss_hwdev *hwdev) +{ + int ret; + u32 reg_value = 0; + + ret = sss_tool_read_clp_reg(hwdev, SSS_TOOL_CLP_REQ, + SSS_TOOL_CLP_BASE, ®_value); + if (ret || !reg_value) { + tool_err("Fail to read clp reg: 0x%x\n", reg_value); + return -EINVAL; + } + + ret = sss_tool_read_clp_reg(hwdev, SSS_TOOL_CLP_RSP, + SSS_TOOL_CLP_BASE, ®_value); + if (ret || !reg_value) { + tool_err("Fail to read rsp ba value: 0x%x\n", reg_value); + return -EINVAL; + } + + ret = sss_tool_read_clp_reg(hwdev, SSS_TOOL_CLP_REQ, + SSS_TOOL_CLP_SIZE, ®_value); + if (ret || !reg_value) { + tool_err("Fail to read req size\n"); + return -EINVAL; + } + + ret = sss_tool_read_clp_reg(hwdev, SSS_TOOL_CLP_RSP, + SSS_TOOL_CLP_SIZE, ®_value); + if (ret || !reg_value) { + tool_err("Fail to read rsp size\n"); + return -EINVAL; + } + + return 0; +} + +static void sss_tool_write_clp_reg(struct sss_hwdev *hwdev, + enum sss_tool_clp_data_type data_type, + enum sss_tool_clp_reg_type reg_type, u32 value) +{ + u32 reg_addr, reg_value; + + if (sss_tool_clp_param_valid(data_type, reg_type)) + return; + + if (sss_tool_check_reg_value(reg_type, value)) + return; + + if (sss_tool_get_clp_reg(hwdev, data_type, reg_type, ®_addr)) + return; + + reg_value = sss_chip_read_reg(hwdev->hwif, reg_addr); + + switch (reg_type) { + case SSS_TOOL_CLP_LEN: + reg_value &= (~(SSS_TOOL_CLP_MASK(LEN) << SSS_TOOL_CLP_OFFSET(LEN))); + reg_value |= (value << SSS_TOOL_CLP_OFFSET(LEN)); + break; + + case SSS_TOOL_CLP_START_REQ: + reg_value &= (~(SSS_TOOL_CLP_MASK(START) << SSS_TOOL_CLP_OFFSET(START))); + reg_value |= (value << SSS_TOOL_CLP_OFFSET(START)); + break; + + case SSS_TOOL_CLP_READY_RSP: + reg_value &= (~(SSS_TOOL_CLP_MASK(READY) << SSS_TOOL_CLP_OFFSET(READY))); + reg_value |= (value << SSS_TOOL_CLP_OFFSET(READY)); + break; + + default: + return; + } + + sss_chip_write_reg(hwdev->hwif, reg_addr, reg_value); +} + +static int sss_tool_read_clp_data(struct sss_hwdev *hwdev, void *buf_out, u16 *out_size) +{ + int err; + u32 reg = SSS_CLP_DATA(RSP); + u32 ready, delay_cnt; + u32 *ptr = (u32 *)buf_out; + u32 temp_out_size = 0; + + err = sss_tool_read_clp_reg(hwdev, SSS_TOOL_CLP_RSP, + SSS_TOOL_CLP_READY_RSP, &ready); + if (err) + return err; + + delay_cnt = 0; + while (ready == 0) { + usleep_range(9000, 10000); /* sleep 9000 us ~ 10000 us */ + delay_cnt++; + err = sss_tool_read_clp_reg(hwdev, SSS_TOOL_CLP_RSP, + SSS_TOOL_CLP_READY_RSP, &ready); + if (err || delay_cnt > SSS_TOOL_CLP_DELAY_CNT_MAX) { + tool_err("Fail to read clp delay rsp, timeout delay_cnt: %u\n", + delay_cnt); + return -EINVAL; + } + } + + err = sss_tool_read_clp_reg(hwdev, SSS_TOOL_CLP_RSP, + SSS_TOOL_CLP_LEN, &temp_out_size); + if (err) + return err; + + if (temp_out_size > SSS_TOOL_CLP_SRAM_SIZE_REG_MAX || !temp_out_size) { + tool_err("Invalid temp out size: %u\n", temp_out_size); + return -EINVAL; + } + + *out_size = (u16)temp_out_size; + for (; temp_out_size > 0; temp_out_size--) { + *ptr = sss_chip_read_reg(hwdev->hwif, reg); + ptr++; + /* read 4 bytes every time */ + reg = reg + 4; + } + + sss_tool_write_clp_reg(hwdev, SSS_TOOL_CLP_RSP, + SSS_TOOL_CLP_READY_RSP, (u32)0x0); + sss_tool_write_clp_reg(hwdev, SSS_TOOL_CLP_RSP, SSS_TOOL_CLP_LEN, (u32)0x0); + + return 0; +} + +static int sss_tool_write_clp_data(struct sss_hwdev *hwdev, void *buf_in, u16 in_size) +{ + int ret; + u32 reg = SSS_CLP_DATA(REQ); + u32 start = 1; + u32 delay_cnt = 0; + u32 *ptr = (u32 *)buf_in; + u16 size_in = in_size; + + ret = sss_tool_read_clp_reg(hwdev, SSS_TOOL_CLP_REQ, + SSS_TOOL_CLP_START_REQ, &start); + if (ret != 0) + return ret; + + while (start == 1) { + usleep_range(9000, 10000); /* sleep 9000 us ~ 10000 us */ + delay_cnt++; + ret = sss_tool_read_clp_reg(hwdev, SSS_TOOL_CLP_REQ, + SSS_TOOL_CLP_START_REQ, &start); + if (ret || delay_cnt > SSS_TOOL_CLP_DELAY_CNT_MAX) + return -EINVAL; + } + + sss_tool_write_clp_reg(hwdev, SSS_TOOL_CLP_REQ, SSS_TOOL_CLP_LEN, size_in); + sss_tool_write_clp_reg(hwdev, SSS_TOOL_CLP_REQ, SSS_TOOL_CLP_START_REQ, (u32)0x1); + + for (; size_in > 0; size_in--) { + sss_chip_write_reg(hwdev->hwif, reg, *ptr); + ptr++; + reg = reg + sizeof(u32); + } + + return 0; +} + +static void sss_tool_clear_clp_data(struct sss_hwdev *hwdev, + enum sss_tool_clp_data_type data_type) +{ + u32 reg = (data_type == SSS_TOOL_CLP_REQ) ? + SSS_CLP_DATA(REQ) : SSS_CLP_DATA(RSP); + u32 count = SSS_TOOL_CLP_MAX_DATA_SIZE; + + for (; count > 0; count--) { + sss_chip_write_reg(hwdev->hwif, reg, 0x0); + reg = reg + sizeof(u32); + } +} + +static void sss_tool_clp_prepare_header(struct sss_hwdev *hwdev, u64 *header, + u16 msg_len, u8 mod, enum sss_mgmt_cmd cmd) +{ + struct sss_hwif *hwif = hwdev->hwif; + + *header = SSS_SET_MSG_HEADER(msg_len, MSG_LEN) | + SSS_SET_MSG_HEADER(mod, MODULE) | + SSS_SET_MSG_HEADER(msg_len, SEG_LEN) | + SSS_SET_MSG_HEADER(0, NO_ACK) | + SSS_SET_MSG_HEADER(SSS_INLINE_DATA, DATA_TYPE) | + SSS_SET_MSG_HEADER(0, SEQID) | + SSS_SET_MSG_HEADER(SSS_ADM_MSG_AEQ_ID, AEQ_ID) | + SSS_SET_MSG_HEADER(SSS_LAST_SEG, LAST) | + SSS_SET_MSG_HEADER(0, DIRECTION) | + SSS_SET_MSG_HEADER(cmd, CMD) | + SSS_SET_MSG_HEADER(hwif->attr.func_id, SRC_GLB_FUNC_ID) | + SSS_SET_MSG_HEADER(0, MSG_ID); +} + +int sss_tool_send_clp_msg(struct sss_hwdev *hwdev, u8 mod, u16 cmd, const void *buf_in, + u16 in_size, void *buf_out, u16 *out_size) + +{ + struct sss_clp_pf_to_mgmt *clp_msg; + u64 header; + u16 size; + u8 *msg_buf; + int ret; + + if (!hwdev || SSS_GET_FUNC_TYPE(hwdev) == SSS_FUNC_TYPE_VF) + return -EINVAL; + + if (!hwdev->chip_present_flag || !SSS_SUPPORT_CLP(hwdev)) + return -EPERM; + + clp_msg = hwdev->clp_pf_to_mgmt; + if (!clp_msg) + return -EPERM; + + msg_buf = clp_msg->clp_msg_buf; + + /* 4 bytes alignment */ + size = SSS_TOOL_CLP_DATA_REAL_SIZE(in_size, header); + + if (size > SSS_TOOL_CLP_MAX_DATA_SIZE) { + tool_err("Invalid data size: %u\n", size); + return -EINVAL; + } + down(&clp_msg->clp_msg_lock); + + ret = sss_tool_check_clp_init_status(hwdev); + if (ret) { + tool_err("Fail to check clp init status\n"); + up(&clp_msg->clp_msg_lock); + return ret; + } + + sss_tool_clear_clp_data(hwdev, SSS_TOOL_CLP_RSP); + sss_tool_write_clp_reg(hwdev, SSS_TOOL_CLP_RSP, + SSS_TOOL_CLP_READY_RSP, 0x0); + + /* Send request */ + memset(msg_buf, 0x0, SSS_TOOL_CLP_INPUT_BUF_LEN); + sss_tool_clp_prepare_header(hwdev, &header, in_size, mod, cmd); + + memcpy(msg_buf, &header, sizeof(header)); + msg_buf += sizeof(header); + memcpy(msg_buf, buf_in, in_size); + + msg_buf = clp_msg->clp_msg_buf; + + sss_tool_clear_clp_data(hwdev, SSS_TOOL_CLP_REQ); + ret = sss_tool_write_clp_data(hwdev, clp_msg->clp_msg_buf, size); + if (ret) { + tool_err("Fail to send clp request\n"); + up(&clp_msg->clp_msg_lock); + return -EINVAL; + } + + /* Get response */ + msg_buf = clp_msg->clp_msg_buf; + memset(msg_buf, 0x0, SSS_TOOL_CLP_INPUT_BUF_LEN); + ret = sss_tool_read_clp_data(hwdev, msg_buf, &size); + sss_tool_clear_clp_data(hwdev, SSS_TOOL_CLP_RSP); + if (ret) { + tool_err("Fail to read clp response\n"); + up(&clp_msg->clp_msg_lock); + return -EINVAL; + } + + size = (u16)((size * SSS_TOOL_CLP_DATA_UNIT) & 0xffff); + if (size <= sizeof(header) || size > SSS_TOOL_CLP_INPUT_BUF_LEN) { + tool_err("Invalid response size: %u", size); + up(&clp_msg->clp_msg_lock); + return -EINVAL; + } + + if (size != *out_size + sizeof(header)) { + tool_err("Invalid size:%u, out_size: %u\n", size, *out_size); + up(&clp_msg->clp_msg_lock); + return -EINVAL; + } + + memcpy(buf_out, (msg_buf + sizeof(header)), size); + up(&clp_msg->clp_msg_lock); + + return 0; +} + +int sss_tool_adm_csr_rd32(struct sss_hwdev *hwdev, u8 dest, u32 addr, u32 *val) +{ + int ret; + u32 csr_val = 0; + struct sss_tool_csr_request_adm_data adm_data = {0}; + + if (!hwdev || !val) + return -EFAULT; + + if (!SSS_SUPPORT_ADM_MSG(hwdev)) + return -EPERM; + + adm_data.dw0 = 0; + adm_data.dw1.bits.operation_id = SSS_TOOL_ADM_CSR_READ; + adm_data.dw1.bits.need_response = SSS_TOOL_ADM_CSR_NEED_RESP_DATA; + adm_data.dw1.bits.data_size = SSS_TOOL_ADM_CSR_DATA_SZ_32; + adm_data.dw1.val32 = cpu_to_be32(adm_data.dw1.val32); + adm_data.dw2.bits.csr_addr = addr; + adm_data.dw2.val32 = cpu_to_be32(adm_data.dw2.val32); + + ret = sss_adm_msg_read_ack(hwdev, dest, (u8 *)(&adm_data), + sizeof(adm_data), &csr_val, 0x4); + if (ret) { + tool_err("Fail to read 32 bit csr, dest %u addr 0x%x, ret: 0x%x\n", + dest, addr, ret); + return ret; + } + + *val = csr_val; + + return 0; +} + +int sss_tool_adm_csr_wr32(struct sss_hwdev *hwdev, u8 dest, u32 addr, u32 val) +{ + int ret; + struct sss_tool_csr_request_adm_data adm_data = {0}; + + if (!hwdev) + return -EFAULT; + + if (!SSS_SUPPORT_ADM_MSG(hwdev)) + return -EPERM; + + adm_data.dw1.bits.operation_id = SSS_TOOL_ADM_CSR_WRITE; + adm_data.dw1.bits.need_response = SSS_TOOL_ADM_CSR_NO_RESP_DATA; + adm_data.dw1.bits.data_size = SSS_TOOL_ADM_CSR_DATA_SZ_32; + adm_data.dw1.val32 = cpu_to_be32(adm_data.dw1.val32); + adm_data.dw2.bits.csr_addr = addr; + adm_data.dw2.val32 = cpu_to_be32(adm_data.dw2.val32); + adm_data.csr_write_data_h = 0xffffffff; + adm_data.csr_write_data_l = val; + + ret = sss_adm_msg_write_nack(hwdev, dest, (u8 *)(&adm_data), sizeof(adm_data)); + if (ret) { + tool_err("Fail to write 32 bit csr! dest %u addr 0x%x val 0x%x\n", + dest, addr, val); + return ret; + } + + return 0; +} + +static int sss_tool_adm_csr_read(void *hwdev, struct sss_tool_msg *tool_msg, + void *buf_in, u32 in_size, void *buf_out, u32 *out_size) +{ + int ret = 0; + u32 cnt = 0; + u32 offset = 0; + u32 i; + struct sss_tool_csr_read *rd_msg = (struct sss_tool_csr_read *)buf_in; + u8 node_id = (u8)tool_msg->mpu_cmd.mod; + u32 rd_len = rd_msg->rd_len; + u32 rd_addr = rd_msg->addr; + + if (!buf_in || !buf_out || in_size != sizeof(*rd_msg) || + *out_size != rd_len || rd_len % SSS_TOOL_DW_WIDTH != 0) + return -EINVAL; + + cnt = rd_len / SSS_TOOL_DW_WIDTH; + for (i = 0; i < cnt; i++) { + ret = sss_tool_adm_csr_rd32(hwdev, node_id, rd_addr + offset, + (u32 *)(((u8 *)buf_out) + offset)); + if (ret) { + tool_err("Fail to read csr, err: %d, node_id: %u, csr addr: 0x%08x\n", + ret, node_id, rd_addr + offset); + return ret; + } + offset += SSS_TOOL_DW_WIDTH; + } + *out_size = rd_len; + + return ret; +} + +static int sss_tool_adm_csr_write(void *hwdev, struct sss_tool_msg *tool_msg, + void *buf_in, u32 in_size, void *buf_out, u32 *out_size) +{ + int ret = 0; + u32 cnt = 0; + u32 offset = 0; + u32 i; + struct sss_tool_csr_write *wr_msg = (struct sss_tool_csr_write *)buf_in; + u8 node_id = (u8)tool_msg->mpu_cmd.mod; + u32 rd_len = wr_msg->rd_len; + u32 rd_addr = wr_msg->addr; + u8 *data = NULL; + + if (!buf_in || in_size != sizeof(*wr_msg) || + wr_msg->rd_len % SSS_TOOL_DW_WIDTH != 0) + return -EINVAL; + + data = kzalloc(rd_len, GFP_KERNEL); + if (!data) + return -EFAULT; + + if (copy_from_user(data, (void *)wr_msg->data, rd_len)) { + tool_err("Fail to copy information from user\n"); + kfree(data); + return -EFAULT; + } + + cnt = rd_len / SSS_TOOL_DW_WIDTH; + for (i = 0; i < cnt; i++) { + ret = sss_tool_adm_csr_wr32(hwdev, node_id, rd_addr + offset, + *((u32 *)(data + offset))); + if (ret) { + tool_err("Fail to write csr, ret: %d, node_id: %u, csr addr: 0x%08x\n", + ret, rd_addr + offset, node_id); + kfree(data); + return ret; + } + offset += SSS_TOOL_DW_WIDTH; + } + + *out_size = 0; + kfree(data); + return ret; +} + +int sss_tool_msg_to_mpu(struct sss_hal_dev *hal_dev, struct sss_tool_msg *tool_msg, + void *buf_in, u32 in_size, void *buf_out, u32 *out_size) +{ + int ret = 0; + u16 cmd = tool_msg->mpu_cmd.cmd; + enum sss_mod_type mod = (enum sss_mod_type)tool_msg->mpu_cmd.mod; + u32 timeout = sss_tool_get_timeout_val(mod, cmd); + void *hwdev = hal_dev->hwdev; + + if (tool_msg->mpu_cmd.channel == SSS_TOOL_CHANNEL_MBOX || + tool_msg->mpu_cmd.channel == SSS_TOOL_CHANNEL_CLP) { + if (tool_msg->mpu_cmd.channel == SSS_TOOL_CHANNEL_MBOX) { + ret = sss_sync_mbx_send_msg(hwdev, mod, cmd, buf_in, (u16)in_size, + buf_out, (u16 *)out_size, timeout, + SSS_CHANNEL_DEFAULT); + } else { + ret = sss_tool_send_clp_msg(hwdev, mod, cmd, buf_in, (u16)in_size, + buf_out, (u16 *)out_size); + } + + if (ret) { + tool_err("Fail to send msg to mgmt cpu, mod: %d, cmd: %u\n", mod, cmd); + return ret; + } + + } else if (tool_msg->mpu_cmd.channel == SSS_TOOL_CHANNEL_ADM_MSG_BYPASS) { + if (tool_msg->mpu_cmd.cmd == SSS_TOOL_ADM_MSG_WRITE) + return sss_tool_adm_csr_write(hwdev, tool_msg, buf_in, in_size, + buf_out, out_size); + + ret = sss_tool_adm_csr_read(hwdev, tool_msg, buf_in, in_size, buf_out, out_size); + } else if (tool_msg->mpu_cmd.channel == SSS_TOOL_CHANNEL_ADM_MSG_TO_MPU) { + if (SSS_GET_HWIF_PCI_INTF_ID(SSS_TO_HWIF(hwdev)) != SSS_SPU_HOST_ID) + ret = sss_sync_send_adm_msg(hwdev, mod, cmd, buf_in, (u16)in_size, + buf_out, (u16 *)out_size, timeout); + else + ret = sss_sync_mbx_send_msg(hwdev, mod, cmd, buf_in, (u16)in_size, + buf_out, (u16 *)out_size, timeout, + SSS_CHANNEL_DEFAULT); + + if (ret) { + tool_err("Fail to send adm msg to mgmt cpu, mod: %d, cmd: %u\n", + mod, cmd); + return ret; + } + + } else { + tool_err("Invalid channel %d\n", tool_msg->mpu_cmd.channel); + return -EINVAL; + } + + return ret; +} + +int sss_tool_msg_to_npu(struct sss_hal_dev *hal_dev, struct sss_tool_msg *tool_msg, + void *buf_in, u32 in_size, void *buf_out, u32 *out_size) +{ + int ret = 0; + u8 cmd = tool_msg->npu_cmd.cmd; + enum sss_mod_type mod = (enum sss_mod_type)tool_msg->npu_cmd.mod; + + if (tool_msg->npu_cmd.direct_resp) { + ret = sss_ctrlq_direct_reply(hal_dev->hwdev, mod, cmd, buf_in, + buf_out, 0, SSS_CHANNEL_DEFAULT); + if (ret) + tool_err("Fail to send direct ctrlq, ret: %d\n", ret); + } else { + ret = sss_ctrlq_sync_cmd_detail_reply(hal_dev->hwdev, mod, cmd, buf_in, buf_out, + NULL, 0, SSS_CHANNEL_DEFAULT); + if (ret) + tool_err("Fail to send detail ctrlq, ret: %d\n", ret); + } + + return ret; +} diff --git a/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_chip.h b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_chip.h new file mode 100644 index 000000000000..4dbaed192f85 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_chip.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_CHIP_H +#define SSS_TOOL_CHIP_H +#include "sss_hw.h" +#include "sss_tool_comm.h" +#include "sss_tool_hw.h" + +int sss_tool_msg_to_mpu(struct sss_hal_dev *hal_dev, struct sss_tool_msg *tool_msg, + void *buf_in, u32 in_size, void *buf_out, u32 *out_size); +int sss_tool_msg_to_npu(struct sss_hal_dev *hal_dev, struct sss_tool_msg *tool_msg, + void *buf_in, u32 in_size, void *buf_out, u32 *out_size); + +#endif diff --git a/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_hw.h b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_hw.h new file mode 100644 index 000000000000..b951026a7c9c --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_hw.h @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_HW_H +#define SSS_TOOL_HW_H + +#define SSS_TOOL_CMD_TYPE (0x18) + +#define SSS_TOOL_PF_DEV_MAX 32 +/* Indicates the maximum number of interrupts that can be recorded. + * Subsequent interrupts are not recorded in FFM. + */ +#define SSS_TOOL_FFM_RECORD_MAX 64 + +#define SSS_TOOL_PF_INFO_MAX (16) +#define SSS_TOOL_BUSINFO_LEN (32) + +#define SSS_TOOL_CHIP_FAULT_SIZE (110 * 1024) +#define SSS_TOOL_DRV_BUF_SIZE_MAX 4096 + +/* dbgtool command type */ +/* You can add commands as required. The dbgtool command can be + * used to invoke all interfaces of the kernel-mode x86 driver. + */ +enum sss_tool_dbg_cmd { + SSS_TOOL_DBG_CMD_API_RD = 0, + SSS_TOOL_DBG_CMD_API_WR, + SSS_TOOL_DBG_CMD_FFM_RD, + SSS_TOOL_DBG_CMD_FFM_CLR, + SSS_TOOL_DBG_CMD_PF_DEV_INFO_GET, + SSS_TOOL_DBG_CMD_MSG_2_UP, + SSS_TOOL_DBG_CMD_FREE_MEM, + SSS_TOOL_DBG_CMD_NUM +}; + +enum module_name { + SSS_TOOL_MSG_TO_NPU = 1, + SSS_TOOL_MSG_TO_MPU, + SSS_TOOL_MSG_TO_SM, + SSS_TOOL_MSG_TO_HW_DRIVER, +#define SSS_TOOL_MSG_TO_SRV_DRV_BASE (SSS_TOOL_MSG_TO_HW_DRIVER + 1) + SSS_TOOL_MSG_TO_NIC_DRIVER = SSS_TOOL_MSG_TO_SRV_DRV_BASE, + SSS_TOOL_MSG_TO_OVS_DRIVER, + SSS_TOOL_MSG_TO_ROCE_DRIVER, + SSS_TOOL_MSG_TO_TOE_DRIVER, + SSS_TOOL_MSG_TO_IOE_DRIVER, + SSS_TOOL_MSG_TO_FC_DRIVER, + SSS_TOOL_MSG_TO_VBS_DRIVER, + SSS_TOOL_MSG_TO_IPSEC_DRIVER, + SSS_TOOL_MSG_TO_VIRTIO_DRIVER, + SSS_TOOL_MSG_TO_MIGRATE_DRIVER, + SSS_TOOL_MSG_TO_PPA_DRIVER, + SSS_TOOL_MSG_TO_CUSTOM_DRIVER = SSS_TOOL_MSG_TO_SRV_DRV_BASE + 11, + SSS_TOOL_MSG_TO_DRIVER_MAX = SSS_TOOL_MSG_TO_SRV_DRV_BASE + 15, /* reserved */ +}; + +enum sss_tool_adm_msg_type { + SSS_TOOL_ADM_MSG_READ, + SSS_TOOL_ADM_MSG_WRITE +}; + +enum sss_tool_sm_cmd_type { + SSS_TOOL_SM_CMD_RD16 = 1, + SSS_TOOL_SM_CMD_RD32, + SSS_TOOL_SM_CMD_RD64_PAIR, + SSS_TOOL_SM_CMD_RD64, + SSS_TOOL_SM_CMD_RD32_CLEAR, + SSS_TOOL_SM_CMD_RD64_PAIR_CLEAR, + SSS_TOOL_SM_CMD_RD64_CLEAR +}; + +enum sss_tool_channel_type { + SSS_TOOL_CHANNEL_MBOX = 1, + SSS_TOOL_CHANNEL_ADM_MSG_BYPASS, + SSS_TOOL_CHANNEL_ADM_MSG_TO_MPU, + SSS_TOOL_CHANNEL_CLP, +}; + +struct sss_tool_api_cmd_rd { + u32 pf_id; + u8 dest; + u8 *cmd; + u16 size; + void *ack; + u16 ack_size; +}; + +struct sss_tool_api_cmd_wr { + u32 pf_id; + u8 dest; + u8 *cmd; + u16 size; +}; + +struct sss_tool_pf_dev_info { + u64 bar0_size; + u8 bus; + u8 slot; + u8 func; + u64 phy_addr; +}; + +struct sss_tool_ffm_intr_info { + u8 node_id; + /* error level of the interrupt source */ + u8 err_level; + /* Classification by interrupt source properties */ + u16 err_type; + u32 err_csr_addr; + u32 err_csr_value; +}; + +struct sss_tool_ffm_intr_tm_info { + struct sss_tool_ffm_intr_info intr_info; + u8 times; + u8 sec; + u8 min; + u8 hour; + u8 mday; + u8 mon; + u16 year; +}; + +struct sss_tool_ffm_record_info { + u32 ffm_num; + u32 last_err_csr_addr; + u32 last_err_csr_value; + struct sss_tool_ffm_intr_tm_info ffm[SSS_TOOL_FFM_RECORD_MAX]; +}; + +struct sss_tool_knl_dbg_info { + struct semaphore dbgtool_sem; + struct sss_tool_ffm_record_info *ffm; +}; + +struct sss_tool_msg_to_up { + u8 pf_id; + u8 mod; + u8 cmd; + void *buf_in; + u16 in_size; + void *buf_out; + u16 *out_size; +}; + +struct sss_tool_dbg_param { + union { + struct sss_tool_api_cmd_rd api_rd; + struct sss_tool_api_cmd_wr api_wr; + struct sss_tool_pf_dev_info *dev_info; + struct sss_tool_ffm_record_info *ffm_rd; + struct sss_tool_msg_to_up msg2up; + } param; + char chip_name[16]; +}; + +struct sss_tool_pf { + char name[IFNAMSIZ]; + char bus_info[SSS_TOOL_BUSINFO_LEN]; + u32 pf_type; +}; + +struct sss_tool_card_info { + struct sss_tool_pf pf[SSS_TOOL_PF_INFO_MAX]; + u32 pf_num; +}; + +struct sss_tool_pf_info { + u32 valid; + u32 pf_id; +}; + +struct sss_tool_cmd_chip_fault_stats { + u32 offset; + u8 chip_fault_stats[SSS_TOOL_DRV_BUF_SIZE_MAX]; +}; + +struct sss_tool_npu_msg { + u32 mod : 8; + u32 cmd : 8; + u32 ack_type : 3; + u32 direct_resp : 1; + u32 len : 12; +}; + +struct sss_tool_mpu_msg { + u32 channel : 8; + u32 mod : 8; + u32 cmd : 16; +}; + +struct sss_tool_msg { + char device_name[IFNAMSIZ]; + u32 module; + union { + u32 msg_formate; /* for driver */ + struct sss_tool_npu_msg npu_cmd; + struct sss_tool_mpu_msg mpu_cmd; + }; + u32 timeout; /* for mpu/npu cmd */ + u32 func_id; + u32 buf_in_size; + u32 buf_out_size; + void *in_buf; + void *out_buf; + int bus_num; + u8 port_id; + u8 rsvd1[3]; + u32 rsvd2[4]; +}; + +#endif /* SSS_TOOL_HW_H */ diff --git a/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_main.c b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_main.c new file mode 100644 index 000000000000..776725e0418a --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_main.c @@ -0,0 +1,736 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt + +#include +#include +#include +#include +#include +#include + +#include "sss_adapter_mgmt.h" +#include "sss_linux_kernel.h" +#include "sss_hw.h" +#include "sss_tool_comm.h" +#include "sss_tool_hw.h" +#include "sss_tool.h" + +#define SSS_TOOL_DEV_PATH "/dev/sssnic_nictool_dev" +#define SSS_TOOL_DEV_CLASS "sssnic_nictool_class" +#define SSS_TOOL_DEV_NAME "sssnic_nictool_dev" + +#define SSS_TOOL_CTRLQ_BUF_SIZE_MAX 2048U +#define SSS_TOOL_MSG_IN_SIZE_MAX (2048 * 1024) +#define SSS_TOOL_MSG_OUT_SIZE_MAX (2048 * 1024) +#define SSS_TOOL_BUF_SIZE_MAX (2048 * 1024) + +typedef int (*sss_tool_deal_handler_fun)(struct sss_hal_dev *hal_dev, struct sss_tool_msg *tool_msg, + void *in_buf, u32 in_len, void *out_buf, u32 *out_len); + +struct sss_tool_deal_handler { + enum module_name msg_name; + sss_tool_deal_handler_fun func; +}; + +static int g_nictool_ref_cnt; + +static dev_t g_dev_id = {0}; + +static struct class *g_nictool_class; +static struct cdev g_nictool_cdev; + +static void *g_card_node_array[SSS_TOOL_CARD_MAX] = {0}; +void *g_card_va[SSS_TOOL_CARD_MAX] = {0}; +u64 g_card_pa[SSS_TOOL_CARD_MAX] = {0}; +int g_card_id; + +static int sss_tool_msg_to_nic(struct sss_hal_dev *hal_dev, struct sss_tool_msg *tool_msg, + void *in_buf, u32 in_len, void *out_buf, u32 *out_len) +{ + int ret = -EINVAL; + void *uld_dev = NULL; + enum sss_service_type service_type; + struct sss_uld_info *uld_info = sss_get_uld_info(); + + service_type = tool_msg->module - SSS_TOOL_MSG_TO_SRV_DRV_BASE; + if (service_type >= SSS_SERVICE_TYPE_MAX) { + tool_err("Invalid input module id: %u\n", tool_msg->module); + return -EINVAL; + } + + uld_dev = sss_get_uld_dev(hal_dev, service_type); + if (!uld_dev) { + if (tool_msg->msg_formate == SSS_TOOL_GET_DRV_VERSION) + return 0; + + tool_err("Fail to get uld device\n"); + return -EINVAL; + } + + if (uld_info[service_type].ioctl) + ret = uld_info[service_type].ioctl(uld_dev, tool_msg->msg_formate, + in_buf, in_len, out_buf, out_len); + sss_uld_dev_put(hal_dev, service_type); + + return ret; +} + +void sss_tool_free_in_buf(void *hwdev, const struct sss_tool_msg *tool_msg, void *in_buf) +{ + if (!in_buf) + return; + + if (tool_msg->module == SSS_TOOL_MSG_TO_NPU) + sss_free_ctrlq_msg_buf(hwdev, in_buf); + else + kfree(in_buf); +} + +void sss_tool_free_out_buf(void *hwdev, struct sss_tool_msg *tool_msg, + void *out_buf) +{ + if (!out_buf) + return; + + if (tool_msg->module == SSS_TOOL_MSG_TO_NPU && + !tool_msg->npu_cmd.direct_resp) + sss_free_ctrlq_msg_buf(hwdev, out_buf); + else + kfree(out_buf); +} + +int sss_tool_alloc_in_buf(void *hwdev, struct sss_tool_msg *tool_msg, + u32 in_len, void **in_buf) +{ + void *msg_buf = NULL; + + if (!in_len) + return 0; + + if (tool_msg->module == SSS_TOOL_MSG_TO_NPU) { + struct sss_ctrl_msg_buf *cmd_buf = NULL; + + if (in_len > SSS_TOOL_CTRLQ_BUF_SIZE_MAX) { + tool_err("Invalid ctrlq in len(%u) more than %u\n", + in_len, SSS_TOOL_CTRLQ_BUF_SIZE_MAX); + return -ENOMEM; + } + + cmd_buf = sss_alloc_ctrlq_msg_buf(hwdev); + if (!cmd_buf) { + tool_err("Fail to alloc ctrlq msg buf\n"); + return -ENOMEM; + } + *in_buf = (void *)cmd_buf; + cmd_buf->size = (u16)in_len; + } else { + if (in_len > SSS_TOOL_MSG_IN_SIZE_MAX) { + tool_err("Invalid in len(%u) more than %u\n", + in_len, SSS_TOOL_MSG_IN_SIZE_MAX); + return -ENOMEM; + } + msg_buf = kzalloc(in_len, GFP_KERNEL); + *in_buf = msg_buf; + } + + if (!(*in_buf)) { + tool_err("Fail to alloc in buf\n"); + return -ENOMEM; + } + + return 0; +} + +int sss_tool_alloc_out_buf(void *hwdev, struct sss_tool_msg *tool_msg, + u32 out_len, void **out_buf) +{ + if (!out_len) { + tool_info("out len is 0, need not alloc buf\n"); + return 0; + } + + if (tool_msg->module == SSS_TOOL_MSG_TO_NPU && + !tool_msg->npu_cmd.direct_resp) { + struct sss_ctrl_msg_buf *msg_buf = NULL; + + if (out_len > SSS_TOOL_CTRLQ_BUF_SIZE_MAX) { + tool_err("Invalid ctrlq out len(%u) more than %u\n", + out_len, SSS_TOOL_CTRLQ_BUF_SIZE_MAX); + return -ENOMEM; + } + + msg_buf = sss_alloc_ctrlq_msg_buf(hwdev); + *out_buf = (void *)msg_buf; + } else { + if (out_len > SSS_TOOL_MSG_OUT_SIZE_MAX) { + tool_err("Invalid out len(%u) more than %u\n", + out_len, SSS_TOOL_MSG_OUT_SIZE_MAX); + return -ENOMEM; + } + *out_buf = kzalloc(out_len, GFP_KERNEL); + } + if (!(*out_buf)) { + tool_err("Fail to alloc out buf\n"); + return -ENOMEM; + } + + return 0; +} + +int sss_tool_copy_to_user(struct sss_tool_msg *tool_msg, + u32 out_len, void *out_buf) +{ + void *out_msg = NULL; + + if (tool_msg->module == SSS_TOOL_MSG_TO_NPU && !tool_msg->npu_cmd.direct_resp) { + out_msg = ((struct sss_ctrl_msg_buf *)out_buf)->buf; + if (copy_to_user(tool_msg->out_buf, out_msg, out_len)) + return -EFAULT; + return 0; + } + + if (copy_to_user(tool_msg->out_buf, out_buf, out_len)) + return -EFAULT; + + return 0; +} + +static int sss_tool_alloc_buf(void *hwdev, struct sss_tool_msg *tool_msg, u32 in_len, + void **in_buf, u32 out_len, void **out_buf) +{ + int ret; + + ret = sss_tool_alloc_in_buf(hwdev, tool_msg, in_len, in_buf); + if (ret) { + tool_err("Fail to alloc tool msg in buf\n"); + return ret; + } + + if (copy_from_user(*in_buf, tool_msg->in_buf, in_len)) { + tool_err("Fail to copy tool_msg to in buf\n"); + sss_tool_free_in_buf(hwdev, tool_msg, *in_buf); + return -EFAULT; + } + + ret = sss_tool_alloc_out_buf(hwdev, tool_msg, out_len, out_buf); + if (ret) { + tool_err("Fail to alloc tool msg out buf\n"); + goto alloc_out_buf_err; + } + + return 0; + +alloc_out_buf_err: + sss_tool_free_in_buf(hwdev, tool_msg, *in_buf); + + return ret; +} + +static void sss_tool_free_buf(void *hwdev, struct sss_tool_msg *tool_msg, + void *in_buf, void *out_buf) +{ + sss_tool_free_out_buf(hwdev, tool_msg, out_buf); + sss_tool_free_in_buf(hwdev, tool_msg, in_buf); +} + +const struct sss_tool_deal_handler g_deal_msg_handle[] = { + {SSS_TOOL_MSG_TO_NPU, sss_tool_msg_to_npu}, + {SSS_TOOL_MSG_TO_MPU, sss_tool_msg_to_mpu}, + {SSS_TOOL_MSG_TO_SM, sss_tool_msg_to_sm}, + {SSS_TOOL_MSG_TO_HW_DRIVER, sss_tool_msg_to_hw}, + {SSS_TOOL_MSG_TO_NIC_DRIVER, sss_tool_msg_to_nic} +}; + +static int sss_tool_deal_cmd(struct sss_hal_dev *hal_dev, struct sss_tool_msg *tool_msg, + void *in_buf, u32 in_len, void *out_buf, u32 *out_len) +{ + int ret = 0; + int index; + int msg_num = ARRAY_LEN(g_deal_msg_handle); + + for (index = 0; index < msg_num; index++) { + if (tool_msg->module != g_deal_msg_handle[index].msg_name) + continue; + + ret = g_deal_msg_handle[index].func(hal_dev, tool_msg, + in_buf, in_len, out_buf, out_len); + break; + } + + if (index == msg_num) + ret = sss_tool_msg_to_nic(hal_dev, tool_msg, + in_buf, in_len, out_buf, out_len); + + return ret; +} + +static struct sss_hal_dev *sss_tool_get_hal_dev_by_msg(struct sss_tool_msg *tool_msg) +{ + struct sss_hal_dev *hal_dev = NULL; + + if (tool_msg->module >= SSS_TOOL_MSG_TO_SRV_DRV_BASE && + tool_msg->module < SSS_TOOL_MSG_TO_DRIVER_MAX && + tool_msg->msg_formate != SSS_TOOL_GET_DRV_VERSION) { + hal_dev = sss_get_lld_dev_by_dev_name(tool_msg->device_name, + tool_msg->module - + SSS_TOOL_MSG_TO_SRV_DRV_BASE); + } else { + hal_dev = sss_get_lld_dev_by_chip_name(tool_msg->device_name); + if (!hal_dev) + hal_dev = sss_get_lld_dev_by_dev_name(tool_msg->device_name, + SSS_SERVICE_TYPE_MAX); + } + + if (tool_msg->module == SSS_TOOL_MSG_TO_NIC_DRIVER && + (tool_msg->msg_formate == SSS_TOOL_GET_XSFP_INFO || + tool_msg->msg_formate == SSS_TOOL_GET_XSFP_PRESENT)) + hal_dev = sss_get_lld_dev_by_chip_and_port(tool_msg->device_name, + tool_msg->port_id); + + return hal_dev; +} + +static int sss_tool_check_msg_valid(struct sss_tool_msg *tool_msg) +{ + if (tool_msg->buf_out_size > SSS_TOOL_BUF_SIZE_MAX || + tool_msg->buf_in_size > SSS_TOOL_BUF_SIZE_MAX) { + tool_err("Invalid in buf len: %u or out buf len: %u\n", + tool_msg->buf_in_size, tool_msg->buf_out_size); + return -EFAULT; + } + + return 0; +} + +static long sss_tool_msg_ioctl(unsigned long arg) +{ + int ret = 0; + u32 in_len = 0; + u32 expect_out_len = 0; + u32 out_len = 0; + void *in_buf = NULL; + void *out_buf = NULL; + struct sss_hal_dev *hal_dev = NULL; + struct sss_tool_msg tool_msg = {0}; + + if (copy_from_user(&tool_msg, (void *)arg, sizeof(tool_msg))) { + tool_err("Fail to copy msg from user space\n"); + return -EFAULT; + } + + if (sss_tool_check_msg_valid(&tool_msg)) { + tool_err("Fail to check msg valid\n"); + return -EFAULT; + } + + tool_msg.device_name[IFNAMSIZ - 1] = '\0'; + expect_out_len = tool_msg.buf_out_size; + in_len = tool_msg.buf_in_size; + + hal_dev = sss_tool_get_hal_dev_by_msg(&tool_msg); + if (!hal_dev) { + if (tool_msg.msg_formate != SSS_TOOL_DEV_NAME_TEST) + tool_err("Fail to find device %s for module %d\n", + tool_msg.device_name, tool_msg.module); + return -ENODEV; + } + + if (tool_msg.msg_formate == SSS_TOOL_DEV_NAME_TEST) + return 0; + + ret = sss_tool_alloc_buf(hal_dev->hwdev, &tool_msg, + in_len, &in_buf, expect_out_len, &out_buf); + if (ret) { + tool_err("Fail to alloc cmd buf\n"); + goto out_free_lock; + } + + out_len = expect_out_len; + + ret = sss_tool_deal_cmd(hal_dev, &tool_msg, in_buf, in_len, out_buf, &out_len); + if (ret) { + tool_err("Fail to execute cmd, module: %u, ret: %d.\n", tool_msg.module, ret); + goto out_free_buf; + } + + if (out_len > expect_out_len) { + ret = -EFAULT; + tool_err("Fail to execute cmd, expected out len from user: %u, out len: %u\n", + expect_out_len, out_len); + goto out_free_buf; + } + + ret = sss_tool_copy_to_user(&tool_msg, out_len, out_buf); + if (ret) + tool_err("Fail to copy return information to user space\n"); + +out_free_buf: + sss_tool_free_buf(hal_dev->hwdev, &tool_msg, in_buf, out_buf); + +out_free_lock: + lld_dev_put(hal_dev); + return (long)ret; +} + +static long sss_tool_knl_ffm_info_rd(struct sss_tool_dbg_param *dbg_param, + struct sss_tool_knl_dbg_info *dbg_info) +{ + if (copy_to_user(dbg_param->param.ffm_rd, dbg_info->ffm, + (unsigned int)sizeof(*dbg_param->param.ffm_rd))) { + tool_err("Fail to copy ffm_info to user space\n"); + return -EFAULT; + } + + return 0; +} + +static struct sss_card_node *sss_tool_find_card_node(char *chip_name) +{ + int i; + struct sss_card_node *card_node = NULL; + + for (i = 0; i < SSS_TOOL_CARD_MAX; i++) { + card_node = (struct sss_card_node *)g_card_node_array[i]; + if (!card_node) + continue; + if (!strncmp(chip_name, card_node->chip_name, IFNAMSIZ)) + break; + } + if (i == SSS_TOOL_CARD_MAX || !card_node) + return NULL; + + g_card_id = i; + + return card_node; +} + +static long sss_tool_dbg_ioctl(unsigned int cmd_type, unsigned long arg) +{ + struct sss_tool_knl_dbg_info *dbg_info = NULL; + struct sss_card_node *card_node = NULL; + struct sss_tool_dbg_param param = {0}; + long ret; + + if (copy_from_user(¶m, (void *)arg, sizeof(param))) { + tool_err("Fail to copy msg param from user\n"); + return -EFAULT; + } + + sss_hold_chip_node(); + + card_node = sss_tool_find_card_node(param.chip_name); + if (!card_node) { + sss_put_chip_node(); + tool_err("Fail to find card node %s\n", param.chip_name); + return -EFAULT; + } + + dbg_info = (struct sss_tool_knl_dbg_info *)card_node->dbgtool_info; + + down(&dbg_info->dbgtool_sem); + + if (cmd_type == SSS_TOOL_DBG_CMD_FFM_RD) { + ret = sss_tool_knl_ffm_info_rd(¶m, dbg_info); + } else if (cmd_type == SSS_TOOL_DBG_CMD_MSG_2_UP) { + tool_info("cmd(0x%x) not suppose.\n", cmd_type); + ret = 0; + } else { + tool_err("Fail to execute cmd(0x%x) ,it is not support\n", cmd_type); + ret = -EFAULT; + } + + up(&dbg_info->dbgtool_sem); + + sss_put_chip_node(); + + return ret; +} + +static int sss_tool_release(struct inode *pnode, struct file *pfile) +{ + return 0; +} + +static int sss_tool_open(struct inode *pnode, struct file *pfile) +{ + return 0; +} + +static ssize_t sss_tool_read(struct file *pfile, char __user *ubuf, + size_t size, loff_t *ppos) +{ + return 0; +} + +static ssize_t sss_tool_write(struct file *pfile, const char __user *ubuf, + size_t size, loff_t *ppos) +{ + return 0; +} + +static long sss_tool_unlocked_ioctl(struct file *pfile, + unsigned int cmd, unsigned long arg) +{ + unsigned int cmd_type = _IOC_NR(cmd); + + if (cmd_type == SSS_TOOL_CMD_TYPE) + return sss_tool_msg_ioctl(arg); + + return sss_tool_dbg_ioctl(cmd_type, arg); +} + +static int sss_tool_mem_mmap(struct file *filp, struct vm_area_struct *mem_area) +{ + unsigned long mem_size = mem_area->vm_end - mem_area->vm_start; + phys_addr_t offset = (phys_addr_t)mem_area->vm_pgoff << PAGE_SHIFT; + phys_addr_t phy_addr; + + if (mem_size > SSS_TOOL_MEM_MAP_SIZE) { + tool_err("Fail to map mem, mem_size :%ld, alloc size: %ld\n", + mem_size, SSS_TOOL_MEM_MAP_SIZE); + return -EAGAIN; + } + + phy_addr = offset ? offset : g_card_pa[g_card_id]; + if (!phy_addr) { + tool_err("Fail to map mem, card_id = %d phy_addr is 0\n", g_card_id); + return -EAGAIN; + } + + mem_area->vm_page_prot = pgprot_noncached(mem_area->vm_page_prot); + if (remap_pfn_range(mem_area, mem_area->vm_start, (phy_addr >> PAGE_SHIFT), + mem_size, mem_area->vm_page_prot)) { + tool_err("Fail to remap pfn range.\n"); + return -EAGAIN; + } + + return 0; +} + +static const struct file_operations sss_tool_file_ops = { + .owner = THIS_MODULE, + .release = sss_tool_release, + .open = sss_tool_open, + .read = sss_tool_read, + .write = sss_tool_write, + .unlocked_ioctl = sss_tool_unlocked_ioctl, + .mmap = sss_tool_mem_mmap, +}; + +static struct sss_tool_knl_dbg_info *sss_tool_alloc_dbg_info(void *hwdev) +{ + struct sss_tool_knl_dbg_info *dbg_info = NULL; + + dbg_info = (struct sss_tool_knl_dbg_info *) + kzalloc(sizeof(struct sss_tool_knl_dbg_info), GFP_KERNEL); + if (!dbg_info) + return NULL; + + dbg_info->ffm = (struct sss_tool_ffm_record_info *) + kzalloc(sizeof(*dbg_info->ffm), GFP_KERNEL); + if (!dbg_info->ffm) { + tool_err("Fail to alloc ffm_record_info\n"); + kfree(dbg_info); + return NULL; + } + + return dbg_info; +} + +static void sss_tool_free_dbg_info(struct sss_tool_knl_dbg_info *dbg_info) +{ + kfree(dbg_info->ffm); + kfree(dbg_info); +} + +static int sss_tool_get_node_id(struct sss_card_node *card_node, int *node_id) +{ + int ret; + + ret = sscanf(card_node->chip_name, SSS_CHIP_NAME "%d", node_id); + if (ret < 0) { + tool_err("Fail to get card id\n"); + return -ENOMEM; + } + + return 0; +} + +static int sss_tool_add_func_to_card_node(void *hwdev, struct sss_card_node *card_node) +{ + int func_id = sss_get_func_id(hwdev); + struct sss_tool_knl_dbg_info *dbg_info = NULL; + int ret; + int node_id; + + if (sss_get_func_type(hwdev) != SSS_FUNC_TYPE_VF) + card_node->func_handle_array[func_id] = hwdev; + + if (card_node->func_num++) + return 0; + + dbg_info = sss_tool_alloc_dbg_info(hwdev); + if (!dbg_info) { + ret = -ENOMEM; + tool_err("Fail to alloc dbg_info\n"); + goto alloc_dbg_info_err; + } + card_node->dbgtool_info = dbg_info; + sema_init(&dbg_info->dbgtool_sem, 1); + + ret = sss_tool_get_node_id(card_node, &node_id); + if (ret) { + tool_err("Fail to add node to global array\n"); + goto get_node_id_err; + } + g_card_node_array[node_id] = card_node; + + return 0; + +get_node_id_err: + sss_tool_free_dbg_info(dbg_info); + card_node->dbgtool_info = NULL; + +alloc_dbg_info_err: + card_node->func_num--; + if (sss_get_func_type(hwdev) != SSS_FUNC_TYPE_VF) + card_node->func_handle_array[func_id] = NULL; + + return ret; +} + +static void sss_tool_del_func_in_card_node(void *hwdev, struct sss_card_node *card_node) +{ + struct sss_tool_knl_dbg_info *dbg_info = card_node->dbgtool_info; + int func_id = sss_get_func_id(hwdev); + int node_id; + + if (sss_get_func_type(hwdev) != SSS_FUNC_TYPE_VF) + card_node->func_handle_array[func_id] = NULL; + + if (--card_node->func_num) + return; + + sss_tool_get_node_id(card_node, &node_id); + if (node_id < SSS_TOOL_CARD_MAX) + g_card_node_array[node_id] = NULL; + + sss_tool_free_dbg_info(dbg_info); + card_node->dbgtool_info = NULL; + + if (node_id < SSS_TOOL_CARD_MAX) + (void)sss_tool_free_card_mem(node_id); +} + +static int sss_tool_create_dev(void) +{ + int ret; + struct device *pdevice = NULL; + + ret = alloc_chrdev_region(&g_dev_id, 0, 1, SSS_TOOL_DEV_NAME); + if (ret) { + tool_err("Fail to alloc sssnic_nictool_dev region(0x%x)\n", ret); + return ret; + } + + g_nictool_class = class_create(THIS_MODULE, SSS_TOOL_DEV_CLASS); + if (IS_ERR(g_nictool_class)) { + tool_err("Fail to create sssnic_nictool_class\n"); + ret = -EFAULT; + goto create_class_err; + } + + cdev_init(&g_nictool_cdev, &sss_tool_file_ops); + + ret = cdev_add(&g_nictool_cdev, g_dev_id, 1); + if (ret < 0) { + tool_err("Fail to add sssnic_nictool_dev to operating system (0x%x)\n", ret); + goto add_cdev_err; + } + + pdevice = device_create(g_nictool_class, NULL, g_dev_id, NULL, SSS_TOOL_DEV_NAME); + if (IS_ERR(pdevice)) { + tool_err("Fail to create sssnic_nictool_dev on operating system\n"); + ret = -EFAULT; + goto create_device_err; + } + + tool_info("Success to register sssnic_nictool_dev to system\n"); + + return 0; + +create_device_err: + cdev_del(&g_nictool_cdev); + +add_cdev_err: + class_destroy(g_nictool_class); + +create_class_err: + g_nictool_class = NULL; + unregister_chrdev_region(g_dev_id, 1); + + return ret; +} + +static void sss_tool_destroy_dev(void) +{ + device_destroy(g_nictool_class, g_dev_id); + cdev_del(&g_nictool_cdev); + class_destroy(g_nictool_class); + g_nictool_class = NULL; + unregister_chrdev_region(g_dev_id, 1); + tool_info("Success to unregister sssnic_nictool_dev to system\n"); +} + +int sss_tool_init(void *hwdev, void *chip_node) +{ + struct sss_card_node *card_node = (struct sss_card_node *)chip_node; + int ret; + + ret = sss_tool_add_func_to_card_node(hwdev, card_node); + if (ret) { + tool_err("Fail to add func to card node\n"); + return ret; + } + + if (g_nictool_ref_cnt++) { + tool_info("sssnic_nictool_dev has already create\n"); + return 0; + } + + ret = sss_tool_create_dev(); + if (ret) { + tool_err("Fail to create sssnic_nictool_dev\n"); + goto out; + } + + return 0; + +out: + g_nictool_ref_cnt--; + sss_tool_del_func_in_card_node(hwdev, card_node); + + return ret; +} + +void sss_tool_uninit(void *hwdev, void *chip_node) +{ + struct sss_card_node *chip_info = (struct sss_card_node *)chip_node; + + sss_tool_del_func_in_card_node(hwdev, chip_info); + + if (g_nictool_ref_cnt == 0) + return; + + if (--g_nictool_ref_cnt) + return; + + if (!g_nictool_class || IS_ERR(g_nictool_class)) { + tool_err("Fail to uninit sssnictool, tool class is NULL.\n"); + return; + } + + sss_tool_destroy_dev(); +} diff --git a/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sdk.c b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sdk.c new file mode 100644 index 000000000000..8f8fb6d364d4 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sdk.c @@ -0,0 +1,527 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ +#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt + +#include +#include +#include +#include +#include +#include + +#include "sss_linux_kernel.h" +#include "sss_hw.h" +#include "sss_hwdev.h" +#include "sss_tool.h" +#include "sss_csr.h" +#include "sss_adapter_mgmt.h" +#include "sss_mgmt_info.h" +#include "sss_pci_global.h" +#include "sss_hwif_api.h" + +typedef int (*sss_tool_hw_cmd_func)(struct sss_hal_dev *hal_dev, const void *buf_in, + u32 in_size, void *buf_out, u32 *out_size); +struct sss_tool_hw_cmd_handle { + enum sss_tool_driver_cmd_type cmd_type; + sss_tool_hw_cmd_func func; +}; + +int sss_tool_get_func_type(struct sss_hal_dev *hal_dev, const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + if (*out_size != sizeof(u16) || !buf_out) { + tool_err("Invalid out_size from user :%u, expect: %lu\n", *out_size, sizeof(u16)); + return -EFAULT; + } + + *(u16 *)buf_out = (u16)sss_get_func_type(SSS_TO_HWDEV(hal_dev)); + + return 0; +} + +int sss_tool_get_func_id(struct sss_hal_dev *hal_dev, const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + if (*out_size != sizeof(u16) || !buf_out) { + tool_err("Invalid out_size from user :%u, expect: %lu\n", *out_size, sizeof(u16)); + return -EFAULT; + } + + *(u16 *)buf_out = (u16)sss_get_func_id(SSS_TO_HWDEV(hal_dev)); + + return 0; +} + +int sss_tool_get_hw_driver_stats(struct sss_hal_dev *hal_dev, const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + struct sss_hwdev *hwdev = hal_dev->hwdev; + struct sss_card_node *node = hwdev->chip_node; + struct sss_hw_stats *stats = buf_out; + struct sss_hw_stats *tmp = stats; + + if (!hwdev) + return -EINVAL; + + if (*out_size != sizeof(struct sss_hw_stats) || !stats) { + tool_err("Invalid out_size from user :%u, expect: %lu\n", + *out_size, sizeof(struct sss_hw_stats)); + return -EFAULT; + } + + memcpy(stats, &hwdev->hw_stats, sizeof(struct sss_hw_stats)); + + atomic_set(&tmp->nic_ucode_event_stats[SSS_CHN_BUSY], + atomic_read(&node->channel_timeout_cnt)); + + return 0; +} + +static int sss_tool_clear_hw_driver_stats(struct sss_hal_dev *hal_dev, const void *buf_in, + u32 in_size, void *buf_out, u32 *out_size) +{ + struct sss_hwdev *hwdev = hal_dev->hwdev; + struct sss_card_node *node = hwdev->chip_node; + + memset((void *)&hwdev->hw_stats, 0, sizeof(struct sss_hw_stats)); + memset((void *)hwdev->chip_fault_stats, 0, SSS_TOOL_CHIP_FAULT_SIZE); + + if (SSS_SUPPORT_CHANNEL_DETECT(hwdev) && atomic_read(&node->channel_timeout_cnt)) { + atomic_set(&node->channel_timeout_cnt, 0); + hwdev->aeq_busy_cnt = 0; +#if !defined(__UEFI__) && !defined(VMWARE) + queue_delayed_work(hwdev->workq, &hwdev->channel_detect_task, + msecs_to_jiffies(SSSNIC_CHANNEL_DETECT_PERIOD)); +#endif + } + + if (*out_size != sizeof(struct sss_hw_stats)) { + tool_err("Invalid out_size from user :%u, expect: %lu\n", + *out_size, sizeof(struct sss_hw_stats)); + return -EFAULT; + } + + return 0; +} + +static int sss_tool_get_self_test_result(struct sss_hal_dev *hal_dev, + const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + u32 val; + + if (*out_size != sizeof(u32) || !buf_out) { + tool_err("Invalid out_size from user :%u, expect: %lu\n", + *out_size, sizeof(u32)); + return -EFAULT; + } + + val = sss_chip_read_reg(SSS_TO_HWIF(hal_dev->hwdev), SSS_MGMT_HEALTH_STATUS_ADDR); + *(u32 *)buf_out = val; + + return 0; +} + +static void sss_tool_get_chip_fault_stats(const void *hwdev, u8 *chip_fault_stats, u32 offset) +{ + u32 size; + + if (offset >= SSS_TOOL_CHIP_FAULT_SIZE) { + tool_err("Invalid chip offset value: %d\n", offset); + return; + } + + size = min(SSS_TOOL_DRV_BUF_SIZE_MAX, SSS_TOOL_CHIP_FAULT_SIZE - (int)offset); + memcpy(chip_fault_stats, ((struct sss_hwdev *)hwdev)->chip_fault_stats + + offset, size); +} + +static int sss_tool_get_chip_faults_stats(struct sss_hal_dev *hal_dev, + const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + u32 offset = 0; + struct sss_tool_cmd_chip_fault_stats *info = NULL; + + if (!buf_in || !buf_out || *out_size != sizeof(*info) || + in_size != sizeof(*info)) { + tool_err("Invalid out_size from user: %d, expect: %lu\n", *out_size, sizeof(*info)); + return -EFAULT; + } + info = (struct sss_tool_cmd_chip_fault_stats *)buf_in; + offset = info->offset; + + info = (struct sss_tool_cmd_chip_fault_stats *)buf_out; + sss_tool_get_chip_fault_stats(hal_dev->hwdev, + info->chip_fault_stats, offset); + + return 0; +} + +static int sss_tool_get_single_card_info(struct sss_hal_dev *hal_dev, const void *buf_in, + u32 in_size, void *buf_out, u32 *out_size) +{ + if (!buf_out || *out_size != sizeof(struct sss_tool_card_info)) { + tool_err("Invalid buf out is NULL, or out_size != %lu\n", + sizeof(struct sss_tool_card_info)); + return -EINVAL; + } + + sss_get_card_info(hal_dev->hwdev, buf_out); + + return 0; +} + +static int sss_tool_is_driver_in_vm(struct sss_hal_dev *hal_dev, + const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + if (!buf_out || (*out_size != sizeof(u8))) { + tool_err("Invalid parameter, buf_out is NULL or out_size != %lu\n", sizeof(u8)); + return -EINVAL; + } + + *((u8 *)buf_out) = sss_is_in_host() ? 0 : 1; + + return 0; +} + +static int sss_tool_get_all_chip_id_cmd(struct sss_hal_dev *hal_dev, + const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + if (*out_size != sizeof(struct sss_card_id) || !buf_out) { + tool_err("Invalid parameter: out_size %u, expect %lu\n", + *out_size, sizeof(struct sss_card_id)); + return -EFAULT; + } + + sss_get_all_chip_id(buf_out); + + return 0; +} + +static int sss_tool_get_card_id(char *dev_name, int *id) +{ + int ret; + + ret = sscanf(dev_name, SSS_CHIP_NAME "%d", id); + if (ret < 0) { + tool_err("Fail to get card id\n"); + return ret; + } + + if (*id >= SSS_TOOL_CARD_MAX || *id < 0) { + tool_err("Invalid chip id %d, out of range: [0-%d]\n", *id, SSS_TOOL_CARD_MAX - 1); + return -EINVAL; + } + + return 0; +} + +static void sss_tool_get_pf_dev_info_param(struct sss_tool_pf_dev_info *dev_info, int card_id, + void **func_array) +{ + u32 func_id; + void *hwdev = NULL; + struct pci_dev *pdev = NULL; + + for (func_id = 0; func_id < SSS_TOOL_PF_DEV_MAX; func_id++) { + hwdev = (void *)func_array[func_id]; + + dev_info[func_id].phy_addr = g_card_pa[card_id]; + + if (!hwdev) { + dev_info[func_id].bar0_size = 0; + dev_info[func_id].bus = 0; + dev_info[func_id].slot = 0; + dev_info[func_id].func = 0; + } else { + pdev = (struct pci_dev *)sss_get_pcidev_hdl(hwdev); + dev_info[func_id].bar0_size = pci_resource_len(pdev, 0); + dev_info[func_id].bus = pdev->bus->number; + dev_info[func_id].slot = PCI_SLOT(pdev->devfn); + dev_info[func_id].func = PCI_FUNC(pdev->devfn); + } + } +} + +static int sss_tool_get_card_adm_mem(int card_id) +{ + int i; + unsigned char *card_va = NULL; + + g_card_id = card_id; + if (!g_card_va[card_id]) { + g_card_va[card_id] = + (void *)__get_free_pages(GFP_KERNEL, SSS_TOOL_PAGE_ORDER); + if (!g_card_va[card_id]) { + tool_err("Fail to alloc adm memory for card %d!\n", card_id); + return -EFAULT; + } + + memset(g_card_va[card_id], 0, PAGE_SIZE * (1 << SSS_TOOL_PAGE_ORDER)); + + g_card_pa[card_id] = virt_to_phys(g_card_va[card_id]); + if (!g_card_pa[card_id]) { + tool_err("Invalid phy addr for card %d is 0\n", card_id); + free_pages((unsigned long)g_card_va[card_id], SSS_TOOL_PAGE_ORDER); + g_card_va[card_id] = NULL; + return -EFAULT; + } + + card_va = g_card_va[card_id]; + for (i = 0; i < (1 << SSS_TOOL_PAGE_ORDER); i++) { + SetPageReserved(virt_to_page(card_va)); + card_va += PAGE_SIZE; + } + } + + return 0; +} + +static int sss_tool_get_pf_dev_info(struct sss_hal_dev *hal_dev, const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + int id; + int ret; + struct sss_tool_pf_dev_info *info = buf_out; + struct sss_card_node *node = sss_get_card_node(hal_dev); + + if (!buf_out || *out_size != sizeof(struct sss_tool_pf_dev_info) * SSS_TOOL_PF_DEV_MAX) { + tool_err("Invalid param: out_size %u, expect %lu\n", + *out_size, sizeof(info) * SSS_TOOL_PF_DEV_MAX); + return -EFAULT; + } + + ret = sss_tool_get_card_id(node->chip_name, &id); + if (ret) + return ret; + + sss_tool_get_pf_dev_info_param(info, id, node->func_handle_array); + + ret = sss_tool_get_card_adm_mem(id); + if (ret) { + tool_err("Fail to get adm memory for userspace %s\n", node->chip_name); + return -EFAULT; + } + + return 0; +} + +long sss_tool_free_card_mem(int id) +{ + unsigned char *va = NULL; + int i; + + if (!g_card_va[id]) + return 0; + + va = g_card_va[id]; + for (i = 0; i < (1 << SSS_TOOL_PAGE_ORDER); i++) { + ClearPageReserved(virt_to_page(va)); + va += PAGE_SIZE; + } + + free_pages((unsigned long)g_card_va[id], SSS_TOOL_PAGE_ORDER); + g_card_va[id] = NULL; + g_card_pa[id] = 0; + + return 0; +} + +static int sss_tool_free_all_card_mem(struct sss_hal_dev *hal_dev, const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + int id; + int ret; + struct sss_card_node *node = sss_get_card_node(hal_dev); + + ret = sss_tool_get_card_id(node->chip_name, &id); + if (ret) + return ret; + + sss_tool_free_card_mem(id); + + return 0; +} + +static int sss_tool_check_card_info_param(char *dev_name, const void *buf_out, u32 out_size) +{ + int ret; + + if (!buf_out || out_size != sizeof(struct sss_card_func_info)) { + tool_err("Invalid out_size %u, expect %lu\n", + out_size, sizeof(struct sss_card_func_info)); + return -EINVAL; + } + + ret = memcmp(dev_name, SSS_CHIP_NAME, strlen(SSS_CHIP_NAME)); + if (ret) { + tool_err("Invalid chip name %s\n", dev_name); + return ret; + } + + return 0; +} + +static int sss_tool_get_card_func_info(struct sss_hal_dev *hal_dev, const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + int ret; + int id = 0; + struct sss_card_func_info *info = buf_out; + struct sss_card_node *node = sss_get_card_node(hal_dev); + + ret = sss_tool_check_card_info_param(node->chip_name, buf_out, *out_size); + if (ret) + return ret; + + ret = sss_tool_get_card_id(node->chip_name, &id); + if (ret) + return ret; + + sss_get_card_func_info(node->chip_name, info); + + if (!info->pf_num) { + tool_err("Fail to get card func info, chip name %s\n", node->chip_name); + return -EFAULT; + } + + ret = sss_tool_get_card_adm_mem(id); + if (ret) { + tool_err("Fail to get adm memory for userspace %s\n", node->chip_name); + return -EFAULT; + } + + info->usr_adm_pa = g_card_pa[id]; + + return 0; +} + +static int sss_tool_get_pf_cap_info(struct sss_hal_dev *hal_dev, const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + struct sss_hwdev *hwdev = NULL; + struct sss_card_node *node = sss_get_card_node(hal_dev); + struct sss_svc_cap_info *in_info = (struct sss_svc_cap_info *)buf_in; + struct sss_svc_cap_info *out_info = (struct sss_svc_cap_info *)buf_out; + + if (*out_size != sizeof(struct sss_svc_cap_info) || + in_size != sizeof(struct sss_svc_cap_info) || + !buf_in || !buf_out) { + tool_err("Invalid out_size %u, in_size: %u, expect %lu\n", + *out_size, in_size, sizeof(struct sss_svc_cap_info)); + return -EINVAL; + } + + if (in_info->func_id >= SSS_MAX_FUNC) { + tool_err("Invalid func id: %u, max_num: %u\n", + in_info->func_id, SSS_MAX_FUNC); + return -EINVAL; + } + + sss_hold_chip_node(); + hwdev = (struct sss_hwdev *)(node->func_handle_array)[in_info->func_id]; + if (!hwdev) { + sss_put_chip_node(); + return -EINVAL; + } + + memcpy(&out_info->cap, SSS_TO_SVC_CAP(hwdev), sizeof(struct sss_service_cap)); + sss_put_chip_node(); + + return 0; +} + +static int sss_tool_get_hw_drv_version(struct sss_hal_dev *hal_dev, const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + int ret; + struct sss_tool_drv_version_info *info = buf_out; + + if (!buf_out || *out_size != sizeof(*info)) { + tool_err("Invalid param, buf_out is NULL or out_size:%u, expect: %lu\n", + *out_size, sizeof(*info)); + return -EINVAL; + } + + ret = snprintf(info->ver, sizeof(info->ver), "%s %s", SSS_DRV_VERSION, + __TIME_STR__); + if (ret < 0) + return -EINVAL; + + return 0; +} + +static int sss_tool_get_pf_id(struct sss_hal_dev *hal_dev, const void *buf_in, u32 in_size, + void *buf_out, u32 *out_size) +{ + struct sss_tool_pf_info *info = NULL; + struct sss_card_node *node = sss_get_card_node(hal_dev); + u32 port_id; + int ret; + + if (!node) + return -ENODEV; + + if (!buf_out || (*out_size != sizeof(*info)) || !buf_in || in_size != sizeof(port_id)) { + tool_err("Invalid out_size from user: %u, expect: %lu, in_size:%u\n", + *out_size, sizeof(*info), in_size); + return -EINVAL; + } + + port_id = *((u32 *)buf_in); + info = (struct sss_tool_pf_info *)buf_out; + + ret = sss_get_pf_id(node, port_id, &info->pf_id, &info->valid); + if (ret != 0) + return ret; + + *out_size = sizeof(*info); + + return 0; +} + +struct sss_tool_hw_cmd_handle g_hw_cmd_handle[] = { + {SSS_TOOL_FUNC_TYPE, sss_tool_get_func_type}, + {SSS_TOOL_GET_FUNC_IDX, sss_tool_get_func_id}, + {SSS_TOOL_GET_CHIP_INFO, sss_tool_get_card_func_info}, + {SSS_TOOL_GET_DRV_VERSION, sss_tool_get_hw_drv_version}, + {SSS_TOOL_GET_PF_ID, sss_tool_get_pf_id}, + {SSS_TOOL_GET_FUNC_CAP, sss_tool_get_pf_cap_info}, + {SSS_TOOL_GET_SELF_TEST_RES, sss_tool_get_self_test_result}, + {SSS_TOOL_GET_CHIP_ID, sss_tool_get_all_chip_id_cmd}, + {SSS_TOOL_GET_PF_DEV_INFO, sss_tool_get_pf_dev_info}, + {SSS_TOOL_IS_DRV_IN_VM, sss_tool_is_driver_in_vm}, + {SSS_TOOL_CMD_FREE_MEM, sss_tool_free_all_card_mem}, + {SSS_TOOL_GET_CHIP_FAULT_STATS, (sss_tool_hw_cmd_func)sss_tool_get_chip_faults_stats}, + {SSS_TOOL_GET_SINGLE_CARD_INFO, (sss_tool_hw_cmd_func)sss_tool_get_single_card_info}, + {SSS_TOOL_GET_HW_STATS, (sss_tool_hw_cmd_func)sss_tool_get_hw_driver_stats}, + {SSS_TOOL_CLEAR_HW_STATS, sss_tool_clear_hw_driver_stats}, +}; + +int sss_tool_msg_to_hw(struct sss_hal_dev *hal_dev, struct sss_tool_msg *tool_msg, + void *buf_in, u32 in_size, void *buf_out, u32 *out_size) +{ + int id; + int ret = 0; + int cmd_num = ARRAY_LEN(g_hw_cmd_handle); + enum sss_tool_driver_cmd_type cmd = + (enum sss_tool_driver_cmd_type)(tool_msg->msg_formate); + + for (id = 0; id < cmd_num; id++) { + if (cmd == g_hw_cmd_handle[id].cmd_type) { + ret = g_hw_cmd_handle[id].func + (hal_dev, buf_in, in_size, buf_out, out_size); + break; + } + } + + if (id == cmd_num) { + tool_err("Fail to send msg to hw, cmd: %d out of range\n", cmd); + return -EINVAL; + } + + return ret; +} diff --git a/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sdk.h b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sdk.h new file mode 100644 index 000000000000..d02af2fe52c1 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sdk.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_SDK_H +#define SSS_TOOL_SDK_H + +#include "sss_tool_comm.h" +#include "sss_tool_hw.h" +#include "sss_hw.h" + +long sss_tool_free_card_mem(int id); + +int sss_tool_msg_to_hw(struct sss_hal_dev *hal_dev, struct sss_tool_msg *tool_msg, + void *buf_in, u32 in_size, void *buf_out, u32 *out_size); + +#endif diff --git a/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sm.c b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sm.c new file mode 100644 index 000000000000..549eb928f5c4 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sm.c @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ +#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt + +#include "sss_hwdev.h" +#include "sss_hwif_adm.h" +#include "sss_tool_comm.h" +#include "sss_tool_sm.h" + +#define SSS_TOOL_CHIP_ACK 1 +#define SSS_TOOL_CHIP_NOACK 0 + +#define SSS_TOOL_SM_CHIP_OP_READ 0x2 +#define SSS_TOOL_SM_CHIP_OP_READ_CLEAR 0x6 + +#define SSS_TOOL_BIT_32 32 + +struct sss_tool_sm_in { + int node; + int id; + int instance; +}; + +struct sss_tool_sm_out { + u64 val1; + u64 val2; +}; + +union sss_tool_sm_chip_request_head { + struct { + u32 pad:15; + u32 ack:1; + u32 op_id:5; + u32 instance:6; + u32 src:5; + } bs; + + u32 value; +}; + +/* counter read request struct */ +struct sss_tool_sm_chip_request { + u32 extra; + union sss_tool_sm_chip_request_head head; + u32 ctr_id; + u32 initial; + u32 pad; +}; + +/* counter read response union */ +union sss_tool_chip_rd_response { + struct { + u32 value1:16; + u32 pad0:16; + u32 pad1[3]; + } bs_ss16_rsp; + + struct { + u32 value1; + u32 pad[3]; + } bs_ss32_rsp; + + struct { + u32 value1:20; + u32 pad0:12; + u32 value2:12; + u32 pad1:20; + u32 pad2[2]; + } bs_sp_rsp; + + struct { + u32 value1; + u32 value2; + u32 pad[2]; + } bs_bs64_rsp; + + struct { + u32 val1_h; + u32 val1_l; + u32 val2_h; + u32 val2_l; + } bs_bp64_rsp; +}; + +typedef int (*sss_tool_sm_handler_func)(void *hwdev, u32 id, u8 instance, + u8 node, struct sss_tool_sm_out *out_buf); + +struct sss_tool_sm_handler { + enum sss_tool_sm_cmd_type msg_name; + sss_tool_sm_handler_func sm_func; +}; + +static void sss_tool_sm_read_msg_create(struct sss_tool_sm_chip_request *request, + u8 instance_id, u8 op_id, + u8 ack, u32 ctr_id, u32 init_val) +{ + request->head.value = 0; + request->head.bs.op_id = op_id; + request->head.bs.ack = ack; + request->head.bs.instance = instance_id; + request->head.value = HTONL(request->head.value); + + request->initial = init_val; + request->ctr_id = ctr_id; + request->ctr_id = HTONL(request->ctr_id); +} + +static void sss_tool_sm_node_htonl(u32 *node, u32 len) +{ + u32 *new_node = node; + u32 i; + + for (i = 0; i < len; i++) { + *new_node = HTONL(*new_node); + new_node++; + } +} + +static int sss_tool_sm_adm_msg_rd(void *hwdev, u32 id, u8 instance, + u8 node, union sss_tool_chip_rd_response *rsp, u8 opcode) +{ + struct sss_tool_sm_chip_request req = {0}; + int ret; + + if (!hwdev) + return -EFAULT; + + if (!SSS_SUPPORT_ADM_MSG((struct sss_hwdev *)hwdev)) { + tool_err("Fail to read sm data, device not support adm msg\n"); + return -EPERM; + } + + sss_tool_sm_read_msg_create(&req, instance, opcode, + SSS_TOOL_CHIP_ACK, id, 0); + + ret = sss_adm_msg_read_ack(hwdev, node, (u8 *)&req, + (unsigned short)sizeof(req), + (void *)rsp, + (unsigned short)sizeof(*rsp)); + if (ret) { + tool_err("Fail to read sm data from adm msg, err(%d)\n", ret); + return ret; + } + + sss_tool_sm_node_htonl((u32 *)rsp, sizeof(*rsp) / sizeof(u32)); + + return 0; +} + +static int sss_tool_sm_msg_rd16(void *hwdev, u32 id, u8 instance, + u8 node, struct sss_tool_sm_out *out_buf) +{ + u16 val1; + union sss_tool_chip_rd_response rsp; + int ret = 0; + + ret = sss_tool_sm_adm_msg_rd(hwdev, id, instance, node, &rsp, SSS_TOOL_SM_CHIP_OP_READ); + if (ret) { + tool_err("Fail to read sm 32 bits\n"); + val1 = ~0; + goto out; + } + + val1 = rsp.bs_ss16_rsp.value1; +out: + out_buf->val1 = val1; + + return ret; +} + +static int sss_tool_sm_msg_rd32(void *hwdev, u32 id, u8 instance, + u8 node, struct sss_tool_sm_out *out_buf) +{ + u32 val1; + union sss_tool_chip_rd_response rsp; + int ret = 0; + + ret = sss_tool_sm_adm_msg_rd(hwdev, id, instance, node, &rsp, SSS_TOOL_SM_CHIP_OP_READ); + if (ret) { + tool_err("Fail to read sm 32 bits\n"); + val1 = ~0; + goto out; + } + + val1 = rsp.bs_ss32_rsp.value1; +out: + out_buf->val1 = val1; + + return ret; +} + +static int sss_tool_sm_msg_rd32_clear(void *hwdev, u32 id, u8 instance, + u8 node, struct sss_tool_sm_out *out_buf) +{ + u32 val1; + union sss_tool_chip_rd_response rsp; + int ret = 0; + + ret = sss_tool_sm_adm_msg_rd(hwdev, id, instance, node, + &rsp, SSS_TOOL_SM_CHIP_OP_READ_CLEAR); + if (ret) { + tool_err("Fail to read sm 32 bits\n"); + val1 = ~0; + goto out; + } + + val1 = rsp.bs_ss32_rsp.value1; + +out: + out_buf->val1 = val1; + return ret; +} + +static int sss_tool_sm_msg_rd128(void *hwdev, u32 id, u8 instance, + u8 node, struct sss_tool_sm_out *out_buf) +{ + u64 val1 = 0; + u64 val2 = 0; + int ret = 0; + union sss_tool_chip_rd_response rsp; + + if ((id & 0x1) != 0) { + tool_err("Invalid id(%u), It is odd number\n", id); + val1 = ~0; + val2 = ~0; + ret = -EINVAL; + goto out; + } + + ret = sss_tool_sm_adm_msg_rd(hwdev, id, instance, node, + &rsp, SSS_TOOL_SM_CHIP_OP_READ); + if (ret) { + tool_err("Fail to read sm 128 bits\n"); + val1 = ~0; + val2 = ~0; + goto out; + } + + sss_tool_sm_node_htonl((u32 *)&rsp, sizeof(rsp) / sizeof(u32)); + val1 = ((u64)rsp.bs_bp64_rsp.val1_h << SSS_TOOL_BIT_32) | rsp.bs_bp64_rsp.val1_l; + val2 = ((u64)rsp.bs_bp64_rsp.val2_h << SSS_TOOL_BIT_32) | rsp.bs_bp64_rsp.val2_l; + +out: + out_buf->val1 = val1; + out_buf->val2 = val2; + + return ret; +} + +static int sss_tool_sm_msg_rd128_clear(void *hwdev, u32 id, u8 instance, + u8 node, struct sss_tool_sm_out *out_buf) +{ + u64 val1 = 0; + u64 val2 = 0; + int ret = 0; + union sss_tool_chip_rd_response rsp; + + if ((id & 0x1) != 0) { + tool_err("Invalid id(%u), It is odd number\n", id); + val1 = ~0; + val2 = ~0; + ret = -EINVAL; + goto out; + } + + ret = sss_tool_sm_adm_msg_rd(hwdev, id, instance, node, + &rsp, SSS_TOOL_SM_CHIP_OP_READ_CLEAR); + if (ret) { + tool_err("Fail to read sm 128 bits\n"); + val1 = ~0; + val2 = ~0; + goto out; + } + + val1 = ((u64)rsp.bs_bp64_rsp.val1_h << SSS_TOOL_BIT_32) | rsp.bs_bp64_rsp.val1_l; + val2 = ((u64)rsp.bs_bp64_rsp.val2_h << SSS_TOOL_BIT_32) | rsp.bs_bp64_rsp.val2_l; + +out: + out_buf->val1 = val1; + out_buf->val2 = val2; + + return ret; +} + +static int sss_tool_sm_msg_rd64(void *hwdev, u32 id, u8 instance, + u8 node, struct sss_tool_sm_out *out_buf) +{ + u64 val1 = 0; + int ret = 0; + union sss_tool_chip_rd_response rsp; + + ret = sss_tool_sm_adm_msg_rd(hwdev, id, instance, node, + &rsp, SSS_TOOL_SM_CHIP_OP_READ); + if (ret) { + tool_err("Fail to read sm 64 bits\n"); + val1 = ~0; + goto out; + } + + val1 = ((u64)rsp.bs_bs64_rsp.value1 << SSS_TOOL_BIT_32) | rsp.bs_bs64_rsp.value2; + +out: + out_buf->val1 = val1; + + return ret; +} + +static int sss_tool_sm_msg_rd64_clear(void *hwdev, u32 id, u8 instance, + u8 node, struct sss_tool_sm_out *out_buf) +{ + u64 val1 = 0; + int ret = 0; + union sss_tool_chip_rd_response rsp; + + ret = sss_tool_sm_adm_msg_rd(hwdev, id, instance, node, + &rsp, SSS_TOOL_SM_CHIP_OP_READ_CLEAR); + if (ret) { + tool_err("Fail to read sm 64 bits\n"); + val1 = ~0; + goto out; + } + + val1 = ((u64)rsp.bs_bs64_rsp.value1 << SSS_TOOL_BIT_32) | rsp.bs_bs64_rsp.value2; + +out: + out_buf->val1 = val1; + + return ret; +} + +const struct sss_tool_sm_handler g_sm_cmd_handle[] = { + {SSS_TOOL_SM_CMD_RD16, sss_tool_sm_msg_rd16}, + {SSS_TOOL_SM_CMD_RD32, sss_tool_sm_msg_rd32}, + {SSS_TOOL_SM_CMD_RD32_CLEAR, sss_tool_sm_msg_rd32_clear}, + {SSS_TOOL_SM_CMD_RD64, sss_tool_sm_msg_rd64}, + {SSS_TOOL_SM_CMD_RD64_CLEAR, sss_tool_sm_msg_rd64_clear}, + {SSS_TOOL_SM_CMD_RD64_PAIR, sss_tool_sm_msg_rd128}, + {SSS_TOOL_SM_CMD_RD64_PAIR_CLEAR, sss_tool_sm_msg_rd128_clear} +}; + +int sss_tool_msg_to_sm(struct sss_hal_dev *hal_dev, struct sss_tool_msg *msg, + void *in_buf, u32 in_len, void *out_buf, u32 *out_len) +{ + int index; + int ret = 0; + int cmd_num = ARRAY_LEN(g_sm_cmd_handle); + u32 msg_formate = msg->msg_formate; + struct sss_tool_sm_in *sm_in = in_buf; + struct sss_tool_sm_out *sm_out = out_buf; + + if (!in_buf || !out_buf || !out_len) { + tool_err("Invalid in_buf or out buf param\n"); + return -EINVAL; + } + + if (in_len != sizeof(*sm_in) || *out_len != sizeof(*sm_out)) { + tool_err("Invalid out buf size :%u, in buf size: %u\n", + *out_len, in_len); + return -EINVAL; + } + + for (index = 0; index < cmd_num; index++) { + if (msg_formate != g_sm_cmd_handle[index].msg_name) + continue; + + ret = g_sm_cmd_handle[index].sm_func(hal_dev->hwdev, (u32)sm_in->id, + (u8)sm_in->instance, (u8)sm_in->node, sm_out); + break; + } + + if (index == cmd_num) { + tool_err("Fail to execute msg %d,could not find callback\n", msg_formate); + return -EINVAL; + } + + if (ret != 0) + tool_err("Fail to get sm information, id:%u, instance:%u, node:%u, msg:%d\n", + sm_in->id, sm_in->instance, sm_in->node, msg_formate); + + *out_len = sizeof(*sm_out); + + return ret; +} diff --git a/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sm.h b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sm.h new file mode 100644 index 000000000000..7c32ebdf2f4d --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/hw/tool/sss_tool_sm.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_SM_H +#define SSS_TOOL_SM_H +#include "sss_pci_global.h" +#include "sss_tool_comm.h" +#include "sss_tool_hw.h" + +#ifndef HTONL +#define HTONL(x) \ + ((((x) & 0x000000ff) << 24) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0xff000000) >> 24)) +#endif + +int sss_tool_msg_to_sm(struct sss_hal_dev *hal_dev, struct sss_tool_msg *msg, + void *in_buf, u32 in_len, void *out_buf, u32 *out_len); + +#endif diff --git a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_export.h b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_export.h index dc98ce2cc96e..b14290fb2f27 100644 --- a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_export.h +++ b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_export.h @@ -85,6 +85,8 @@ bool sss_get_nic_capability(void *hwdev, struct sss_nic_service_cap *capability) */ bool sss_support_nic(void *hwdev); +bool sss_support_ppa(void *hwdev, struct sss_ppa_service_cap *cap); + /* * * @brief sss_get_max_sq_num - get max queue number * @param hwdev: device pointer to hwdev @@ -163,6 +165,8 @@ int sss_get_dev_present_flag(const void *hwdev); */ u8 sss_get_max_pf_num(void *hwdev); +u16 sss_nic_intr_num(void *hwdev); + /* * * @brief sss_get_chip_present_state - get card present state * @param hwdev: device pointer to hwdev diff --git a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_mbx.h b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_mbx.h index a2ac2b3548af..33b5338a3ed7 100644 --- a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_mbx.h +++ b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_mbx.h @@ -171,7 +171,7 @@ enum sss_mod_type { SSS_MOD_TYPE_FLR = 5, SSS_MOD_TYPE_RSVD1 = 6, SSS_MOD_TYPE_CFGM = 7, /* Configuration module */ - SSS_MOD_TYPE_CQM = 8, + SSS_MOD_TYPE_QMM = 8, SSS_MOD_TYPE_RSVD2 = 9, COMM_MOD_FC = 10, SSS_MOD_TYPE_OVS = 11, diff --git a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_statistics.h b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_statistics.h index 9dbc5e2367b4..0dbb4b6963ea 100644 --- a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_statistics.h +++ b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_statistics.h @@ -10,20 +10,26 @@ #include "sss_hw_event.h" #include "sss_hw_aeq.h" +struct sss_qmm_stats { + atomic_t qmm_rsv_cnt[134]; +}; + struct sss_link_event_stats { atomic_t link_down_stats; atomic_t link_up_stats; }; struct sss_fault_event_stats { + atomic_t chip_fault_stats[22][SSS_FAULT_LEVEL_MAX]; atomic_t fault_type_stat[SSS_FAULT_TYPE_MAX]; atomic_t pcie_fault_stats; }; struct sss_hw_stats { atomic_t heart_lost_stats; - struct sss_link_event_stats sss_link_event_stats; - struct sss_fault_event_stats sss_fault_event_stats; + struct sss_qmm_stats qmm_stats; + struct sss_link_event_stats link_event_stats; + struct sss_fault_event_stats fault_event_stats; atomic_t nic_ucode_event_stats[SSS_ERR_MAX]; }; diff --git a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_svc_cap.h b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_svc_cap.h index 805a93237bb4..158ba77fe663 100644 --- a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_svc_cap.h +++ b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hw_svc_cap.h @@ -23,7 +23,7 @@ enum sss_service_type { SSS_SERVICE_TYPE_MAX, SSS_SERVICE_TYPE_INTF = (1 << 15), - SSS_SERVICE_TYPE_CQM = (1 << 16), + SSS_SERVICE_TYPE_QMM = (1 << 16), }; /* RDMA service capability */ diff --git a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hwif_export.h b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hwif_export.h index aa732253fd25..e83810dde176 100644 --- a/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hwif_export.h +++ b/drivers/net/ethernet/3snic/sssnic/include/hw/sss_hwif_export.h @@ -71,6 +71,8 @@ u8 sss_get_pcie_itf_id(void *hwdev); */ enum sss_func_type sss_get_func_type(void *hwdev); +enum sss_func_type sss_get_func_id(void *hwdev); + /* * * @brief sss_get_glb_pf_vf_offset - get vf offset id of pf * @param hwdev: device pointer to hwdev diff --git a/drivers/net/ethernet/3snic/sssnic/include/sss_tool_comm.h b/drivers/net/ethernet/3snic/sssnic/include/sss_tool_comm.h new file mode 100644 index 000000000000..633bd3850af9 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/include/sss_tool_comm.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_COMM_H +#define SSS_TOOL_COMM_H + +#define tool_err(format, ...) pr_err(format, ##__VA_ARGS__) +#define tool_warn(format, ...) pr_warn(format, ##__VA_ARGS__) +#define tool_info(format, ...) pr_info(format, ##__VA_ARGS__) + +#define SSS_TOOL_SHOW_ITEM_LEN 32 + +#define SSS_TOOL_VERSION_INFO_LEN 128 + +#define SSS_TOOL_EPERM 1 /* Operation not permitted */ +#define SSS_TOOL_EIO 2 /* I/O error */ +#define SSS_TOOL_EINVAL 3 /* Invalid argument */ +#define SSS_TOOL_EBUSY 4 /* Device or resource busy */ +#define SSS_TOOL_EOPNOTSUPP 0xFF /* Operation not supported */ + +enum sss_tool_driver_cmd_type { + SSS_TOOL_GET_TX_INFO = 1, + SSS_TOOL_GET_Q_NUM, + SSS_TOOL_GET_TX_WQE_INFO, + SSS_TOOL_TX_MAPPING, + SSS_TOOL_GET_RX_INFO, + SSS_TOOL_GET_RX_WQE_INFO, + SSS_TOOL_GET_RX_CQE_INFO, + SSS_TOOL_UPRINT_FUNC_EN, + SSS_TOOL_UPRINT_FUNC_RESET, + SSS_TOOL_UPRINT_SET_PATH, + SSS_TOOL_UPRINT_GET_STATISTICS, + SSS_TOOL_FUNC_TYPE, + SSS_TOOL_GET_FUNC_IDX, + SSS_TOOL_GET_INTER_NUM, + SSS_TOOL_CLOSE_TX_STREAM, + SSS_TOOL_GET_DRV_VERSION, + SSS_TOOL_CLEAR_FUNC_STATS, + SSS_TOOL_GET_HW_STATS, + SSS_TOOL_CLEAR_HW_STATS, + SSS_TOOL_GET_SELF_TEST_RES, + SSS_TOOL_GET_CHIP_FAULT_STATS, + SSS_TOOL_NIC_RSVD1, + SSS_TOOL_NIC_RSVD2, + SSS_TOOL_NIC_RSVD3, + SSS_TOOL_GET_CHIP_ID, + SSS_TOOL_GET_SINGLE_CARD_INFO, + SSS_TOOL_GET_FIRMWARE_ACTIVE_STATUS, + SSS_TOOL_ROCE_DFX_FUNC, + SSS_TOOL_GET_DEVICE_ID, + SSS_TOOL_GET_PF_DEV_INFO, + SSS_TOOL_CMD_FREE_MEM, + SSS_TOOL_GET_LOOPBACK_MODE = 32, + SSS_TOOL_SET_LOOPBACK_MODE, + SSS_TOOL_SET_LINK_MODE, + SSS_TOOL_SET_PF_BW_LIMIT, + SSS_TOOL_GET_PF_BW_LIMIT, + SSS_TOOL_ROCE_CMD, + SSS_TOOL_GET_POLL_WEIGHT, + SSS_TOOL_SET_POLL_WEIGHT, + SSS_TOOL_GET_HOMOLOGUE, + SSS_TOOL_SET_HOMOLOGUE, + SSS_TOOL_GET_SSET_COUNT, + SSS_TOOL_GET_SSET_ITEMS, + SSS_TOOL_IS_DRV_IN_VM, + SSS_TOOL_LRO_ADPT_MGMT, + SSS_TOOL_SET_INTER_COAL_PARAM, + SSS_TOOL_GET_INTER_COAL_PARAM, + SSS_TOOL_GET_CHIP_INFO, + SSS_TOOL_GET_NIC_STATS_LEN, + SSS_TOOL_GET_NIC_STATS_STRING, + SSS_TOOL_GET_NIC_STATS_INFO, + SSS_TOOL_GET_PF_ID, + SSS_TOOL_NIC_RSVD4, + SSS_TOOL_NIC_RSVD5, + SSS_TOOL_DCB_QOS_INFO, + SSS_TOOL_DCB_PFC_STATE, + SSS_TOOL_DCB_ETS_STATE, + SSS_TOOL_DCB_STATE, + SSS_TOOL_QOS_DEV, + SSS_TOOL_GET_QOS_COS, + SSS_TOOL_GET_ULD_DEV_NAME, + SSS_TOOL_GET_TX_TIMEOUT, + SSS_TOOL_SET_TX_TIMEOUT, + + SSS_TOOL_RSS_CFG = 0x40, + SSS_TOOL_RSS_INDIR, + SSS_TOOL_PORT_ID, + + SSS_TOOL_GET_FUNC_CAP = 0x50, + SSS_TOOL_GET_XSFP_PRESENT = 0x51, + SSS_TOOL_GET_XSFP_INFO = 0x52, + SSS_TOOL_DEV_NAME_TEST = 0x53, + + SSS_TOOL_GET_WIN_STAT = 0x60, + SSS_TOOL_WIN_CSR_READ = 0x61, + SSS_TOOL_WIN_CSR_WRITE = 0x62, + SSS_TOOL_WIN_API_CMD_RD = 0x63, + + SSS_TOOL_VM_COMPAT_TEST = 0xFF +}; + +struct sss_tool_show_item { + char name[SSS_TOOL_SHOW_ITEM_LEN]; + u8 hexadecimal; /* 0: decimal , 1: Hexadecimal */ + u8 rsvd[7]; + u64 value; +}; + +struct sss_tool_drv_version_info { + char ver[SSS_TOOL_VERSION_INFO_LEN]; +}; + +#endif /* _SSS_NIC_MT_H_ */ + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/Makefile b/drivers/net/ethernet/3snic/sssnic/nic/Makefile index 653bbd4538a4..677234f13b6d 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/Makefile +++ b/drivers/net/ethernet/3snic/sssnic/nic/Makefile @@ -2,10 +2,14 @@ # Copyright (c) 2023 3SNIC # +SYS_TIME=$(shell date +%Y-%m-%d_%H:%M:%S) +ccflags-y += -D __TIME_STR__=\"$(SYS_TIME)\" + ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/include ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/include/hw ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/include/kernel ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/nic +ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/nic/tool ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/nic/include ccflags-y += -Werror @@ -33,4 +37,9 @@ sssnic-y := sss_nic_main.o \ sss_nic_rss_cfg.o \ sss_nic_event.o \ sss_nic_io.o \ - sss_nic_netdev_ops_api.o + sss_nic_netdev_ops_api.o \ + ./tool/sss_tool_nic_func.o \ + ./tool/sss_tool_nic_dcb.o \ + ./tool/sss_tool_nic_phy_attr.o \ + ./tool/sss_tool_nic_qp_info.o \ + ./tool/sss_tool_nic_stats.o diff --git a/drivers/net/ethernet/3snic/sssnic/nic/include/sss_nic_cfg_mag_define.h b/drivers/net/ethernet/3snic/sssnic/nic/include/sss_nic_cfg_mag_define.h index d749fbae1962..73bbeb34f642 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/include/sss_nic_cfg_mag_define.h +++ b/drivers/net/ethernet/3snic/sssnic/nic/include/sss_nic_cfg_mag_define.h @@ -455,4 +455,6 @@ struct sss_nic_mag_cfg { struct mutex sfp_mutex; /* mutex used for copy sfp info */ }; +#define SSSNIC_PF_LIMIT_BW_MAX 100 + #endif diff --git a/drivers/net/ethernet/3snic/sssnic/nic/include/sss_nic_tx_define.h b/drivers/net/ethernet/3snic/sssnic/nic/include/sss_nic_tx_define.h index 90bca502a330..b6076c87121a 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/include/sss_nic_tx_define.h +++ b/drivers/net/ethernet/3snic/sssnic/nic/include/sss_nic_tx_define.h @@ -45,9 +45,9 @@ struct sss_nic_sq_stats { u64 dma_map_err; u64 unknown_tunnel_proto; u64 frag_size_zero; + u64 frag_len_overflow; u64 rsvd1; u64 rsvd2; - u64 rsvd3; #ifdef HAVE_NDO_GET_STATS64 struct u64_stats_sync stats_sync; diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_cfg.c b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_cfg.c index afad99d3d633..65cb4ac9c8f9 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_cfg.c +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_cfg.c @@ -1100,3 +1100,42 @@ int sss_nic_rq_hw_pc_info(struct sss_nic_dev *nic_dev, return ret; } +int sss_nic_set_pf_rate(struct sss_nic_dev *nic_dev, u8 speed) +{ + int ret; + u32 pf_rate; + u32 speed_convert[SSSNIC_PORT_SPEED_UNKNOWN] = { + 0, 10, 100, 1000, 10000, 25000, 40000, 50000, 100000, 200000 + }; + struct sss_nic_io *nic_io = nic_dev->nic_io; + struct sss_nic_mbx_tx_rate_cfg rate_cfg = {0}; + u16 out_len = sizeof(rate_cfg); + + if (speed >= SSSNIC_PORT_SPEED_UNKNOWN) { + nic_err(nic_io->dev_hdl, "Invalid speed level: %u\n", speed); + return -EINVAL; + } + + if (nic_io->mag_cfg.pf_bw_limit == SSSNIC_PF_LIMIT_BW_MAX) { + pf_rate = 0; + } else { + pf_rate = (speed_convert[speed] / 100) * nic_io->mag_cfg.pf_bw_limit; + if (pf_rate == 0 && speed != SSSNIC_PORT_SPEED_NOT_SET) + pf_rate = 1; + } + + rate_cfg.func_id = sss_get_global_func_id(nic_dev->hwdev); + rate_cfg.max_rate = pf_rate; + rate_cfg.min_rate = 0; + + ret = sss_nic_l2nic_msg_to_mgmt_sync(nic_dev->hwdev, SSSNIC_MBX_OPCODE_SET_MAX_MIN_RATE, + &rate_cfg, sizeof(rate_cfg), &rate_cfg, &out_len); + if (SSS_ASSERT_SEND_MSG_RETURN(ret, out_len, &rate_cfg)) { + nic_err(nic_dev->dev_hdl, "Fail to set rate:%u, ret: %d, state: 0x%x, out len: 0x%x\n", + pf_rate, ret, rate_cfg.head.state, out_len); + return rate_cfg.head.state ? rate_cfg.head.state : -EIO; + } + + return 0; +} + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_cfg.h b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_cfg.h index 2b90897baba5..387990edd5ed 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_cfg.h +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_cfg.h @@ -99,5 +99,7 @@ void sss_nic_io_deinit(struct sss_nic_dev *nic_dev); int sss_nic_rq_hw_pc_info(struct sss_nic_dev *nic_dev, struct sss_nic_rq_pc_info *out_info, u16 num_qps, u16 wqe_type); +int sss_nic_set_pf_rate(struct sss_nic_dev *nic_dev, u8 speed); + #endif diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_dcb.c b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_dcb.c index bce0dec3725c..573cf72f3b39 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_dcb.c +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_dcb.c @@ -158,8 +158,8 @@ static u8 sss_nic_get_cos_num(u8 cos_bitmap) return cos_count; } -static void sss_nic_sync_dcb_cfg(struct sss_nic_dev *nic_dev, - const struct sss_nic_dcb_config *dcb_config) +void sss_nic_sync_dcb_cfg(struct sss_nic_dev *nic_dev, + const struct sss_nic_dcb_config *dcb_config) { struct sss_nic_dcb_config *hw_config = &nic_dev->hw_dcb_cfg; diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_dcb.h b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_dcb.h index bf426bc9b8f4..00a649598f28 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_dcb.h +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_dcb.h @@ -7,6 +7,11 @@ #include "sss_kernel.h" #include "sss_nic_dcb_define.h" +enum SSSNIC_DCB_FLAGS { + SSSNIC_DCB_UP_COS_SETTING, + SSSNIC_DCB_TRAFFIC_STOPPED, +}; + enum sss_nic_dcb_trust { DCB_PCP, DCB_DSCP, @@ -18,5 +23,7 @@ int sss_nic_dcb_init(struct sss_nic_dev *nic_dev); int sss_nic_update_dcb_cfg(struct sss_nic_dev *nic_dev); void sss_nic_update_sq_cos(struct sss_nic_dev *nic_dev, u8 dcb_en); void sss_nic_update_qp_cos_map(struct sss_nic_dev *nic_dev, u8 cos_num); +void sss_nic_sync_dcb_cfg(struct sss_nic_dev *nic_dev, + const struct sss_nic_dcb_config *dcb_config); #endif diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_ethtool_stats_api.c b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_ethtool_stats_api.c index 543441f0b67e..91de82b658fa 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_ethtool_stats_api.c +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_ethtool_stats_api.c @@ -25,6 +25,8 @@ #include "sss_nic_tx.h" #include "sss_nic_rx.h" #include "sss_nic_ethtool_stats_api.h" +#include "sss_tool_comm.h" +#include "sss_tool_nic.h" #define SSSNIC_SET_SUPPORTED_MODE 0 #define SSSNIC_SET_ADVERTISED_MODE 1 @@ -89,6 +91,35 @@ do { \ (len) == sizeof(u16) ? *(u16 *)(ptr) : *(u8 *)(ptr) \ ) +#define SSSNIC_DEV_STATS_PACK(items, item_idx, array, stats_ptr) \ +do { \ + int j; \ + for (j = 0; j < ARRAY_LEN(array); j++) { \ + memcpy((items)[item_idx].name, (array)[j].name, SSS_TOOL_SHOW_ITEM_LEN); \ + (items)[item_idx].hexadecimal = 0; \ + (items)[item_idx].value = \ + SSSNIC_GET_VALUE_OF_PTR((array)[j].len, \ + (char *)(stats_ptr) + (array)[j].offset); \ + (item_idx)++; \ + } \ +} while (0) + +#define SSSNIC_QUEUE_STATS_PACK(items, item_idx, array, stats_ptr, qid) \ +do { \ + int j; \ + for (j = 0; j < ARRAY_LEN(array); j++) { \ + memcpy((items)[item_idx].name, (array)[j].name, \ + SSS_TOOL_SHOW_ITEM_LEN); \ + snprintf((items)[item_idx].name, SSS_TOOL_SHOW_ITEM_LEN, \ + (array)[j].name, (qid)); \ + (items)[item_idx].hexadecimal = 0; \ + (items)[item_idx].value = \ + SSSNIC_GET_VALUE_OF_PTR((array)[j].len, \ + (char *)(stats_ptr) + (array)[j].offset); \ + (item_idx)++; \ + } \ +} while (0) + #define SSSNIC_CONVERT_DATA_TYPE(len, p) (((len) == sizeof(u64)) ? *(u64 *)(p) : *(u32 *)(p)) #define SSSNIC_AUTONEG_STRING(autoneg) ((autoneg) ? ("autong enable") : ("autong disable")) #define SSSNIC_AUTONEG_ENABLE(autoneg) ((autoneg) ? SSSNIC_PORT_CFG_AN_ON : SSSNIC_PORT_CFG_AN_OFF) @@ -127,6 +158,17 @@ static struct sss_nic_stats g_nic_sq_stats[] = { SSSNIC_SQ_STATS(tx_dropped), }; +static struct sss_nic_stats g_nic_sq_stats_extern[] = { + SSSNIC_SQ_STATS(skb_pad_err), + SSSNIC_SQ_STATS(offload_err), + SSSNIC_SQ_STATS(dma_map_err), + SSSNIC_SQ_STATS(unknown_tunnel_proto), + SSSNIC_SQ_STATS(frag_size_zero), + SSSNIC_SQ_STATS(frag_len_overflow), + SSSNIC_SQ_STATS(rsvd1), + SSSNIC_SQ_STATS(rsvd2), +}; + static struct sss_nic_stats g_nic_rq_stats[] = { SSSNIC_RQ_STATS(rx_packets), SSSNIC_RQ_STATS(rx_bytes), @@ -140,6 +182,14 @@ static struct sss_nic_stats g_nic_rq_stats[] = { SSSNIC_RQ_STATS(rx_buf_errors), }; +static struct sss_nic_stats g_nic_rq_stats_extern[] = { + SSSNIC_RQ_STATS(alloc_rx_dma_err), + SSSNIC_RQ_STATS(alloc_skb_err), + SSSNIC_RQ_STATS(reset_drop_sge), + SSSNIC_RQ_STATS(large_xdp_pkts), + SSSNIC_RQ_STATS(rsvd2), +}; + static struct sss_nic_stats g_netdev_stats[] = { SSSNIC_NETDEV_STATS(rx_packets), SSSNIC_NETDEV_STATS(tx_packets), @@ -167,6 +217,13 @@ static struct sss_nic_stats g_dev_stats[] = { SSSNIC_TX_STATS(tx_timeout), }; +static struct sss_nic_stats g_dev_stats_extern[] = { + SSSNIC_TX_STATS(tx_drop), + SSSNIC_TX_STATS(tx_invalid_qid), + SSSNIC_TX_STATS(rsvd1), + SSSNIC_TX_STATS(rsvd2), +}; + static struct sss_nic_stats g_function_stats[] = { SSSNIC_FUNCTION_STATS(tx_unicast_pkts), SSSNIC_FUNCTION_STATS(tx_unicast_bytes), @@ -432,6 +489,20 @@ static sss_nic_port_type_handler_t g_link_port_set_handler[] = { sss_nic_set_none_port }; +u32 sss_nic_get_io_stats_size(const struct sss_nic_dev *nic_dev) +{ + u32 count; + + count = ARRAY_LEN(g_dev_stats) + + ARRAY_LEN(g_dev_stats_extern) + + (ARRAY_LEN(g_nic_sq_stats) + + ARRAY_LEN(g_nic_sq_stats_extern) + + ARRAY_LEN(g_nic_rq_stats) + + ARRAY_LEN(g_nic_rq_stats_extern)) * nic_dev->max_qp_num; + + return count; +} + int sss_nic_eth_ss_test(struct sss_nic_dev *nic_dev) { return ARRAY_LEN(g_test_strings); @@ -959,3 +1030,29 @@ int sssnic_set_link_settings(struct net_device *netdev, return 0; } + +void sss_nic_get_io_stats(const struct sss_nic_dev *nic_dev, void *stats) +{ + struct sss_tool_show_item *items = stats; + int item_idx = 0; + u16 qid; + + SSSNIC_DEV_STATS_PACK(items, item_idx, g_dev_stats, &nic_dev->tx_stats); + SSSNIC_DEV_STATS_PACK(items, item_idx, g_dev_stats_extern, + &nic_dev->tx_stats); + + for (qid = 0; qid < nic_dev->max_qp_num; qid++) { + SSSNIC_QUEUE_STATS_PACK(items, item_idx, g_nic_sq_stats, + &nic_dev->sq_desc_group[qid].stats, qid); + SSSNIC_QUEUE_STATS_PACK(items, item_idx, g_nic_sq_stats_extern, + &nic_dev->sq_desc_group[qid].stats, qid); + } + + for (qid = 0; qid < nic_dev->max_qp_num; qid++) { + SSSNIC_QUEUE_STATS_PACK(items, item_idx, g_nic_rq_stats, + &nic_dev->rq_desc_group[qid].stats, qid); + SSSNIC_QUEUE_STATS_PACK(items, item_idx, g_nic_rq_stats_extern, + &nic_dev->rq_desc_group[qid].stats, qid); + } +} + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_ethtool_stats_api.h b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_ethtool_stats_api.h index c2b5a7c23102..cf2b1cbe894a 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_ethtool_stats_api.h +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_ethtool_stats_api.h @@ -104,4 +104,6 @@ int sss_nic_set_settings_to_hw(struct sss_nic_dev *nic_dev, int sssnic_set_link_settings(struct net_device *netdev, u8 autoneg, u32 speed); +void sss_nic_get_io_stats(const struct sss_nic_dev *nic_dev, void *stats); + #endif diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_event.c b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_event.c index abbecc57ea05..9ea8113edf04 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_event.c +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_event.c @@ -543,7 +543,7 @@ static int _sss_nic_event_handler(void *hwdev, u16 cmd, void *in_buf, u16 in_siz ((struct sss_mgmt_msg_head *)out_buf)->state = SSS_MGMT_CMD_UNSUPPORTED; *out_size = sizeof(struct sss_mgmt_msg_head); - sdk_warn(nic_io->dev_hdl, "Unsupport nic event, cmd: %u\n", cmd); + nic_warn(nic_io->dev_hdl, "Unsupport nic event, cmd: %u\n", cmd); return 0; } diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_mag_cfg.c b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_mag_cfg.c index c6522d87eba5..c11ec5a24515 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_mag_cfg.c +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_mag_cfg.c @@ -161,6 +161,15 @@ int sss_nic_set_loopback_mode(struct sss_nic_dev *nic_dev, u8 lp_mode, u8 enable return sss_nic_cfg_loopback_mode(nic_dev, SSS_MGMT_MSG_SET_CMD, &lp_mode, &enable); } +int sss_nic_get_loopback_mode(struct sss_nic_dev *nic_dev, u8 *mode, u8 *enable) +{ + if (!nic_dev || !mode || !enable) + return -EINVAL; + + return sss_nic_cfg_loopback_mode(nic_dev, SSS_MGMT_MSG_GET_CMD, mode, + enable); +} + int sss_nic_set_hw_led_state(struct sss_nic_dev *nic_dev, enum sss_nic_mag_led_type led_type, enum sss_nic_mag_led_mode led_mode) { @@ -361,7 +370,7 @@ static void sss_nic_link_status_event_handler(struct sss_nic_io *nic_io, struct sss_event_info event_info = {0}; struct sss_nic_event_link_info *link_info = (void *)event_info.event_data; - sdk_info(nic_io->dev_hdl, "Link status report received, func_id: %u, status: %u\n", + nic_info(nic_io->dev_hdl, "Link status report received, func_id: %u, status: %u\n", sss_get_global_func_id(nic_io->hwdev), in_link_state->status); sss_update_link_stats(nic_io->hwdev, in_link_state->status); @@ -415,7 +424,7 @@ static void sss_nic_port_sfp_event_handler(struct sss_nic_io *nic_io, struct sss_nic_cache_port_sfp *routine_cmd = NULL; if (in_size != sizeof(*in_xsfp_info)) { - sdk_err(nic_io->dev_hdl, "Invalid in_size: %u, should be %ld\n", + nic_err(nic_io->dev_hdl, "Invalid in_size: %u, should be %ld\n", in_size, sizeof(*in_xsfp_info)); return; } @@ -435,7 +444,7 @@ static void sss_nic_port_sfp_absent_event_handler(struct sss_nic_io *nic_io, struct sss_nic_cache_port_sfp *routine_cmd = NULL; if (in_size != sizeof(*in_xsfp_present)) { - sdk_err(nic_io->dev_hdl, "Invalid in_size: %u, should be %ld\n", + nic_err(nic_io->dev_hdl, "Invalid in_size: %u, should be %ld\n", in_size, sizeof(*in_xsfp_present)); return; } @@ -447,7 +456,7 @@ static void sss_nic_port_sfp_absent_event_handler(struct sss_nic_io *nic_io, mutex_unlock(&nic_io->mag_cfg.sfp_mutex); } -static bool sss_nic_if_sfp_absent(struct sss_nic_dev *nic_dev) +bool sss_nic_if_sfp_absent(struct sss_nic_dev *nic_dev) { int ret; bool sfp_abs_state; @@ -484,8 +493,8 @@ static bool sss_nic_if_sfp_absent(struct sss_nic_dev *nic_dev) return !!xsfp_present.abs_status; } -static int sss_nic_get_sfp_info(struct sss_nic_dev *nic_dev, - struct sss_nic_mbx_get_xsfp_info *xsfp_info) +int sss_nic_get_sfp_info(struct sss_nic_dev *nic_dev, + struct sss_nic_mbx_get_xsfp_info *xsfp_info) { int ret; u16 out_len = sizeof(*xsfp_info); @@ -709,7 +718,7 @@ static int _sss_nic_mag_event_handler(void *hwdev, u16 cmd, out_msg_head->state = SSS_MGMT_CMD_UNSUPPORTED; *out_size = sizeof(*out_msg_head); - sdk_warn(nic_io->dev_hdl, "Invalid mag event cmd: %u\n", cmd); + nic_warn(nic_io->dev_hdl, "Invalid mag event cmd: %u\n", cmd); return 0; } diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_mag_cfg.h b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_mag_cfg.h index 2d9e6e000d90..ef112925cf50 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_mag_cfg.h +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_mag_cfg.h @@ -69,4 +69,11 @@ int sss_nic_pf_mag_mbx_handler(void *hwdev, u16 vf_id, u16 cmd, void *buf_in, u16 in_size, void *buf_out, u16 *out_size); +int sss_nic_get_sfp_info(struct sss_nic_dev *nic_dev, + struct sss_nic_mbx_get_xsfp_info *xsfp_info); + +bool sss_nic_if_sfp_absent(struct sss_nic_dev *nic_dev); + +int sss_nic_get_loopback_mode(struct sss_nic_dev *nic_dev, u8 *mode, u8 *enable); + #endif diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_main.c b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_main.c index cad51ef881a3..22968d4c6e24 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_main.c +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_main.c @@ -40,6 +40,8 @@ #include "sss_nic_netdev_ops_api.h" #include "sss_nic_ntuple.h" #include "sss_nic_event.h" +#include "sss_tool_nic_func.h" + #define DEFAULT_POLL_BUDGET 64 static u32 poll_budget = DEFAULT_POLL_BUDGET; @@ -1021,6 +1023,7 @@ struct sss_uld_info g_nic_uld_info = { .suspend = NULL, .resume = NULL, .event = sss_nic_event, + .ioctl = sss_tool_ioctl, }; struct sss_uld_info *get_nic_uld_info(void) diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_netdev_ops.c b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_netdev_ops.c index e5c5dd64ae57..9f623f4b1ab3 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_netdev_ops.c +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_netdev_ops.c @@ -603,7 +603,7 @@ static int sss_nic_ndo_set_vf_tx_rate(struct net_device *netdev, int vf_id, } ret = sss_nic_set_vf_tx_rate_limit(nic_dev->nic_io, (u16)SSSNIC_OS_VF_ID_TO_HW(vf_id), - (u32)max_tx_rate, (u32)min_tx_rate); + (u32)min_tx_rate, (u32)max_tx_rate); if (ret != 0) { nicif_err(nic_dev, drv, netdev, "Fail to set VF %d max rate %d min rate %d%s\n", diff --git a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_netdev_ops_api.h b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_netdev_ops_api.h index 66cdfc97afbb..bb8bfce43c01 100644 --- a/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_netdev_ops_api.h +++ b/drivers/net/ethernet/3snic/sssnic/nic/sss_nic_netdev_ops_api.h @@ -64,4 +64,6 @@ void sss_nic_get_tx_stats(struct sss_nic_dev *nic_dev, void sss_nic_get_rx_stats(struct sss_nic_dev *nic_dev, struct rtnl_link_stats64 *stats); +u32 sss_nic_get_io_stats_size(const struct sss_nic_dev *nic_dev); + #endif diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic.h b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic.h new file mode 100644 index 000000000000..b91ecd8e7e3a --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_NIC_H +#define SSS_TOOL_NIC_H + +#define SSS_TOOL_DCB_OPCODE_WR BIT(0) /* 1 - write, 0 - read */ + +#define SSS_TOOL_MSG_QOS_DEV_TRUST BIT(0) +#define SSS_TOOL_MSG_QOS_DEV_DFT_COS BIT(1) +#define SSS_TOOL_MSG_QOS_DEV_PCP2COS BIT(2) +#define SSS_TOOL_MSG_QOS_DEV_DSCP2COS BIT(3) + +struct sss_tool_loop_mode { + u32 loop_mode; + u32 loop_ctrl; +}; + +struct sss_tool_wqe_info { + int q_id; + void *slq_handle; + unsigned int wqe_id; +}; + +struct sss_tool_hw_page { + u64 phy_addr; + u64 *map_addr; +}; + +struct sss_tool_sq_info { + u16 q_id; + u16 pi; + u16 ci; /* sw_ci */ + u16 fi; /* hw_ci */ + u32 q_depth; + u16 pi_reverse; /* TODO: what is this? */ + u16 wqebb_size; + u8 priority; + u16 *ci_addr; + u64 cla_addr; + void *slq_handle; + /* TODO: NIC don't use direct wqe */ + struct sss_tool_hw_page direct_wqe; + struct sss_tool_hw_page doorbell; + u32 page_idx; + u32 glb_sq_id; +}; + +struct sss_tool_rq_info { + u16 q_id; + u16 delta; + u16 hw_pi; + u16 ci; /* sw_ci */ + u16 sw_pi; + u16 wqebb_size; + u16 q_depth; + u16 buf_len; + + void *slq_handle; + u64 ci_wqe_page_addr; + u64 ci_cla_tbl_addr; + + u8 coalesc_timer_cfg; + u8 pending_limt; + u16 msix_idx; + u32 msix_vector; +}; + +struct sss_tool_msg_head { + u8 status; + u8 rsvd1[3]; +}; + +struct sss_tool_dcb_state { + struct sss_tool_msg_head head; + + u16 op_code; /* 0 - get dcb state, 1 - set dcb state */ + u8 state; /* 0 - disable, 1 - enable dcb */ + u8 rsvd; +}; + +struct sss_tool_qos_dev_cfg { + struct sss_tool_msg_head head; + + u8 op_code; /* 0:get 1: set */ + u8 rsvd0; + u16 cfg_bitmap; /* bit0 - trust, bit1 - dft_cos, bit2 - pcp2cos, bit3 - dscp2cos */ + + u8 trust; /* 0 - pcp, 1 - dscp */ + u8 dft_cos; + u16 rsvd1; + u8 pcp2cos[8]; /* 必须8个一起配置 */ + + /* 配置dscp2cos时,若cos值设置为0xFF*/ + /*驱动则忽略此dscp优先级的配置*/ + /*允许一次性配置多个dscp跟cos的映射关系 */ + u8 dscp2cos[64]; + u32 rsvd2[4]; +}; + +struct sss_tool_qos_cos_cfg { + struct sss_tool_msg_head head; + + u8 port_id; + u8 func_cos_bitmap; + u8 port_cos_bitmap; + u8 func_max_cos_num; + u32 rsvd2[4]; +}; + +#endif /* SSS_TOOL_NIC_H */ + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_dcb.c b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_dcb.c new file mode 100644 index 000000000000..a49d6bc8b3ba --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_dcb.c @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt + +#include "sss_nic_cfg.h" +#include "sss_nic_dcb.h" +#include "sss_tool_comm.h" +#include "sss_tool_nic.h" +#include "sss_nic_rx_init.h" +#include "sss_nic_netdev_ops_api.h" + +#define SSS_TOOL_DBG_DFLT_DSCP_VAL 0xFF + +static int sss_tool_update_pcp_cfg(struct sss_nic_dev *nic_dev, + const struct sss_tool_qos_dev_cfg *qos_cfg) +{ + u8 valid_cos_bitmap = 0; + u8 cos_num = 0; + int i; + + if (!(qos_cfg->cfg_bitmap & SSS_TOOL_MSG_QOS_DEV_PCP2COS)) + return 0; + + for (i = 0; i < SSSNIC_DCB_UP_MAX; i++) { + if (!(nic_dev->dft_func_cos_bitmap & BIT(qos_cfg->pcp2cos[i]))) { + tool_err("Invalid pcp cos:%u, func cos valid map is %u", + qos_cfg->pcp2cos[i], nic_dev->dft_func_cos_bitmap); + return -EINVAL; + } + + if ((BIT(qos_cfg->pcp2cos[i]) & valid_cos_bitmap) == 0) { + cos_num++; + valid_cos_bitmap |= (u8)BIT(qos_cfg->pcp2cos[i]); + } + } + + nic_dev->backup_dcb_cfg.pcp_valid_cos_map = valid_cos_bitmap; + nic_dev->backup_dcb_cfg.pcp_user_cos_num = cos_num; + memcpy(nic_dev->backup_dcb_cfg.pcp2cos, qos_cfg->pcp2cos, sizeof(qos_cfg->pcp2cos)); + + return 0; +} + +static int sss_tool_update_dscp_cfg(struct sss_nic_dev *nic_dev, + const struct sss_tool_qos_dev_cfg *qos_cfg) +{ + u8 valid_cos_bitmap = 0; + u8 cos_num = 0; + u8 cos; + int i; + + if (!(qos_cfg->cfg_bitmap & SSS_TOOL_MSG_QOS_DEV_DSCP2COS)) + return 0; + + for (i = 0; i < SSSNIC_DCB_IP_PRI_MAX; i++) { + if (qos_cfg->dscp2cos[i] != SSS_TOOL_DBG_DFLT_DSCP_VAL) + cos = qos_cfg->dscp2cos[i]; + else + cos = nic_dev->backup_dcb_cfg.dscp2cos[i]; + + if (cos >= SSSNIC_DCB_UP_MAX || !(nic_dev->dft_func_cos_bitmap & BIT(cos))) { + tool_err("Invalid dscp cos:%u, func cos valid map is %u", + cos, nic_dev->dft_func_cos_bitmap); + return -EINVAL; + } + + if ((BIT(cos) & valid_cos_bitmap) == 0) { + cos_num++; + valid_cos_bitmap |= (u8)BIT(cos); + } + } + + for (i = 0; i < SSSNIC_DCB_IP_PRI_MAX; i++) { + if (qos_cfg->dscp2cos[i] != SSS_TOOL_DBG_DFLT_DSCP_VAL) + nic_dev->backup_dcb_cfg.dscp2cos[i] = qos_cfg->dscp2cos[i]; + else + nic_dev->backup_dcb_cfg.dscp2cos[i] = nic_dev->hw_dcb_cfg.dscp2cos[i]; + } + + nic_dev->backup_dcb_cfg.dscp_valid_cos_map = valid_cos_bitmap; + nic_dev->backup_dcb_cfg.dscp_user_cos_num = cos_num; + + return 0; +} + +static int sss_tool_update_pcp_dscp_cfg(struct sss_nic_dev *nic_dev, + const struct sss_tool_qos_dev_cfg *qos_cfg) +{ + int ret; + + ret = sss_tool_update_pcp_cfg(nic_dev, qos_cfg); + if (ret != 0) { + tool_err("Fail to update pcp cfg\n"); + return ret; + } + + ret = sss_tool_update_dscp_cfg(nic_dev, qos_cfg); + if (ret != 0) + tool_err("Fail to update dscp cfg\n"); + + return ret; +} + +static int sss_tool_update_wanted_qos_cfg(struct sss_nic_dev *nic_dev, + const void *in_buf) +{ + const struct sss_tool_qos_dev_cfg *qos_cfg = in_buf; + u8 valid_cos_bitmap; + u8 cos_num; + int ret; + + if (qos_cfg->cfg_bitmap & SSS_TOOL_MSG_QOS_DEV_TRUST) { + if (qos_cfg->trust > DCB_DSCP) { + tool_err("Invalid trust:%u of qos cfg\n", qos_cfg->trust); + return -EINVAL; + } + + nic_dev->backup_dcb_cfg.trust = qos_cfg->trust; + } + + if (qos_cfg->cfg_bitmap & SSS_TOOL_MSG_QOS_DEV_DFT_COS) { + if (!(BIT(qos_cfg->dft_cos) & nic_dev->dft_func_cos_bitmap)) { + tool_err("Invalid default cos:%u of qos cfg\n", qos_cfg->dft_cos); + return -EINVAL; + } + + nic_dev->backup_dcb_cfg.default_cos = qos_cfg->dft_cos; + } + + ret = sss_tool_update_pcp_dscp_cfg(nic_dev, qos_cfg); + if (ret != 0) + return ret; + + if (nic_dev->backup_dcb_cfg.trust != DCB_PCP) { + valid_cos_bitmap = nic_dev->backup_dcb_cfg.dscp_valid_cos_map; + cos_num = nic_dev->backup_dcb_cfg.dscp_user_cos_num; + } else { + valid_cos_bitmap = nic_dev->backup_dcb_cfg.pcp_valid_cos_map; + cos_num = nic_dev->backup_dcb_cfg.pcp_user_cos_num; + } + + if (SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_DCB_ENABLE)) { + if (cos_num > nic_dev->qp_res.qp_num) { + tool_err("Invalid cos num, DCB is on, cos num:%d need less than channel num:%u\n", + cos_num, nic_dev->qp_res.qp_num); + return -EOPNOTSUPP; + } + } + + if (!(BIT(nic_dev->backup_dcb_cfg.default_cos) & valid_cos_bitmap)) { + tool_info("Success to update cos %u to %u\n", + nic_dev->backup_dcb_cfg.default_cos, (u8)fls(valid_cos_bitmap) - 1); + nic_dev->backup_dcb_cfg.default_cos = (u8)fls(valid_cos_bitmap) - 1; + } + + return 0; +} + +static int sss_tool_set_tx_cos_state(struct sss_nic_dev *nic_dev, u8 dcb_en) +{ + int ret; + u8 i; + struct sss_nic_dcb_info dcb_info = {0}; + struct sss_nic_dcb_config *dcb_cfg = &nic_dev->hw_dcb_cfg; + + dcb_info.trust = dcb_cfg->trust; + dcb_info.default_cos = dcb_cfg->default_cos; + dcb_info.dcb_on = dcb_en; + + if (!dcb_en) { + memset(dcb_info.dscp2cos, dcb_cfg->default_cos, sizeof(dcb_info.dscp2cos)); + memset(dcb_info.pcp2cos, dcb_cfg->default_cos, sizeof(dcb_info.pcp2cos)); + + } else { + for (i = 0; i < SSSNIC_DCB_IP_PRI_MAX; i++) + dcb_info.dscp2cos[i] = dcb_cfg->dscp2cos[i]; + for (i = 0; i < SSSNIC_DCB_COS_MAX; i++) + dcb_info.pcp2cos[i] = dcb_cfg->pcp2cos[i]; + } + + ret = sss_nic_set_dcb_info(nic_dev->nic_io, &dcb_info); + if (ret != 0) + tool_err("Fail to set dcb state\n"); + + return ret; +} + +static int sss_tool_configure_dcb_hw(struct sss_nic_dev *nic_dev, u8 dcb_en) +{ + int ret; + u8 user_cos_num = sss_nic_get_user_cos_num(nic_dev); + + ret = sss_nic_set_hw_dcb_state(nic_dev, 1, dcb_en); + if (ret != 0) { + tool_err("Fail to set dcb state\n"); + return ret; + } + + sss_nic_update_qp_cos_map(nic_dev, user_cos_num); + sss_nic_update_sq_cos(nic_dev, dcb_en); + + if (SSSNIC_FUNC_IS_VF(nic_dev->hwdev)) { + /* VF does not support DCB, use the default cos */ + nic_dev->hw_dcb_cfg.default_cos = (u8)fls(nic_dev->dft_func_cos_bitmap) - 1; + + return 0; + } + + ret = sss_tool_set_tx_cos_state(nic_dev, dcb_en); + if (ret != 0) { + tool_err("Fail to set tx cos state\n"); + goto set_tx_cos_fail; + } + + ret = sss_nic_update_rx_rss(nic_dev); + if (ret != 0) { + tool_err("Fail to configure rx\n"); + goto update_rx_rss_fail; + } + + if (!dcb_en) + SSSNIC_CLEAR_NIC_DEV_FLAG(nic_dev, SSSNIC_DCB_ENABLE); + else + SSSNIC_SET_NIC_DEV_FLAG(nic_dev, SSSNIC_DCB_ENABLE); + + return 0; +update_rx_rss_fail: + sss_tool_set_tx_cos_state(nic_dev, dcb_en ? 0 : 1); + +set_tx_cos_fail: + sss_nic_update_sq_cos(nic_dev, dcb_en ? 0 : 1); + sss_nic_set_hw_dcb_state(nic_dev->hwdev, 1, dcb_en ? 0 : 1); + + return ret; +} + +static int sss_tool_setup_cos(struct net_device *netdev, u8 cos) +{ + struct sss_nic_dev *nic_dev = netdev_priv(netdev); + + if (cos > nic_dev->max_cos_num) { + tool_err("Invalid num_tc: %u more then max cos: %u\n", cos, nic_dev->max_cos_num); + return -EINVAL; + } + + if (cos && SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_SAME_RXTX)) { + tool_err("Fail to enable DCB while Symmetric RSS is enabled\n"); + return -EOPNOTSUPP; + } + + return sss_tool_configure_dcb_hw(nic_dev, cos ? 1 : 0); +} + +static void sss_tool_change_qos_cfg(struct sss_nic_dev *nic_dev, + const struct sss_nic_dcb_config *dcb_cfg) +{ + u8 user_cos_num = sss_nic_get_user_cos_num(nic_dev); + + sss_nic_sync_dcb_cfg(nic_dev, dcb_cfg); + sss_nic_update_qp_cos_map(nic_dev, user_cos_num); + + clear_bit(SSSNIC_DCB_UP_COS_SETTING, &nic_dev->dcb_flags); +} + +static int sss_tool_dcbcfg_set_up_bitmap(struct sss_nic_dev *nic_dev) +{ + int ret; + u8 user_cos_num = sss_nic_get_user_cos_num(nic_dev); + struct sss_nic_dcb_config old_dcb_cfg; + bool netif_run = false; + + memcpy(&old_dcb_cfg, &nic_dev->hw_dcb_cfg, sizeof(struct sss_nic_dcb_config)); + + if (!memcmp(&nic_dev->backup_dcb_cfg, &old_dcb_cfg, sizeof(struct sss_nic_dcb_config))) { + tool_info("Valid up bitmap is the same, nothing has to change\n"); + return 0; + } + + rtnl_lock(); + if (netif_running(nic_dev->netdev)) { + sss_nic_vport_down(nic_dev); + netif_run = true; + } + + if (test_and_set_bit(SSSNIC_DCB_UP_COS_SETTING, &nic_dev->dcb_flags)) { + tool_warn("Cos up map setup in inprocess, please try again later\n"); + ret = -EFAULT; + goto set_qos_cfg_fail; + } + + sss_tool_change_qos_cfg(nic_dev, &nic_dev->backup_dcb_cfg); + + if (SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_DCB_ENABLE)) { + ret = sss_tool_setup_cos(nic_dev->netdev, user_cos_num); + if (ret != 0) + goto setup_cos_fail; + } + + if (netif_run) { + ret = sss_nic_vport_up(nic_dev); + if (ret != 0) + goto vport_up_fail; + } + + rtnl_unlock(); + + return 0; + +vport_up_fail: + if (SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_DCB_ENABLE)) + sss_tool_setup_cos(nic_dev->netdev, user_cos_num ? 0 : user_cos_num); + +setup_cos_fail: + sss_tool_change_qos_cfg(nic_dev, &old_dcb_cfg); + +set_qos_cfg_fail: + if (netif_run) + sss_nic_vport_up(nic_dev); + + rtnl_unlock(); + + return ret; +} + +int sss_tool_dcb_mt_qos_map(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + int ret; + u8 i; + struct sss_tool_qos_dev_cfg *qos_out = out_buf; + + if (!out_buf || !out_len || !in_buf) { + tool_err("Invalid param, use null pointer\n"); + return -EFAULT; + } + + if (in_len != sizeof(*qos_out) || *out_len != sizeof(*qos_out)) { + tool_err("Invalid in len: %u or outlen: %u is not equal to %lu\n", + in_len, *out_len, sizeof(*qos_out)); + return -EINVAL; + } + + memcpy(qos_out, in_buf, sizeof(*qos_out)); + qos_out->head.status = 0; + if (qos_out->op_code & SSS_TOOL_DCB_OPCODE_WR) { + memcpy(&nic_dev->backup_dcb_cfg, &nic_dev->hw_dcb_cfg, + sizeof(struct sss_nic_dcb_config)); + ret = sss_tool_update_wanted_qos_cfg(nic_dev, in_buf); + if (ret != 0) { + qos_out->head.status = SSS_TOOL_EINVAL; + return 0; + } + + ret = sss_tool_dcbcfg_set_up_bitmap(nic_dev); + if (ret != 0) + qos_out->head.status = SSS_TOOL_EIO; + } else { + for (i = 0; i < SSSNIC_DCB_IP_PRI_MAX; i++) + qos_out->dscp2cos[i] = nic_dev->hw_dcb_cfg.dscp2cos[i]; + for (i = 0; i < SSSNIC_DCB_UP_MAX; i++) + qos_out->pcp2cos[i] = nic_dev->hw_dcb_cfg.pcp2cos[i]; + qos_out->trust = nic_dev->hw_dcb_cfg.trust; + qos_out->dft_cos = nic_dev->hw_dcb_cfg.default_cos; + } + + return 0; +} + +int sss_tool_dcb_mt_dcb_state(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + int ret; + u8 user_cos_num = sss_nic_get_user_cos_num(nic_dev); + struct sss_tool_dcb_state *dcb_out = out_buf; + const struct sss_tool_dcb_state *dcb_in = in_buf; + + if (!in_buf || !out_buf || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EFAULT; + } + + if (in_len != sizeof(*dcb_in) || *out_len != sizeof(*dcb_out)) { + tool_err("Invalid in len: %u or out len: %u is not equal to %lu\n", + in_len, *out_len, sizeof(*dcb_in)); + return -EINVAL; + } + + memcpy(dcb_out, dcb_in, sizeof(*dcb_in)); + dcb_out->head.status = 0; + + if (!(dcb_in->op_code & SSS_TOOL_DCB_OPCODE_WR)) { + dcb_out->state = !!SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_DCB_ENABLE); + return 0; + } + + if (SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_DCB_ENABLE) == dcb_in->state) + return 0; + + if (dcb_in->state && user_cos_num > nic_dev->qp_res.qp_num) { + tool_err("Fail to mt dcb state, cos num %u larger than channel num %u\n", + user_cos_num, nic_dev->qp_res.qp_num); + return -EOPNOTSUPP; + } + + rtnl_lock(); + if (netif_running(nic_dev->netdev)) { + sss_nic_vport_down(nic_dev); + ret = sss_tool_setup_cos(nic_dev->netdev, dcb_in->state ? user_cos_num : 0); + if (ret != 0) { + sss_nic_vport_up(nic_dev); + rtnl_unlock(); + return ret; + } + + ret = sss_nic_vport_up(nic_dev); + if (ret != 0) { + sss_tool_setup_cos(nic_dev->netdev, dcb_in->state ? 0 : user_cos_num); + sss_nic_vport_up(nic_dev); + } + + rtnl_unlock(); + return ret; + } + + ret = sss_tool_setup_cos(nic_dev->netdev, dcb_in->state ? user_cos_num : 0); + rtnl_unlock(); + + return ret; +} + +int sss_tool_dcb_mt_hw_qos_get(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + struct sss_tool_qos_cos_cfg *out_cfg = out_buf; + const struct sss_tool_qos_cos_cfg *in_cfg = in_buf; + + if (!in_buf || !out_buf || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EFAULT; + } + + if (in_len != sizeof(*in_cfg) || *out_len != sizeof(*out_cfg)) { + tool_err("Invalid in len: %u or out len: %u is not equal to %lu\n", + in_len, *out_len, sizeof(*in_cfg)); + return -EINVAL; + } + + memcpy(out_cfg, in_cfg, sizeof(*in_cfg)); + out_cfg->func_max_cos_num = nic_dev->max_cos_num; + out_cfg->head.status = 0; + out_cfg->port_cos_bitmap = (u8)nic_dev->dft_port_cos_bitmap; + out_cfg->func_cos_bitmap = (u8)nic_dev->dft_func_cos_bitmap; + out_cfg->port_id = sss_get_phy_port_id(nic_dev->hwdev); + + return 0; +} + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_dcb.h b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_dcb.h new file mode 100644 index 000000000000..c6f6f3c34925 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_dcb.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_NIC_DCB_H +#define SSS_TOOL_NIC_DCB_H + +int sss_tool_dcb_mt_qos_map(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_dcb_mt_dcb_state(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_dcb_mt_hw_qos_get(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +#endif + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_func.c b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_func.c new file mode 100644 index 000000000000..d9a6210b1608 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_func.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt + +#include "sss_nic_mag_cfg.h" +#include "sss_tool_comm.h" +#include "sss_tool_nic.h" +#include "sss_tool_nic_dcb.h" +#include "sss_tool_nic_qp_info.h" +#include "sss_tool_nic_phy_attr.h" +#include "sss_tool_nic_stats.h" + +typedef int (*sss_tool_cmd_func)(struct sss_nic_dev *nic_dev, + const void *in_buf, u32 in_len, + void *out_buf, u32 *out_len); + +struct sss_tool_cmd_handle { + enum sss_tool_driver_cmd_type cmd_type; + sss_tool_cmd_func func; +}; + +static int sss_tool_get_nic_version(void *out_buf, const u32 *out_len) +{ + struct sss_tool_drv_version_info *ver_info = out_buf; + int ret; + + if (!out_buf || !out_len) { + tool_err("Invalid param, use null pointer.\n"); + return -EINVAL; + } + + if (*out_len != sizeof(*ver_info)) { + tool_err("Invalid out len :%u is not equal to %lu\n", + *out_len, sizeof(*ver_info)); + return -EINVAL; + } + + ret = snprintf(ver_info->ver, sizeof(ver_info->ver), "%s %s", + SSSNIC_DRV_VERSION, __TIME_STR__); + if (ret < 0) + return -EINVAL; + + return 0; +} + +static const struct sss_tool_cmd_handle sss_tool_nic_cmd_handle[] = { + {SSS_TOOL_GET_TX_INFO, sss_tool_get_tx_info}, + {SSS_TOOL_GET_RX_INFO, sss_tool_get_rx_info}, + {SSS_TOOL_GET_TX_WQE_INFO, sss_tool_get_tx_wqe_info}, + {SSS_TOOL_GET_RX_WQE_INFO, sss_tool_get_rx_wqe_info}, + {SSS_TOOL_GET_Q_NUM, sss_tool_get_q_num}, + {SSS_TOOL_GET_RX_CQE_INFO, sss_tool_get_rx_cqe_info}, + {SSS_TOOL_GET_INTER_NUM, sss_tool_get_inter_num}, + {SSS_TOOL_SET_PF_BW_LIMIT, sss_tool_set_pf_bw_limit}, + {SSS_TOOL_GET_PF_BW_LIMIT, sss_tool_get_pf_bw_limit}, + {SSS_TOOL_GET_LOOPBACK_MODE, sss_tool_get_loopback_mode}, + {SSS_TOOL_SET_LOOPBACK_MODE, sss_tool_set_loopback_mode}, + {SSS_TOOL_GET_TX_TIMEOUT, sss_tool_get_netdev_tx_timeout}, + {SSS_TOOL_SET_TX_TIMEOUT, sss_tool_set_netdev_tx_timeout}, + {SSS_TOOL_GET_SSET_COUNT, sss_tool_get_sset_count}, + {SSS_TOOL_GET_SSET_ITEMS, sss_tool_get_sset_stats}, + {SSS_TOOL_GET_XSFP_PRESENT, sss_tool_get_xsfp_present}, + {SSS_TOOL_GET_XSFP_INFO, sss_tool_get_xsfp_info}, + {SSS_TOOL_GET_ULD_DEV_NAME, sss_tool_get_netdev_name}, + {SSS_TOOL_CLEAR_FUNC_STATS, sss_tool_clear_func_stats}, + {SSS_TOOL_SET_LINK_MODE, sss_tool_set_link_mode}, + {SSS_TOOL_DCB_STATE, sss_tool_dcb_mt_dcb_state}, + {SSS_TOOL_QOS_DEV, sss_tool_dcb_mt_qos_map}, + {SSS_TOOL_GET_QOS_COS, sss_tool_dcb_mt_hw_qos_get}, +}; + +static int sss_tool_cmd_to_nic_driver(struct sss_nic_dev *nic_dev, + u32 cmd, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + int idx; + int cmd_num = ARRAY_LEN(sss_tool_nic_cmd_handle); + enum sss_tool_driver_cmd_type cmd_type = (enum sss_tool_driver_cmd_type)cmd; + int ret = -EINVAL; + + mutex_lock(&nic_dev->qp_mutex); + for (idx = 0; idx < cmd_num; idx++) { + if (cmd_type == sss_tool_nic_cmd_handle[idx].cmd_type) { + ret = sss_tool_nic_cmd_handle[idx].func + (nic_dev, in_buf, in_len, out_buf, out_len); + break; + } + } + mutex_unlock(&nic_dev->qp_mutex); + + if (idx == cmd_num) + tool_err("Fail to send to nic driver, cmd %d is not exist\n", cmd_type); + + return ret; +} + +int sss_tool_ioctl(void *uld_dev, u32 cmd, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + if (cmd == SSS_TOOL_GET_DRV_VERSION) + return sss_tool_get_nic_version(out_buf, out_len); + + if (!uld_dev) + return -EINVAL; + + return sss_tool_cmd_to_nic_driver(uld_dev, cmd, in_buf, in_len, out_buf, out_len); +} + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_func.h b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_func.h new file mode 100644 index 000000000000..64bbd9c3a40c --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_func.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_NIC_FUNC_H +#define SSS_TOOL_NIC_FUNC_H + +int sss_tool_ioctl(void *uld_dev, u32 cmd, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +#endif diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_phy_attr.c b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_phy_attr.c new file mode 100644 index 000000000000..d79be081f5cc --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_phy_attr.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt + +#include "sss_nic_cfg.h" +#include "sss_nic_mag_cfg.h" +#include "sss_nic_dev_define.h" +#include "sss_tool_comm.h" +#include "sss_tool_nic.h" +#include "sss_nic_netdev_ops_api.h" + +enum sss_tool_link_mode { + SSS_TOOL_LINK_MODE_AUTO = 0, + SSS_TOOL_LINK_MODE_UP, + SSS_TOOL_LINK_MODE_DOWN, + SSS_TOOL_LINK_MODE_MAX, +}; + +typedef void (*sss_tool_set_link_mode_handler_t)(struct sss_nic_dev *nic_dev); + +int sss_tool_get_loopback_mode(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + struct sss_tool_loop_mode *mode = out_buf; + + if (!out_len || !mode) { + tool_err("Invalid param, use null pointer\n"); + return -EINVAL; + } + + if (*out_len != sizeof(*mode)) { + tool_err("Invalid out len: %u is not equal to %lu\n", + *out_len, sizeof(*mode)); + return -EINVAL; + } + + return sss_nic_get_loopback_mode(nic_dev, (u8 *)&mode->loop_mode, + (u8 *)&mode->loop_ctrl); +} + +int sss_tool_set_loopback_mode(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + int ret; + const struct sss_tool_loop_mode *mode = in_buf; + + if (!SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_INTF_UP)) { + tool_err("Fail to set lookback mode, netdev is down\n"); + return -EFAULT; + } + + if (!mode || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EINVAL; + } + + if (in_len != sizeof(*mode) || *out_len != sizeof(*mode)) { + tool_err("Invalid in len %d or out len %u is not equal to %lu\n", + in_len, *out_len, sizeof(*mode)); + return -EINVAL; + } + + ret = sss_nic_set_loopback_mode(nic_dev->hwdev, (u8)mode->loop_mode, (u8)mode->loop_ctrl); + if (ret == 0) + tool_info("succeed to set loopback mode %u en %u\n", + mode->loop_mode, mode->loop_ctrl); + + return ret; +} + +static bool sss_tool_check_param_valid(struct sss_nic_dev *nic_dev, + const void *in_buf, u32 in_len, + const u32 *out_len) +{ + if (!SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_INTF_UP)) { + tool_err("Fail to set link mode, netdev is down\n"); + return false; + } + + if (!in_buf || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EINVAL; + } + + if (in_len != sizeof(SSS_TOOL_LINK_MODE_MAX) || + *out_len != sizeof(SSS_TOOL_LINK_MODE_MAX)) { + tool_err("Invalid in len %d or out len: %u is not equal to %lu\n", + in_len, *out_len, sizeof(SSS_TOOL_LINK_MODE_MAX)); + return false; + } + + return true; +} + +static void sss_tool_set_link_status(struct sss_nic_dev *nic_dev, bool status) +{ + struct net_device *netdev = nic_dev->netdev; + + if (!SSS_CHANNEL_RES_VALID(nic_dev) || + SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_LP_TEST) || + SSSNIC_TEST_NIC_DEV_FLAG(nic_dev, SSSNIC_FORCE_LINK_UP)) + return; + + if (!status) { + if (!netif_carrier_ok(netdev)) + return; + + tool_info("Link down\n"); + nic_dev->link_status = status; + netif_carrier_off(netdev); + + } else { + if (netif_carrier_ok(netdev)) + return; + + tool_info("Link up\n"); + nic_dev->link_status = status; + netif_carrier_on(netdev); + } +} + +static void sss_tool_link_mode_auto(struct sss_nic_dev *nic_dev) +{ + u8 link_status; + + if (sss_nic_get_hw_link_state(nic_dev, &link_status)) + link_status = false; + + sss_tool_set_link_status(nic_dev, (bool)link_status); + tool_info("Success to set link mode to auto, the state is link %s\n", + (link_status ? "up" : "down")); +} + +static void sss_tool_link_mode_up(struct sss_nic_dev *nic_dev) +{ + sss_tool_set_link_status(nic_dev, true); + tool_info("Success to set link mode to up\n"); +} + +static void sss_tool_link_mode_down(struct sss_nic_dev *nic_dev) +{ + sss_tool_set_link_status(nic_dev, false); + tool_info("Success to set link mode to down\n"); +} + +int sss_tool_set_link_mode(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + const enum sss_tool_link_mode *mode = in_buf; + + sss_tool_set_link_mode_handler_t handler[] = { + sss_tool_link_mode_auto, + sss_tool_link_mode_up, + sss_tool_link_mode_down, + }; + + if (!sss_tool_check_param_valid(nic_dev, in_buf, in_len, out_len)) + return -EFAULT; + + if (*mode >= SSS_TOOL_LINK_MODE_MAX) { + tool_err("Fail to set link mode, mode %d\n", *mode); + return -EINVAL; + } + + handler[*mode](nic_dev); + + return 0; +} + +static int sss_tool_update_pf_bw_limit(struct sss_nic_dev *nic_dev, u32 bw_limit) +{ + int ret; + u32 old_bw_limit; + struct sss_nic_port_info port_info = {0}; + struct sss_nic_io *nic_io = nic_dev->nic_io; + + if (!nic_io) + return -EINVAL; + + if (bw_limit > SSSNIC_PF_LIMIT_BW_MAX) { + tool_err("Fail to update pf bw limit, bandwidth: %u large then max limit: %u\n", + bw_limit, SSSNIC_PF_LIMIT_BW_MAX); + return -EINVAL; + } + + old_bw_limit = nic_io->mag_cfg.pf_bw_limit; + nic_io->mag_cfg.pf_bw_limit = bw_limit; + + if (!SSSNIC_SUPPORT_RATE_LIMIT(nic_io)) + return 0; + + ret = sss_nic_get_hw_port_info(nic_dev, &port_info, SSS_CHANNEL_NIC); + if (ret != 0) { + tool_err("Fail to get port info\n"); + nic_io->mag_cfg.pf_bw_limit = bw_limit; + return -EIO; + } + + ret = sss_nic_set_pf_rate(nic_dev, port_info.speed); + if (ret != 0) { + tool_err("Fail to set pf bandwidth\n"); + nic_io->mag_cfg.pf_bw_limit = bw_limit; + return ret; + } + + return 0; +} + +static int sss_tool_check_preconditions(struct sss_nic_dev *nic_dev, + const void *in_buf, u32 in_len, + void *out_buf, u32 *out_len) +{ + int ret; + u8 link_state = 0; + + if (SSSNIC_FUNC_IS_VF(nic_dev->hwdev)) { + tool_err("Fail to set VF bandwidth rate, please use ip link cmd\n"); + return -EINVAL; + } + + if (!in_buf || !out_buf || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EINVAL; + } + + if (in_len != sizeof(in_len)) { + tool_err("Invalid in len %d is not equal to %lu\n", + in_len, sizeof(in_len)); + return -EINVAL; + } + + if (*out_len != sizeof(link_state)) { + tool_err("Invalid out len %d is not equal to %lu\n", + in_len, sizeof(link_state)); + return -EINVAL; + } + + ret = sss_nic_get_hw_link_state(nic_dev, &link_state); + if (ret != 0) { + tool_err("Fail to get link state\n"); + return -EIO; + } + + if (!link_state) { + tool_err("Fail to set pf rate, must be link up\n"); + return -EINVAL; + } + + return 0; +} + +int sss_tool_set_pf_bw_limit(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + int ret; + u32 pf_bw_limit; + + ret = sss_tool_check_preconditions(nic_dev, in_buf, in_len, out_buf, out_len); + if (ret != 0) + return -EINVAL; + + pf_bw_limit = *((u32 *)in_buf); + + ret = sss_tool_update_pf_bw_limit(nic_dev, pf_bw_limit); + if (ret != 0) { + tool_err("Fail to set pf bandwidth limit to %d%%\n", pf_bw_limit); + if (ret < 0) + return ret; + } + + *((u8 *)out_buf) = (u8)ret; + + return 0; +} + +int sss_tool_get_pf_bw_limit(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + struct sss_nic_io *nic_io = NULL; + + if (SSSNIC_FUNC_IS_VF(nic_dev->hwdev)) { + tool_err("Fail to get VF bandwidth rate, please use ip link cmd\n"); + return -EINVAL; + } + + if (!out_buf || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EINVAL; + } + + if (*out_len != sizeof(in_len)) { + tool_err("Invalid out len %d is not equal to %lu\n", + *out_len, sizeof(in_len)); + return -EFAULT; + } + + nic_io = nic_dev->nic_io; + if (!nic_io) + return -EINVAL; + + *((u32 *)out_buf) = nic_io->mag_cfg.pf_bw_limit; + + return 0; +} + +int sss_tool_get_netdev_name(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + if (!out_buf || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EFAULT; + } + + if (*out_len != IFNAMSIZ) { + tool_err("Invalid out len %u is not equal to %u\n\n", + *out_len, IFNAMSIZ); + return -EINVAL; + } + + strlcpy(out_buf, nic_dev->netdev->name, IFNAMSIZ); + + return 0; +} + +int sss_tool_get_netdev_tx_timeout(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + int *tx_timeout = out_buf; + struct net_device *net_dev = nic_dev->netdev; + + if (!out_buf || !out_len) { + tool_err("Fail to get netdev tx timeout, use null pointer\n"); + return -EFAULT; + } + + if (*out_len != sizeof(in_len)) { + tool_err("Fail to get netdev tx timeout, out len %u is not equal to %lu\n", + *out_len, sizeof(in_len)); + return -EINVAL; + } + + *tx_timeout = net_dev->watchdog_timeo; + + return 0; +} + +int sss_tool_set_netdev_tx_timeout(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + const int *tx_timeout = in_buf; + struct net_device *net_dev = nic_dev->netdev; + + if (!in_buf) { + tool_err("Invalid in buf is null\n"); + return -EFAULT; + } + + if (in_len != sizeof(in_len)) { + tool_err("Invalid in len: %u is not equal to %lu\n", + in_len, sizeof(in_len)); + return -EINVAL; + } + + net_dev->watchdog_timeo = *tx_timeout * HZ; + tool_info("Success to set tx timeout check period to %ds\n", *tx_timeout); + + return 0; +} + +int sss_tool_get_xsfp_present(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + struct sss_nic_mbx_get_xsfp_present *sfp_info = out_buf; + + if (!in_buf || !out_buf || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EFAULT; + } + + if (in_len != sizeof(*sfp_info) || *out_len != sizeof(*sfp_info)) { + tool_err("Invalid in len: %u or out len: %u is not equal to %lu\n", + in_len, *out_len, sizeof(*sfp_info)); + return -EINVAL; + } + + sfp_info->abs_status = sss_nic_if_sfp_absent(nic_dev); + sfp_info->head.state = 0; + + return 0; +} + +int sss_tool_get_xsfp_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + int ret; + struct sss_nic_mbx_get_xsfp_info *xsfp_info = out_buf; + + if (!in_buf || !out_buf || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EFAULT; + } + + if (in_len != sizeof(*xsfp_info) || *out_len != sizeof(*xsfp_info)) { + tool_err("Invalid in len: %u or out len: %u is not equal to %lu\n", + in_len, *out_len, sizeof(*xsfp_info)); + return -EINVAL; + } + + ret = sss_nic_get_sfp_info(nic_dev, xsfp_info); + if (ret != 0) + xsfp_info->head.state = SSS_TOOL_EIO; + + return 0; +} + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_phy_attr.h b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_phy_attr.h new file mode 100644 index 000000000000..5deb53481829 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_phy_attr.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_NIC_PHY_ATTR_H +#define SSS_TOOL_NIC_PHY_ATTR_H + +int sss_tool_get_loopback_mode(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_set_loopback_mode(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_set_link_mode(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_set_pf_bw_limit(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_pf_bw_limit(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_netdev_name(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_netdev_tx_timeout(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_set_netdev_tx_timeout(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_xsfp_present(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_xsfp_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +#endif + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_qp_info.c b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_qp_info.c new file mode 100644 index 000000000000..1dae86be7bdf --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_qp_info.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt + +#include "sss_kernel.h" +#include "sss_nic_tx.h" +#include "sss_tool_comm.h" +#include "sss_tool_nic.h" + +static int sss_tool_get_wqe_info(struct sss_nic_dev *nic_dev, + u16 q_id, u16 wqe_id, u16 wqebb_cnt, + u8 *out_buff, const u16 *out_len, + enum sss_nic_queue_type q_type) +{ + u32 i; + void *src_wqebb = NULL; + u32 offset; + struct sss_nic_io_queue *queue = NULL; + struct sss_nic_io *nic_io = NULL; + + nic_io = nic_dev->nic_io; + if (!nic_io) { + tool_err("Fail to get wqe info, nic_io is NULL.\n"); + return -EINVAL; + } + + if (q_id >= nic_io->max_qp_num) { + tool_err("Fail to get wqe info, q_id[%u] > num_qps_cfg[%u].\n", + q_id, nic_io->max_qp_num); + return -EINVAL; + } + + if (q_type == SSSNIC_RQ) + queue = &nic_io->rq_group[q_id]; + else + queue = &nic_io->sq_group[q_id]; + + if ((wqe_id + wqebb_cnt) > queue->wq.q_depth) { + tool_err("Fail to get wqe info, (idx[%u] + idx[%u]) > q_depth[%u].\n", + wqe_id, wqebb_cnt, queue->wq.q_depth); + return -EINVAL; + } + + if (*out_len != (queue->wq.elem_size * wqebb_cnt)) { + tool_err("Fail to get wqe info, out len :%u is not equal to %d\n", + *out_len, (queue->wq.elem_size * wqebb_cnt)); + return -EINVAL; + } + + for (i = 0; i < wqebb_cnt; i++) { + src_wqebb = sss_wq_wqebb_addr(&queue->wq, + (u16)SSS_WQ_MASK_ID(&queue->wq, wqe_id + i)); + offset = queue->wq.elem_size * i; + memcpy(out_buff + offset, src_wqebb, queue->wq.elem_size); + } + + return 0; +} + +static void sss_tool_get_sq_info(struct sss_nic_io *nic_io, u16 q_id, + struct sss_tool_sq_info *sq_info) +{ + struct sss_nic_io_queue *sq = NULL; + + sq = &nic_io->sq_group[q_id]; + + sq_info->q_depth = sq->wq.q_depth; + sq_info->q_id = q_id; + sq_info->pi = sss_nic_get_sq_local_pi(sq); + sq_info->doorbell.map_addr = (u64 *)sq->db_addr; + sq_info->fi = sss_nic_get_sq_hw_ci(sq); + sq_info->wqebb_size = sq->wq.elem_size; + sq_info->ci = sss_nic_get_sq_local_ci(sq); + sq_info->ci_addr = sq->tx.ci_addr; + sq_info->slq_handle = sq; + sq_info->cla_addr = sq->wq.block_paddr; +} + +static void sss_tool_get_rq_info(struct sss_nic_io *nic_io, u16 q_id, + struct sss_tool_rq_info *rq_info) +{ + struct sss_nic_io_queue *rq = NULL; + + rq = &nic_io->rq_group[q_id]; + + rq_info->msix_idx = rq->msix_id; + rq_info->hw_pi = cpu_to_be16(*rq->rx.pi_vaddr); + rq_info->buf_len = nic_io->rx_buff_len; + rq_info->wqebb_size = rq->wq.elem_size; + rq_info->slq_handle = rq; + rq_info->q_id = q_id; + rq_info->ci_cla_tbl_addr = rq->wq.block_paddr; + rq_info->q_depth = (u16)rq->wq.q_depth; + rq_info->ci_wqe_page_addr = sss_wq_get_first_wqe_page_addr(&rq->wq); +} + +static int sss_tool_get_queue_info(struct sss_nic_dev *nic_dev, u16 q_id, + void *out_buff, enum sss_nic_queue_type q_type) +{ + struct sss_nic_io *nic_io = NULL; + + nic_io = nic_dev->nic_io; + if (!nic_io) { + tool_err("Fail to get wqe info, nic_io is NULL.\n"); + return -EINVAL; + } + + if (q_id >= nic_io->max_qp_num) { + tool_err("Fail to get rq info, input q_id(%u) is larger than max qp num:%u\n", + q_id, nic_io->max_qp_num); + return -EINVAL; + } + + (q_type == SSSNIC_RQ) ? sss_tool_get_rq_info(nic_io, q_id, out_buff) : + sss_tool_get_sq_info(nic_io, q_id, out_buff); + + return 0; +} + +static bool sss_tool_check_input_pointer(struct sss_nic_dev *nic_dev, + const void *in_buf, void *out_buf, u32 *out_len) +{ + if (!SSS_CHANNEL_RES_VALID(nic_dev)) { + tool_err("Invalid input param nic_dev\n"); + return false; + } + + if (!in_buf || !out_buf || !out_len) { + tool_err("Invalid input param,in_buf/out_buf/out_len\n"); + return false; + } + + return true; +} + +int sss_tool_get_tx_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + u16 q_id; + struct sss_tool_sq_info sq_info = {0}; + + if (!sss_tool_check_input_pointer(nic_dev, in_buf, out_buf, out_len)) + return -EINVAL; + + if (in_len != sizeof(in_len)) { + tool_err("Fail to get tx info, in len :%u is not equal to %lu\n", + in_len, sizeof(in_len)); + return -EINVAL; + } + + if (*out_len != sizeof(sq_info)) { + tool_err("Fail to get tx info, out len :%u is not equal to %lu\n", + *out_len, sizeof(sq_info)); + return -EINVAL; + } + + q_id = (u16)(*((u32 *)in_buf)); + + return sss_tool_get_queue_info(nic_dev, q_id, out_buf, SSSNIC_SQ); +} + +int sss_tool_get_tx_wqe_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + u16 wqebb_cnt = 1; + const struct sss_tool_wqe_info *info = in_buf; + + if (!sss_tool_check_input_pointer(nic_dev, in_buf, out_buf, out_len)) + return -EINVAL; + + if (in_len != sizeof(*info)) { + tool_err("Fail to get tx wqe info, in len %u is not equal to %lu\n", + in_len, sizeof(*info)); + return -EINVAL; + } + + return sss_tool_get_wqe_info(nic_dev, (u16)info->q_id, (u16)info->wqe_id, wqebb_cnt, + out_buf, (u16 *)out_len, SSSNIC_SQ); +} + +int sss_tool_get_rx_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + int ret; + u16 q_id; + struct sss_tool_rq_info *rq_info = out_buf; + + if (!sss_tool_check_input_pointer(nic_dev, in_buf, out_buf, out_len)) + return -EINVAL; + + if (in_len != sizeof(u32)) { + tool_err("Invalid in len: %u is not equal to %lu\n", + in_len, sizeof(u32)); + return -EINVAL; + } + + if (*out_len != sizeof(*rq_info)) { + tool_err("Invalid out len: %u is not equal to %lu\n", + *out_len, sizeof(*rq_info)); + return -EINVAL; + } + + q_id = (u16)(*((u32 *)in_buf)); + + ret = sss_tool_get_queue_info(nic_dev, q_id, out_buf, SSSNIC_RQ); + if (ret != 0) { + tool_err("Fail to get rq info, ret: %d.\n", ret); + return ret; + } + + rq_info->pending_limt = nic_dev->rq_desc_group[q_id].last_pending_limt; + rq_info->msix_vector = nic_dev->rq_desc_group[q_id].irq_id; + rq_info->delta = (u16)nic_dev->rq_desc_group[q_id].delta; + rq_info->sw_pi = nic_dev->rq_desc_group[q_id].pi; + rq_info->coalesc_timer_cfg = nic_dev->rq_desc_group[q_id].last_coal_timer; + rq_info->ci = (u16)(nic_dev->rq_desc_group[q_id].ci & + nic_dev->rq_desc_group[q_id].qid_mask); + + return 0; +} + +int sss_tool_get_rx_wqe_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + u16 wqebb_cnt = 1; + const struct sss_tool_wqe_info *info = in_buf; + + if (!sss_tool_check_input_pointer(nic_dev, in_buf, out_buf, out_len)) + return -EINVAL; + + if (in_len != sizeof(struct sss_tool_wqe_info)) { + tool_err("Fail to get rx wqe info, in len: %u is not equal to %lu\n", + in_len, sizeof(struct sss_tool_wqe_info)); + return -EINVAL; + } + + return sss_tool_get_wqe_info(nic_dev, (u16)info->q_id, (u16)info->wqe_id, wqebb_cnt, + out_buf, (u16 *)out_len, SSSNIC_RQ); +} + +int sss_tool_get_rx_cqe_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + u16 wqe_id = 0; + u16 q_id = 0; + const struct sss_tool_wqe_info *info = in_buf; + + if (!sss_tool_check_input_pointer(nic_dev, in_buf, out_buf, out_len)) + return -EINVAL; + + if (in_len != sizeof(struct sss_tool_wqe_info)) { + tool_err("Fail to get rx cqe info, in len: %u is not equal to %lu\n", + in_len, sizeof(struct sss_tool_wqe_info)); + return -EINVAL; + } + + if (*out_len != sizeof(struct sss_nic_cqe)) { + tool_err("Fail to get rx cqe info, out len: %u is not equal to %lu\n", + *out_len, sizeof(struct sss_nic_cqe)); + return -EINVAL; + } + + wqe_id = (u16)info->wqe_id; + q_id = (u16)info->q_id; + + if (q_id >= nic_dev->qp_res.qp_num || wqe_id >= nic_dev->rq_desc_group[q_id].q_depth) { + tool_err("Fail to get rx cqe info, q_id[%u] >= %u, or wqe idx[%u] >= %u.\n", + q_id, nic_dev->qp_res.qp_num, wqe_id, + nic_dev->rq_desc_group[q_id].q_depth); + return -EFAULT; + } + + memcpy(out_buf, nic_dev->rq_desc_group[q_id].rx_desc_group[wqe_id].cqe, + sizeof(struct sss_nic_cqe)); + + return 0; +} + +int sss_tool_get_q_num(struct sss_nic_dev *nic_dev, const void *in_buf, u32 in_len, + void *out_buf, u32 *out_len) +{ + if (!SSS_CHANNEL_RES_VALID(nic_dev)) { + tool_err("Fail to get queue number, netdev is down\n"); + return -EFAULT; + } + + if (!out_buf || !out_len) { + tool_err("Invalid param, use null pointer.\n"); + return -EINVAL; + } + + if (*out_len != sizeof(nic_dev->qp_res.qp_num)) { + tool_err("Invalid out len: %u is not equal to %lu\n", + *out_len, sizeof(nic_dev->qp_res.qp_num)); + return -EINVAL; + } + + *((u16 *)out_buf) = nic_dev->qp_res.qp_num; + + return 0; +} + +int sss_tool_get_inter_num(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + u16 intr_num = sss_nic_intr_num(nic_dev->hwdev); + + if (!out_buf || !out_len) { + tool_err("Invalid param, use null pointer\n"); + return -EFAULT; + } + + if (*out_len != sizeof(intr_num)) { + tool_err("Invalid out len:%u is not equal to %lu\n", + *out_len, sizeof(intr_num)); + return -EFAULT; + } + + *(u16 *)out_buf = intr_num; + + return 0; +} + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_qp_info.h b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_qp_info.h new file mode 100644 index 000000000000..3c7f10c64462 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_qp_info.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_NIC_QP_INFO_H +#define SSS_TOOL_NIC_QP_INFO_H + +int sss_tool_get_tx_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_rx_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_tx_wqe_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_rx_wqe_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_rx_cqe_info(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_q_num(struct sss_nic_dev *nic_dev, const void *in_buf, u32 in_len, + void *out_buf, u32 *out_len); + +int sss_tool_get_inter_num(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +#endif + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_stats.c b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_stats.c new file mode 100644 index 000000000000..55c4880a0759 --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_stats.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt + +#include "sss_kernel.h" +#include "sss_tool_comm.h" +#include "sss_tool_nic.h" +#include "sss_nic_netdev_ops_api.h" +#include "sss_nic_ethtool_stats_api.h" + +enum sss_tool_show_set { + SSS_TOOL_SHOW_SSET_IO_STATS = 1, +}; + +static void sss_tool_reset_nicdev_stats(struct sss_nic_dev *nic_dev) +{ + u64_stats_update_begin(&nic_dev->tx_stats.stats_sync); + nic_dev->tx_stats.rsvd1 = 0; + nic_dev->tx_stats.rsvd2 = 0; + nic_dev->tx_stats.tx_drop = 0; + nic_dev->tx_stats.tx_timeout = 0; + nic_dev->tx_stats.tx_invalid_qid = 0; + u64_stats_update_end(&nic_dev->tx_stats.stats_sync); +} + +static void sss_tool_reset_rq_stats(struct sss_nic_rq_stats *rq_stats) +{ + u64_stats_update_begin(&rq_stats->stats_sync); + rq_stats->reset_drop_sge = 0; + rq_stats->rx_packets = 0; + rq_stats->alloc_rx_dma_err = 0; + rq_stats->rx_bytes = 0; + + rq_stats->csum_errors = 0; + rq_stats->rx_dropped = 0; + rq_stats->errors = 0; + rq_stats->large_xdp_pkts = 0; + rq_stats->rx_buf_errors = 0; + rq_stats->alloc_skb_err = 0; + rq_stats->xdp_dropped = 0; + rq_stats->other_errors = 0; + rq_stats->rsvd2 = 0; + u64_stats_update_end(&rq_stats->stats_sync); +} + +static void sss_tool_reset_sq_stats(struct sss_nic_sq_stats *sq_stats) +{ + u64_stats_update_begin(&sq_stats->stats_sync); + sq_stats->unknown_tunnel_proto = 0; + sq_stats->tx_packets = 0; + sq_stats->tx_dropped = 0; + sq_stats->frag_len_overflow = 0; + sq_stats->tx_busy = 0; + sq_stats->wake = 0; + sq_stats->skb_pad_err = 0; + sq_stats->dma_map_err = 0; + sq_stats->frag_size_zero = 0; + sq_stats->tx_bytes = 0; + sq_stats->offload_err = 0; + sq_stats->rsvd1 = 0; + sq_stats->rsvd2 = 0; + u64_stats_update_end(&sq_stats->stats_sync); +} + +int sss_tool_clear_func_stats(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + int i; + + if (!out_len) { + tool_err("Invalid out len is null\n"); + return -EINVAL; + } + +#ifndef HAVE_NETDEV_STATS_IN_NETDEV + memset(&nic_dev->net_stats, 0, sizeof(nic_dev->net_stats)); +#endif + sss_tool_reset_nicdev_stats(nic_dev); + for (i = 0; i < nic_dev->max_qp_num; i++) { + sss_tool_reset_rq_stats(&nic_dev->rq_desc_group[i].stats); + sss_tool_reset_sq_stats(&nic_dev->sq_desc_group[i].stats); + } + + *out_len = 0; + + return 0; +} + +int sss_tool_get_sset_count(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + u32 count = 0; + + if (!in_buf || in_len != sizeof(count) || !out_len || + *out_len != sizeof(count) || !out_buf) { + tool_err("Invalid in_len: %u\n", in_len); + return -EINVAL; + } + + if (*((u32 *)in_buf) == SSS_TOOL_SHOW_SSET_IO_STATS) + count = sss_nic_get_io_stats_size(nic_dev); + + *((u32 *)out_buf) = count; + + return 0; +} + +int sss_tool_get_sset_stats(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len) +{ + struct sss_tool_show_item *items = out_buf; + u32 count; + + if (!in_buf || in_len != sizeof(count) || !out_len || !out_buf) { + tool_err("Invalid in_len: %u\n", in_len); + return -EINVAL; + } + + if (*((u32 *)in_buf) != SSS_TOOL_SHOW_SSET_IO_STATS) { + tool_err("Invalid input para %u stats\n", *((u32 *)in_buf)); + return -EINVAL; + } + + count = sss_nic_get_io_stats_size(nic_dev); + + if (count * sizeof(*items) != *out_len) { + tool_err("Invalid out len: %u is not equal to %lu\n", + *out_len, count * sizeof(*items)); + return -EINVAL; + } + + sss_nic_get_io_stats(nic_dev, items); + + return 0; +} + diff --git a/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_stats.h b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_stats.h new file mode 100644 index 000000000000..1a686e5712be --- /dev/null +++ b/drivers/net/ethernet/3snic/sssnic/nic/tool/sss_tool_nic_stats.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 3snic Technologies Co., Ltd */ + +#ifndef SSS_TOOL_NIC_STATS_H +#define SSS_TOOL_NIC_STATS_H + +int sss_tool_clear_func_stats(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_sset_count(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +int sss_tool_get_sset_stats(struct sss_nic_dev *nic_dev, const void *in_buf, + u32 in_len, void *out_buf, u32 *out_len); + +#endif + -- GitLab